Javascript的一些实用技巧(持续更新)

整理一些自己觉得有用的js的技巧跟知识点,嘛,想到哪写到哪吧,毕竟我记性这么差,还这么懒。

变量交换值

1
2
3
var a = 'world', b = 'hello';
[a, b] = [b, a]
console.log(a, b) // hello world

ES6的解构赋值算是我非常喜欢的一个功能了,允许按照一定模式,从数组和对象中提取值,对变量进行赋值。
如果是两个数字交换值的话,还可以这么做:

1
2
3
4
5
var a = 12, b = 2;
a ^= b;
b ^= a;
a ^= b;
console.log(a, b) // 2 12

这个东西就比较黑科技了,按位运算符异或^,将数字转为二进制进行按位比对,上面的计算步骤大概是(位数就不写全了):

1
2
3
a = 12 ^ 2 = 1100 ^ 0010 = 1110 = 14;
b = 14 ^ 2 = 1110 ^ 0010 = 1100 = 12;
a = 14 ^ 12 = 1110 ^ 1100 = 0010 = 2;

快速取整

1
2
3
4
5
console.log(~~47.11)  // 47
console.log(~~-12.88) // -12
console.log(~~3) // 3
console.log(~~'1.2') // 1
console.log(~~NaN) // 0

按位取反运算符~,会先判断类型进行隐式转换,之后将数字原码转二进制之后进行取反,再取其补码,除符号位外取反再加1
对于数字和字符串类型,执行两次后就可以快速实现一个取整的效果,其他类型会转换成0

转换数字

1
2
console.log(+'1')  // 1
console.log(+{}}) // NaN

当进行运算时会隐式转换数字,所以使用+可以快速地转换数字

转换Boolean

1
2
console.log(!!1)  // true
console.log(!!'') // false

二次取反不解释,简单粗暴

参数解构和字符串拼接

1
2
3
4
5
6
7
8
9
10
11
12
let person = {
name: "张三",
age: 20
}

function say ({name, age}) {
// let message = '大家好,我叫'+ name +',我今年'+ age +'岁了';
let message = `大家好,我叫${name},我今年${age}岁了`;
console.log(message)
}

say(person); // 大家好,我叫张三,我今年20岁了

在函数方法中使用参数解构可以更方便的获取数组/对象中的值。
在拼接字符串时,在替换引号之后,可以使用${}将变量直接写入字符串中,相比于+拼接字符串更加灵活。

valueOf 和 toString

抛开二者的基本作用不谈,作为对象和方法的隐式属性,有一些意想不到的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var a = {
value: 0,
valueOf: function () {
console.log('valueOf');
return this.value += 1;
},
toString: function () {
console.log('toString');
return this.value += 1;
}
}

alert(a); // valueOf 1
alert(a); // valueOf 2
console.log(+a); // toString 3
console.log(+a); // toString 4

可以发现,运算会触发对象的valueOf方法,取值会触发toString方法
以上的写法,每次对于对象获取到的值都不同,在调用之后都会发生改变,于是就可以实现一个很有意思的效果。

1
console.log(a === 1 && a === 2 && a === 3);  // valueOf valueOf valueOf true

&&运算符也会触发valueOf,就能实现这么一个一眼看上去几乎不可能为true的表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
function add (num) {
var sum = num;
var _add = function (_num) {
sum += _num;
return _add;
}
_add.toString = function () {
return sum;
}
return _add;
}

console.log(add(1)(2)(3)) // 6

既然取值触发toString,那么就可以在这上面做一些文章了,将一个函数方法链式调用来计算所有参数和,最后在取值的时候使用toString方法拿到值。

Spread 扩展运算符

ES6的扩展运算符...可以将一个数组转为用逗号分隔的参数序列

1
2
3
4
5
6
function add(x, y) {
return x + y;
}

let numbers = [4, 38];
add(...numbers) // 42

合并数组

1
2
3
let arr1 = ['a', 'b'];
let arr2 = ['c'];
console.log([...arr1, ...arr2]); // ['a', 'b', 'c']

数组&对象克隆,拒绝浅拷贝

1
2
3
4
5
let arr = [], obj = {};
// let newArr = Object.assign([], arr);
// let newArr = JSON.parse(JSON.stringify(arr));
let newArr = [...arr];
let newObj = {...obj};

取数组最大值/最小值

1
2
3
let arr = [4, 6, 55, 12, 21];
console.log(Math.max(...arr)); // 55
console.log(Math.min(...arr)); // 4

将字符串转为数组

1
console.log([...'hello'])  // ['h', 'e', 'l', 'l', 'o']

平铺多维数组,这里只列举二维的

1
2
3
let arr11 = [11, [22, 33], [44, 55], 66];
let flatArr = [].concat(...arr);
console.log(flatArr); // [11, 22, 33, 44, 55, 66]

Set 数组去重

1
2
let unique = arr => [...new Set(arr)];
console.log(unique(['h', 'e', 'l', 'l', 'o'])); // ['h', 'e', 'l', 'o']

ES6 提供了新的数据结构 Set。它类似于数组,允许存储任何类型的唯一值。
Set 本身是一个构造函数,用来生成 Set 数据结构,使用 Set 将数组处理之后再将其转为数组,就可以实现简单的数组去重

生成随机字符串

1
Math.random().toString(32).substr(2)

生成结果类似于’n76ebcr9sg’这样的字符串,toString方法可以转换数字进制,32进制数字包含了a-z和0-9这些字符,在生成随机数转换32位后截取前两位的’0.’,就可以快速的生成一个随机字符串。

typeof

1
2
typeof null   // object
typeof new Array() // object

在使用typeof判断数据类型的时候,需要注意null的类型判断也是’object’(毕竟万物皆对象)
由于js的基本类型没有数组类型,所以数组的typeof也是’object’,那么如何去区分数组和对象呢

1
2
3
4
5
6
7
8
9
let arr = [], obj = {} 
Array.isArray(arr) // true
Array.isArray(obj) // false

typeof arr === 'object' && !isNaN(arr.length)//true
typeof obj === 'object' && !isNaN(obj.length)//false

Object.prototype.toString.call(arr) // [object Array]
Object.prototype.toString.call(obj) // [object Object]

instanceof

1
2
3
4
5
6
new Number(1) instanceof Number  // true  
1 instanceof Number // false
new String('hello') instanceof String // true
'hello' instanceof String // false
[] instanceof Array // true
[] instanceof Object // true

在使用instanceof判断类型的时候也需要注意,instanceof只对对象实例生效,对于基本类型的验证都是false,而对于数组的类型判断,既是数组也是对象

在条件中使用 && 及 || 进行短语判断

1
2
3
let foo = 10;  
foo === 10 && doSomething(); // === if (foo === 10) doSomething();
foo === 5 || doSomething(); // === if (foo !== 5) doSomething();

这种写法算是利用了&&||的特性,起到了和if语句相同的效果。
&&会执行所有的条件判断语句,||执行到true的时候就会短路掉之后的条件,不去执行。

变量属性名

1
2
3
4
5
let key = 'hello', value = 'world';
console.log({ // {hello: 'world'}
[key]: value
}
})

ES6允许使用变量来作为对象的属性。

浮点数计算

1
2
3
console.log(0.1 + 0.2)  // 0.30000000000000004
console.log((0.1 + 0.2).toFixed(1)) // 0.3
console.log(0.1 * 10 + 0.2 * 10)/ 10) // 0.3

js的浮点数计算算是很烦人的一点了,转换二进制之后对于浮点数的识别很不友好,最简单的解决办法就是使用toFixed了,还有就是转换为整数之后再进行计算,当然还有其它的方法,封装好的工具包等,就不多介绍了。

获取出现次数

当我们想要获取字符串中某个字符串出现的次数,比如ggasddghasdw中’a’出现的次数

1
2
let str = 'ggasddghasdw';
console.log(str.split('a').length - 1) // 2

同理,对于数组元素也可以使用这样的方式

1
2
let arr = [1, 2, 3, 5, 3];
console.log(arr.toString().split(3).length - 1) // 2

深拷贝对象

使用ES6的方法可以更灵活的完成对象的深拷贝

1
2
3
4
5
6
7
8
9
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 });
delete copy.a; // copy => { b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 };
const { a, ...result } = copy; // result => { b: 2, c: 3 }

未完待续

文章目录
  1. 1. 变量交换值
  2. 2. 快速取整
  3. 3. 转换数字
  4. 4. 转换Boolean
  5. 5. 参数解构和字符串拼接
  6. 6. valueOf 和 toString
  7. 7. Spread 扩展运算符
  8. 8. Set 数组去重
  9. 9. 生成随机字符串
  10. 10. typeof
  11. 11. instanceof
  12. 12. 在条件中使用 && 及 || 进行短语判断
  13. 13. 变量属性名
  14. 14. 浮点数计算
  15. 15. 获取出现次数
  16. 16. 深拷贝对象
|