本文主要介绍一些JS中用到的小技巧

1. 类型强制转换

 

1.1 string强制转换为数字

可以用*1来转化为数字(实际上是调用.valueOf方法) 然后使用Number.isNaN来判断是否为NaN,或者使用 a !== a 来判断是否为NaN,因为 NaN !== NaN

'32' * 1            // 32

'ds' * 1            // NaN

null * 1            // 0

undefined * 1    // NaN

1  * { valueOf: ()=>'3' }        // 3

常用: 也可以使用+来转化字符串为数字

+ '123'            // 123

+ 'ds'               // NaN

+ ''                    // 0

+ null              // 0

+ undefined    // NaN

+ { valueOf: ()=>'3' }    // 3

1.2 object强制转化为string

 

可以使用 字符串+Object 的方式来转化对象为字符串(实际上是调用 .toString() 方法)

'the Math object:' + Math                // "the Math object:[object Math]"

'the JSON object:' + JSON              // "the JSON object:[object JSON]"

当然也可以覆盖对象的toString和valueOf方法来自定义对象的类型转换:

2  * { valueOf: ()=>'3' }                // 6

'J' + { toString: ()=>'S' }                // "JS"

《Effective JavaScript》P11:当+用在连接字符串时,当一个对象既有toString方法又有valueOf方法时候,JS通过盲目使用valueOf方法来解决这种含糊。 对象通过valueOf方法强制转换为数字,通过toString方法强制转换为字符串

'' + {toString:()=>'S',valueOf:()=>'J'}                // J

1.3 使用Boolean过滤数组中的所有假值

 

我们知道JS中有一些假值:false,null,0,"",undefined,NaN,怎样把数组中的假值快速过滤呢,可以使用Boolean构造函数来进行一次转换

const compact = arr => arr.filter(Boolean)

compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34])             // [ 1, 2, 3, 'a', 's', 34 ]

1.4 双位运算符 ~~

 

可以使用双位操作符来替代 Math.floor( )。双否定位操作符的优势在于它执行相同的操作运行速度更快。

Math.floor(4.9) === 4      //true

// 简写为:

~~4.9 === 4      //true

不过要注意,对整数来说 ~~ 运算结果与 Math.floor( ) 运算结果相同,而对于负数来说不相同:

~~4.5            // 4

Math.floor(4.5)        // 4

~~-4.5        // -4

Math.floor(-4.5)        // -5

1.5 短路运算符

我们知道逻辑与&&与逻辑或||是短路运算符,短路运算符就是从左到右的运算中前者满足要求,就不再执行后者了; 可以理解为:

  • &&为取假运算,从左到右依次判断,如果遇到一个假值,就返回假值,以后不再执行,否则返回最后一个真值

  • ||为取真运算,从左到右依次判断,如果遇到一个真值,就返回真值,以后不再执行,否则返回最后一个假值

let param1 = expr1 && expr2

let param2 = expr1 || expr2

let variable1

let variable2 = variable1  || 'foo'

如果variable1是真值就直接返回了,后面短路就不会被返回了,如果为假值,则会返回后面的foo。

也可以用来进行简单的判断,取代冗长的if语句:

let variable = param && param.prop

如果param如果为真值则返回param.prop属性,否则返回param这个假值,这样在某些地方防止param为undefined的时候还取其属性造成报错。

1.6 取整 | 0

 

对一个数字| 0可以取整,负数也同样适用,num | 0

1.3 | 0         // 1

-1.9 | 0        // -1

1.7 判断奇偶数 & 1

对一个数字& 1可以判断奇偶数,负数也同样适用,num & 1

const num=3;

!!(num & 1)                    // true

!!(num % 2)                    // true

2. 函数

 

2.1 函数默认值

func = (l, m = 3, n = 4 ) => (l * m * n);

func(2)             //output: 24

注意,传入参数为undefined或者不传入的时候会使用默认参数,但是传入null还是会覆盖默认参数。

2.2 强制参数

 

默认情况下,如果不向函数参数传值,那么JS 会将函数参数设置为undefined。其它一些语言则会发出警告或错误。要执行参数分配,可以使用if语句抛出未定义的错误,或者可以利用强制参数。

mandatory = ( ) => {

throw new Error('Missing parameter!');

}

foo = (bar = mandatory( )) => {     // 这里如果不传入参数,就会执行manadatory函数报出错误

return bar;

}

2.3 隐式返回值

 

返回值是我们通常用来返回函数最终结果的关键字。只有一个语句的箭头函数,可以隐式返回结果(函数必须省略大括号{ },以便省略返回关键字)。

要返回多行语句(例如对象文本),需要使用( )而不是{ }来包裹函数体。这样可以确保代码以单个语句的形式进行求值。

function calcCircumference(diameter) {

return Math.PI * diameter

}

// 简写为:

calcCircumference = diameter => (

Math.PI * diameter;

)

2.4 惰性载入函数

 

在某个场景下我们的函数中有判断语句,这个判断依据在整个项目运行期间一般不会变化,所以判断分支在整个项目运行期间只会运行某个特定分支,那么就可以考虑惰性载入函数

function foo(){

if(a !== b){

console.log('aaa')

}else{

console.log('bbb')

}

}

// 优化后

function foo(){

if(a != b){

foo = function(){

console.log('aaa')

}

}else{

foo = function(){

console.log('bbb')

}

}

return foo();

}

那么第一次运行之后就会覆写这个方法,下一次再运行的时候就不会执行判断了。当然现在只有一个判断,如果判断很多,分支比较复杂,那么节约的资源还是可观的。

2.5 一次性函数

 

跟上面的惰性载入函数同理,可以在函数体里覆写当前函数,那么可以创建一个一次性的函数,重新赋值之前的代码相当于只运行了一次,适用于运行一些只需要执行一次的初始化代码

var sca = function() {

console.log('msg')

sca = function() {

console.log('foo')

}

}

sca()        // msg

sca()        // foo

sca()        // foo

3. 字符串

 

3.1 字符串比较时间先后

比较时间先后顺序可以使用字符串:

var a = "2014-08-08";

var b = "2014-09-09";

console.log(a>b, a<b); // false true

console.log("21:00"<"09:10");  // false

console.log("21:00"<"9:10");   // true   时间形式注意补0

因为字符串比较大小是按照字符串从左到右每个字符的charCode来的,但所以特别要注意时间形式注意补0

4. 数字

 

4.1 不同进制表示法

 

ES6中新增了不同进制的书写格式,在后台传参的时候要注意这一点。

29            // 10进制

035            // 8进制29      原来的方式

0o35            // 8进制29      ES6的方式

0x1d            // 16进制29

0b11101            // 2进制29

4.2 精确到指定位数的小数

 

将数字四舍五入到指定的小数位数。使用 Math.round() 和模板字面量将数字四舍五入为指定的小数位数。 省略第二个参数 decimals ,数字将被四舍五入到一个整数。

const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`)

round(1.345, 2)                 // 1.35

round(1.345, 1)                 // 1.3

4.3 数字补0操作

 

感谢网友 @JserWang @vczhan 提供 这个小技巧 有时候比如显示时间的时候有时候会需要把一位数字显示成两位,这时候就需要补0操作,可以使用slice和string的padStart方法

const addZero1 = (num, len = 2) => (`0${num}`).slice(-len)

const addZero2 = (num, len = 2) => (`${num}`).padStart( len   , '0')

addZero1(3) // 03

addZero2(32,4)  // 0032

5. 数组

 

5.1 reduce方法同时实现map和filter

假设现在有一个数列,你希望更新它的每一项(map的功能)然后筛选出一部分(filter的功能)。如果是先使用map然后filter的话,你需要遍历这个数组两次。 在下面的代码中,我们将数列中的值翻倍,然后挑选出那些大于50的数。

const numbers = [10, 20, 30, 40];

const doubledOver50 = numbers.reduce((finalList, num) => {

num = num * 2;

if (num > 50) {

finalList.push(num);

}

return finalList;

}, []);

doubledOver50;            // [60, 80]

5.2 统计数组中相同项的个数

 

很多时候,你希望统计数组中重复出现项的个数然后用一个对象表示。那么你可以使用reduce方法处理这个数组。

下面的代码将统计每一种车的数目然后把总数用一个对象表示。

var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota'];

var carsObj = cars.reduce(function (obj, name) {

obj[name] = obj[name] ? ++obj[name] : 1;

return obj;

}, {});

carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }

5.3 使用解构来交换参数数值

 

有时候你会将函数返回的多个值放在一个数组里。我们可以使用数组解构来获取其中每一个值。

let param1 = 1;

let param2 = 2;

[param1, param2] = [param2, param1];

console.log(param1) // 2

console.log(param2) // 1

当然我们关于交换数值有不少其他办法:

var temp = a; a = b; b = temp

b = [a, a = b][0]

a = a + b; b = a - b; a = a - b

5.4 接收函数返回的多个结果

 

在下面的代码中,我们从/post中获取一个帖子,然后在/comments中获取相关评论。由于我们使用的是async/await,函数把返回值放在一个数组中。而我们使用数组解构后就可以把返回值直接赋给相应的变量。

async function getFullPost(){

return await Promise.all([

fetch('/post'),

fetch('/comments')

]);

}

const [post, comments] = getFullPost();

5.5 将数组平铺到指定深度

 

使用递归,为每个深度级别 depth 递减 1 。 使用 Array.reduce() 和 Array.concat() 来合并元素或数组。 基本情况下,depth 等于 1 停止递归。 省略第二个参数,depth 只能平铺到 1 (单层平铺) 的深度。

const flatten = (arr, depth = 1) =>

depth != 1

? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), [])

: arr.reduce((a, v) => a.concat(v), []);

flatten([1, [2], 3, 4]);                             // [1, 2, 3, 4]

flatten([1, [2, [3, [4, 5], 6], 7], 8], 2);           // [1, 2, 3, [4, 5], 6, 7, 8]

5.6 数组的对象解构

 

数组也可以对象解构,可以方便的获取数组的第n个值

const csvFileLine = '1997,John Doe,US,john@doe.com,New York';

const { 2: country, 4: state } = csvFileLine.split(',');

country            // US

state            // New Yourk

6. 对象

 

6.1 使用解构删除不必要属性

有时候你不希望保留某些对象属性,也许是因为它们包含敏感信息或仅仅是太大了(just too big)。你可能会枚举整个对象然后删除它们,但实际上只需要简单的将这些无用属性赋值给变量,然后把想要保留的有用部分作为剩余参数就可以了。

下面的代码里,我们希望删除_internal和tooBig参数。我们可以把它们赋值给internal和tooBig变量,然后在cleanObject中存储剩下的属性以备后用。

let {_internal, tooBig, ...cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'};

console.log(cleanObject);                         // {el1: '1', el2: '2', el3: '3'}

6.2 在函数参数中解构嵌套对象

 

在下面的代码中,engine是对象car中嵌套的一个对象。如果我们对engine的vin属性感兴趣,使用解构赋值可以很轻松地得到它。

var car = {

model: 'bmw 2018',

engine: {

v6: true,

turbo: true,

vin: 12345

}

}

const modelAndVIN = ({model, engine: {vin}}) => {

console.log(`model: ${model} vin: ${vin}`);

}

modelAndVIN(car); // => model: bmw 2018  vin: 12345

7. 代码复用

 

7.1 Object [key]

虽然将 foo.bar 写成 foo ['bar'] 是一种常见的做法,但是这种做法构成了编写可重用代码的基础。许多框架使用了这种方法,比如element的表单验证。

请考虑下面这个验证函数的简化示例:

function validate(values) {

if(!values.first)

return false;

if(!values.last)

return false;

return true;

}

console.log(validate({first:'Bruce',last:'Wayne'})); // true

上面的函数完美的完成验证工作。但是当有很多表单,则需要应用验证,此时会有不同的字段和规则。如果可以构建一个在运行时配置的通用验证函数,会是一个好选择。

// object validation rules

const schema = {

first: {

required:true

},

last: {

required:true

}

}

// universal validation function

const validate = (schema, values) => {

for(field in schema) {

if(schema[field].required) {

if(!values[field]) {

return false;

}

}

}

return true;

}

console.log(validate(schema, {first:'Bruce'})); // false

console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

现在有了这个验证函数,我们就可以在所有窗体中重用,而无需为每个窗体编写自定义验证函数。

网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:

  1. JavaScript 开发人员需要知道的简写技巧

  2. 《Effective Javascript》

  3. 不得不知的ES6小技巧

  4. js运算符的一些特殊应用

  5. JS高级技巧(简洁版)

  6. 小议 js 下字符串比较大小

【js】中的小技巧的更多相关文章

  1. (网页)JS中的小技巧,但十分的实用!

    转自CSDN: 1.document.write(”"); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->(head,body)4. ...

  2. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  3. js 数组去重小技巧

    js 数组去重小技巧 Intro 今天遇到一个问题,需要对数据进行去重,想看一下有没有什么比较方便的方法,果然有些收获. Question 问题描述: 我有一个这样的数据: [ { "Pro ...

  4. 杂谈---小故事小道理,面试中的小技巧(NO.2)

    本篇是接着上一篇面试随笔的,上一次有猿友反应写的有些“扯淡”,LZ思来想去最大的原因可能是由于上一章写的全是一些大忌,既然是大忌,那么在现实当中发生的概率还是相对较小的,大部分人还是很少在面试中犯如此 ...

  5. lua学习笔记11:lua中的小技巧

    lua中的小技巧,即基础lua语言本身的特种,进行一个些简化的操作 一. 巧用or x = x or v 等价于: if not x then x = v end 假设x为nil或false,就给他赋 ...

  6. js中OOP小指南

    js中OOP小指南 在指南中,我将尝试解析以面向对象规范聚焦的es6的新特性. 首先, 什么是设计模式 范例是某个事务的例子或模型,在某种情况下,按照一种模式创建了计算机程序. 什么是面向对象 显然你 ...

  7. JS Math对象中一些小技巧

    JS中快速获取数组中最大/最小值 var a=[1,2,3,5]; alert(Math.max.apply(Math, a));//最大值 alert(Math.min.apply(Math, a) ...

  8. js几个小技巧和坑

    蝴蝶书看了,也知道充满了毒瘤和糟粕,但该用还是得用. 实际写了几天,小技巧记录下来.都是在py里有直接答案,不会遇到的问题,没想到js里这么费事. 还是要多读<ES6标准入门> 1判断ob ...

  9. iOS开发中调试小技巧

    对于软件开发而言,调试是必须学会的技能,重要性不言而喻.对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中.不同语言.不同IDE.不同平台的 ...

随机推荐

  1. 01_NIO基本概念

    [NIO的几个概念] Buffer(缓冲区) Channel(通道,管道) Selector(选择器,多路复用器) [Buffer] Buffer是一个对象,它包括一些要写入或者要读取的数据.在NIO ...

  2. c++开发ocx入门实践三--基于opencv的简易视频播发器ocx

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51404649  利用opencv做了个简易的视频播放器的ocx,可以在c++/c#/web ...

  3. 【Machine Learning】分类与回归 区别

    一.分类与回归的区别 两类监督学习 Classification Regression 分类和回归的区别在于输出变量的类型(而非输入变量). 定性输出称为分类,或者说是离散变量预测(discrete) ...

  4. 【Python】Python3基本语法入门学习

    0.Python概述 1.First Word Game 2.变量与字符串 3.improved game 4.Python数据类型 5.常用操作符 6.分支与循环 7.列表 8.元组 9.字符串内置 ...

  5. EF单实对应多表

    一.单实体对应多表 适用场景主表,拥有相同主键附属表或扩展表. 1. 建表词句 CREATE TABLE [Chapter2].[Product]( [SKU] [int] primary key , ...

  6. Python零基础学习系列之四--Python程序设计思想

    前面我们把Python环境安装成功,同时也选择了自己合适的IDE工具来开启自己的编程之旅. 那么今天来说说怎么编程,程序设计需要什么步骤,我们应该怎么做才能编写自己的程序. 1-1.程序设计方法: I ...

  7. QT的lineidet的光标问题

    http://blog.csdn.net/Howard_Liu1314/article/details/10456165

  8. linux中进入mysql时报错Access denied for user 'root'@'localhost' (using password: YES)解决方案

    之前在linux中装完mysql后直接在命令行窗口输入mysql就会进入数据库了,但是今天输入mysql命令后直接报错,如下图: 之后输入:mysql -uroot -p 提示输入密码:***** 还 ...

  9. Hyperledger Fabric 1.0 学习搭建 (二)--- 源码及镜像文件处理

    2.1下载Fabric源码下载Fabric源码是因为要用到源码中提到的列子和工具, 工具编译需要用到go语言环境, 因此需要把源码目录放到$GOPATH下. 通过1.3中go的安装配置, $GOPAT ...

  10. mangodb驱动编译

    1.Installing the MongoDB C Driver (libmongoc) and BSON library (libbson) Building on Windows with Vi ...