写这篇文章的缘由是最近感觉在公司的一些需求和功能开发需求上,对一些js处理不是很熟练,缺乏一些技巧。因此整理了一份在实际开发过程中常用的 js 技巧,灵活地运用,能够解决问题的能力,也会对代码的简洁性有较大的提升。
01.数组去重
正常我们实现数组去重都是通过双层变量或者indexOf的方式。
(1)双层for循环去重
function unique(arr) {
for(var i=0;i<arr.length;i++) {
for(var j=i+1;j<arr.length;j++) {
if(arr[i] === arr[j]) {
arr.splice(j,1);
j--
}
}
}
return arr;
}
(2)利用indexOf去重
function unique(arr) {
if(!Array.isArray(arr)) {
console.log('type error!');
return;
}
var array = [];
for (var i=0;i<arr.length;i++) {
if(array.indexOf(arr[i]) === -1) {
array.push(arr[i]);
}
}
return array;
}
但其实有一种更简单的方式:利用Array.from与set去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!');
return;
}
return Array.from(new Set(arr));
}
02、截断数组
如果你有修改数组长度为某个固定值的需求,那么你可以试试这个
let arr = [0,1,2,3,4,5];
arr.length = 3;
console.log(array);
Output:[0,1,2];
03、获取数组中的最后一项
通常获取数组最后一项,我们用的比较多的是:
let arr = [0,1,2,3,4,5];
const last = arr[arr.length - 1];
console.log(last);
Output: 5;
但我们也可以通过slice操作来实现:
let arr = [0,1,2,3,4,5];
const last = arr.slice(-1)[0];
console.log(last);
Output: 5;
04、美化你的JSON
日常开发中,会经常使用到 JSON.stringify,但并不清楚他具体有哪些参数,实际上它有三个参数:
- json: 必须,可以是数组或Object
- replacer: 可选值,可以是数组,也可以是方法
- space: 用什么来进行分割
而我们恰恰可以指定第三个参数space的值去美化我们的JSON。
05、数组转化为对象(Array to Object)
数组转化为对象,大多数同学想到的是通过遍历数组,放入空对象的方式:
var obj = {};
var arr = ["1","2","3"];
for (var key in arr) {
obj[key] = arr[key];
}
console.log(obj);
Output: {0:1,1:2,2:3}
但是有一种比较简单快速的方法,即利用展开运算符展开数组
var arr = ["1","2","3"];
var obj = {...arr};
console.log(obj);
Output:{0:1,1:2,2:3}
06、合理利用三元表达式
有些场景我们需要针对不同的条件,给变量赋予不同的值,往往通过if—else的方式:
const isGood = true;
let feeling;
if (isGood) {
feeling = 'good';
} else {
feeling = 'bad';
}
console.log(`I feel ${feeling}`)
Output: I feel good
但是为什么不采用三元表达式呢?
const isGood = true;
const feeling = isGood ? 'good' : 'true';
console.log(`I feel ${feeling}`);
Output: I feel good
这种也是所谓的 Single line (单行)思想,其实就是代码趋向于极简的风格。
07、转换为数字类型(Convert to Number)
常见转换为数字的方式,可能主要通过parseInt() 、Number() 这两种方式:
const age = "30";
const ageConvert = parseInt(age);
console.log(typeof ageConvert);
Output: number;
其实也可以通过 +
操作来实现转换:
const age = "30";
const ageConvert = +age;
console.log(typeof ageConvert);
Output: number
08、转换为字符串类型(Convert to String)
常见转换为字符串的方式,可能主要通过toString()、String() 这两种方式:
let a = 123;
console.log(typeof a.toString());
Output: string
但也可以通过 value + ""
的方式来实现
let a = 123;
console.log(typeof (a + ""));
Output: string
09、性能追踪
如果想要测试一段 js 代码的执行耗时,可以尝试使用 performance
:
let start = performance.now();
let sum = 0;
for (let i = 0; i < 100000; i++ ) {
sum += 1;
}
let end = performance.now();
console.log(start);
console.log(end);
10、合并对象 (Combining Objects)
合并两个对象使用的最多 API 就是 Object.assign()
了:
const obj1 = {a:1};
const obj2 = {b:2};
console.log(Object.assign(obj1, obj2));
Output:{a:1, b:2}
实际上通过扩展运算符 (spread operator) 会特别简单:
const obj1 = {a:1};
const obj2 = {b:2};
console.log({...obj1, ...obj2});
Output:{a:1, b:2}
11、短路运算(Short-circuit evalutation)
可以通过 && 或 | | 来简化我们的代码,比如:
if (isOnline) { postMessage()};
// 使用 &&
isOnline && postMessage();
// 使用 ||
let name = null || "jerry";
12、数组扁平化(Flattening an array)
数组的扁平化一般会通过递归
或reduce
去实现。
(1) 递归:
var arr = [1,[2,[3,4]]];
function flatten(arr) {
var result = [];
for (var i = 0; i < arr.length; i++ ) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
}
console.log(flatten(arr));
Output:[1,2,3,4]
(2) reduce:
var arr = [1,[2,[3,4]]];
function flatten(arr) {
return arr.reduce(function(prev,next) {
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, []);
}
但是 ES6 提供了一个新方法 flat(depth)
, 参数 depth ,代表展开嵌套数组的深度,默认值是1
let arr = [1,[2,[3,[4,[5]]]]];
console.log(arr.flat(3));
Output:[1, 2, 3, 4, [5]]
13、求幂运算
平时实现指数运算,用的比较多的应该是 Math.pow()
,比如求 2^10:
console.log(Math.pow(2,10));
在 ES7 中引入了指数运算符 **
, **
具有与 Math.pow() 一样的运算结果。
console.log(2**10); // 1024
14、浮点数转为整数 (Float to Integer)
一般将浮点数转化为整数会用到 Math.floor() , Math.ceil() , Math.round() 。但其实使用位运算符 ~
,>>
,<<
,|
,>>>
也能够实现取整。
console.log(~~5.96); // 5
console.log(5.96 >> 0);// 5
console.log(5.96 << 0);// 5
console.log(5.96 | 0);// 5
// >>> 不可对负数取整
console.log(5.96 >>> 0);// 5
15、Object.create(null)
在 Vue 和 Vuex 的源码中,作者都使用了 Object.create(null) 来初始化一个新对象。为什么不使用更简洁的 {} 呢?我们来看下 Object.create() 的定义:
Object.create(proto,[propertiesObject]);
- proto: 新创建对象的原型对象;
- propertiesObject: 可选。要添加到新对象上的可枚举的属性(新添加的属性是其自身的属性,而不是其原型链上的属性)。
我们可以对比分别通过 Object.create(null) 和 {} 创建对象的不同:
从上图可以看到,通过 {} 创建的对象继承了 Object 自身的方法,如 hasOwnProperty 、toString 等,在新对象上可以直接使用。
而使用 Object.create(null) 创建的对象,除了自身属性之外,原型链上没有任务属性。也就是说通过Object.create(null) 的方式可以创建一个纯净的对象,我们可以自己定hasOwnProperty、toString 等方法,完全不必担心会将原型链上的同名方法覆盖掉。
16、拷贝数组
日常开发中,数组的拷贝是一个经常会遇到的场景。实现数组的拷贝有很多骚技巧。
(1)Array.slice()
const arr = [1,2,3];
const copyArr = arr.slice();
(2)展开操作符
const arr = [1,2,3];
const copyArr = [...arr];
(3)使用 Array 构造函数和展开操作符
const arr = [1,2,3,4];
const copyArr = new Array(...arr);
(4)Array.concat
const arr = [1,2,3,4];
const copyArr = arr.concat();
17、避免多条件并列
开发中有时会遇到多个条件,执行相同的语句,也就是多个 ||
的情况:
if (status === "a" || status === "b" || status === "c") {doSomething();}
这种写法语义性、可读性都不太好。可以通过 switch case 或 includes 的方式进行改造。
(1) switch case
switch (case ) {
case "a":
case "b":
case "c":
doSomeThing();
}
(2) includes
const enum = ["a","b","c"];
if (enum.includes(status)) { doSomeThing(); }
18.Object.freeze()
在 Vue 的文档中介绍数据绑定和响应时,特意标注了对于经过 Object.freeze() 方法的对象无法进行更新响应。Object.freeze() 方法用于冻结对象,禁止对于该对象的属性进行修改。正是由于这种特性,所以在实际项目中,它有很多的使用场景。
像一些纯展示类的页面,可能存在巨大的数组或对象,如果这些数据不会发生改变,那么你就可以使用 Object.freeze() 将它们冻结,这样 Vue 就不会对这些对象做 setter 或 getter 的转换,可以大大提升性能。