最近又重温了ES6的文档,发现除了箭头函数,解构赋值,扩展运算符这样经常使用的语法外,还有不少很给力的方法,不只使代码更简洁,还能够提升代码的健壮性,更令我意外的是,浏览器兼容大部分的方法,无需babel也可完美运行。因此以为颇有必要整理一下,在项目中,抛弃陈旧的老古董写法,升级为ES6规范代码。javascript
//es5作法
const a1 = [1, 2]
const a2 = a1.concat()
a2[0] = 2
a1 //[1,2] 修改a2不会对a1有影响
复制代码
扩展运算符提供了复制数组的简便写法:java
//es6作法
const a1 = [1, 2]
const a2 = [...a1]
//or
const [...a2] = a1
a2[0] = 2
a1 //[1,2] 修改a2不会对a1有影响
复制代码
注:上述复制的过程是深拷贝,可是要注意的一点是,concat和扩展运算符用作合并数组时,都是浅拷贝。es6
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
复制代码
该方法返回一个布尔值,表示某个数组是否包含给定的值。没有该方法以前,咱们一般使用数组的indexOf方法,检查是否包含某个值。babel
indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,因此要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会致使对NaN的误判。数据结构
[NaN].indexOf[NaN] //-1
[NaN].includes(NaN) //0
复制代码
注:Map和Set数据结构有一个has方法,注意与includes区分。Map结构的has方法,是来查找键名的 Set结构的has方法,是用来查找键值的。ide
用于对象的合并,将原对象的全部可枚举属性,复制到目标对象上。函数
object.assign拷贝的属性是有限制的,只拷贝源对象自身的属性(不拷贝继承属性,也不拷贝不可枚举的属性)ui
//为对象添加属性和方法
//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能够用来处理数组,可是会把数组视为对象。
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 或字符串,也不论是否可枚举。
用于获取函数的多余参数,这样就不须要使用arguments对象了。
// arguments变量的写法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
复制代码
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循环可使用的范围包括数组、Set 和 Map 结构、某些相似数组的对象(好比arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
数组:
//为对象添加属性和方法
//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'
复制代码
for...in循环有几个缺点。
forEach循环的缺点是没法中途跳出forEach循环,break命令或return命令都不能奏效。
与之相对的,for...of有以下优势:
http://es6.ruanyifeng.com/#docs/iterator#for---of-%E5%BE%AA%E7%8E%AF