阅读 1879

想写出优雅的代码?试试这些ES6小tips

最近又重温了ES6的文档,发现除了箭头函数,解构赋值,扩展运算符这样常用的语法外,还有很多很给力的方法,不仅使代码更简洁,还可以提高代码的健壮性,更令我意外的是,浏览器兼容大部分的方法,无需babel也可完美运行。所以觉得很有必要整理一下,在项目中,抛弃陈旧的老古董写法,升级为ES6规范代码。

一.数组升级

1.扩展运算符之复制数组

//es5做法
const a1 = [1, 2]
const a2 = a1.concat()

a2[0] = 2
a1 //[1,2] 修改a2不会对a1有影响
复制代码

扩展运算符提供了复制数组的简便写法:

//es6做法
const a1 = [1, 2]
const a2 = [...a1]
//or
const [...a2] = a1

a2[0] = 2
a1 //[1,2] 修改a2不会对a1有影响
复制代码

注:上述复制的过程是深拷贝,但是要注意的一点是,concat和扩展运算符用做合并数组时,都是浅拷贝。

2.数组实例的find()和findIndex()

find方法,用于找出第一个符合条件的数组成员,它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

//es5做法
const arr = [1,5,10,15]
for(var i=0;i<arr.length;i++) {
    if(arr[i]>5) {
        return arr[i]
    }
} //10
//es6做法
[1,5,10,15].find(function(value,index,arr) {
    return value > 5
}) //10
复制代码

另外,这两个方法都可以发现NaN,弥补了indexOf方法的不足。

[NaN].indexOf[NaN] //-1

[NaN].findIndex(y => Object.is(NaN,y)) //0
复制代码

3.数组实例的includes()

该方法返回一个布尔值,表示某个数组是否包含给定的值。没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。

indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判。

[NaN].indexOf[NaN] //-1

[NaN].includes(NaN) //0
复制代码

注:Map和Set数据结构有一个has方法,注意与includes区分。Map结构的has方法,是来查找键名的 Set结构的has方法,是用来查找键值的。

二.对象升级

1.Object.assign()

用于对象的合并,将原对象的所有可枚举属性,复制到目标对象上。

object.assign拷贝的属性是有限制的,只拷贝源对象自身的属性(不拷贝继承属性,也不拷贝不可枚举的属性)

//为对象添加属性和方法
//es6
class Point {
 constructor(x, y) {
   Object.assign(this, {x, y});
 }
}
Object.assign(Point.prototype, {
 addPoint(arg1, arg2) {
   ···
 }
});
复制代码

这个方法很常用,但一些细节问题还是要拎出来提醒自己注意一下。

(1)浅拷贝

Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

(2)同名属性的替换

对于这种嵌套的对象,一旦遇到同名的属性,Object.assign的处理方法是替换,而不是添加。要特别注意!!

(3)数组的处理

Object.assign可以用来处理数组,但是会把数组视为对象。

2.属性的遍历

ES6 一共有 5 种方法可以遍历对象的属性。

(1)for...in

for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

(2)Object.keys(obj)

Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

(3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)的键名。

(4)Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

(5)Reflect.ownKeys(obj)

Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

三. 函数升级

1.rest参数

用于获取函数的多余参数,这样就不需要使用arguments对象了。

// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
复制代码

2.箭头函数

ES6 允许使用“箭头”(=>)定义函数。

// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
复制代码

注意点:

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

四.for...of循环

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。

1.用法

数组:

//为对象添加属性和方法
//es6
const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}
复制代码

Set 和 Map 结构

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
 console.log(e);
}
// Gecko
// Trident
// Webkit

var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
 console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-262
复制代码

类数组的对象

// 字符串
let str = "hello";

for (let s of str) {
 console.log(s); // h e l l o
}

// DOM NodeList对象
let paras = document.querySelectorAll("p");

for (let p of paras) {
 p.classList.add("test");
}

// arguments对象
function printArgs() {
 for (let x of arguments) {
   console.log(x);
 }
}
printArgs('a', 'b');
// 'a'
// 'b'
复制代码

2.与其他遍历语法的比较

for...in循环有几个缺点。

  • 数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
  • for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键
  • 某些情况下,for...in循环会以任意顺序遍历键名。 总之,for...in循环主要是为遍历对象而设计的,不适用于遍历数组。

forEach循环的缺点是无法中途跳出forEach循环,break命令或return命令都不能奏效。

与之相对的,for...of有如下优点:

  • 有着同for...in一样的简洁语法,但是没有for...in那些缺点。
  • 不同于forEach方法,它可以与break、continue和return配合使用。
  • 提供了遍历所有数据结构的统一操作接口。

五.参考网址

http://es6.ruanyifeng.com/#docs/iterator#for---of-%E5%BE%AA%E7%8E%AF

关注下面的标签,发现更多相似文章
评论