前言 ES6增加了不少新特性,灵活运用可以大幅提高工作效率,下面总结了一下比较常用的新特性。
let const
解构赋值
模板字符串
数组拓展
箭头函数
对象拓展
let 1 2 3 4 5 6 7 8 9 10 11 12 13 function test ( ) { for (let i=1 ;i<3 ;i++){ console .log(i); } console .log(i); let a = 1 ; let a = 2 ; } test();
let拥有块级作用域(花括号内就是一个块)
es6强制开启严格模式 严格模式下,没有变量提升,变量未声明,不能引用,报错Uncaught ReferenceError: a is not defined
,而不是undefined
let声明后的变量不能重复声明
const 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function last ( ) { const PI=3.14159265 ; PI = 6 ; console .log(PI); const PI; PI = 6 ; console .log(PI); const x={ a:1 } console .log(x); } last();
const同样拥有块级作用域
const声明基础类型值时是常量,不能被赋值修改
const必须声明时赋值,否则报错Uncaught SyntaxError: Missing initializer in const declaration
const声明引用类型值时,可以被修改
解构赋值
什么是解构赋值? ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
数组解构赋值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let [a, b, c] = [1 , 2 , 3 ];let a = 1 ;let b = 2 ;let c = 3 ;let [a, b, c=3 ] = [1 , 2 ];console .log(a,b,c); let [a, b, c] = [1 , 2 ];console .log(a,b,c); { let a,b,c; [a,b,...c]=[1 ,2 ,3 ,4 ,5 ,6 ]; console .log(a,b,c); }
适用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 { let a=1 ; let b=2 ; [a,b]=[b,a]; console .log(a,b); } { function fn ( ) { return [1 ,2 ] } let a,b; [a,b]=fn(); console .log(a,b); } { function fn ( ) { return [1 ,2 ,3 ,4 ,5 ] } let a,b,c; [a,,,b]=fn(); console .log(a,b); } { function fn ( ) { return [1 ,2 ,3 ,4 ,5 ] } let a,b,c; [a,,...b]=fn(); console .log(a,b); }
对象解构赋值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { let a,b; ({a,b}={a :1 ,b :2 }) console .log(a,b); } { let a={x :42 ,y :true }; let {x,y}=a; console .log(x,y); } { let {a=10 ,b=5 }={a :3 }; console .log(a,b); }
适用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 { let metaData={ title:'abc' , test:[{ title:'test' , desc:'description' }] } let {title :esTitle,test :[{title :cnTitle}]}=metaData; console .log(esTitle,cnTitle); }
字符串的拓展 includes(), startsWith(), endsWith()
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
1 2 3 4 5 let s = 'Hello world!' ;s.startsWith('world' , 6 ) s.endsWith('Hello' , 5 ) s.includes('Hello' , 6 )
repeat() repeat方法返回一个新字符串,表示将原字符串重复n次。1 2 3 'x' .repeat(3 ) 'hello' .repeat(2 ) 'na' .repeat(0 )
模板字符串 模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。1 2 3 4 5 6 { let name="list" ; let info="hello world" ; let m=`i am ${name} ,${info} ` ; console .log(m); }
使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
padStart(),padEnd() ES2017引入了字符串补全长度的功能。
padStart()用于头部补全
padEnd()用于尾部补全。
1 2 3 4 5 { console .log('1' .padStart(2 ,'0' )); console .log('1' .padEnd(2 ,'0' )); }
数值拓展 Number.isInteger() Number.isInteger()用来判断一个数值是否为整数。1 2 3 Number .isInteger(25 ) Number .isInteger(25.0 ) Number .isInteger(25.1 )
如果参数不是数值,Number.isInteger返回false
数组的拓展 扩展运算符 扩展运算符可以展开数组1 2 3 4 5 6 7 8 9 Math .max.apply(null , [14 , 3 , 77 ])Math .max(...[14 , 3 , 77 ])Math .max(14 , 3 , 77 );
适用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 const a1 = [1 , 2 ];const a2 = a1.concat();a2[0 ] = 2 ; a1 const a1 = [1 , 2 ];const a2 = [...a1];const [...a2] = a1;
1 2 3 4 5 6 7 8 9 10 11 const arr1 = ['a' , 'b' ];const arr2 = ['c' ];const arr3 = ['d' , 'e' ];arr1.concat(arr2, arr3); [...arr1, ...arr2, ...arr3]
1 2 3 4 a = list[0 ], rest = list.slice(1 ) [a, ...rest] = list
Array.of Array.of方法用于将一组值,转换为数组。1 2 3 4 5 6 7 { let arr = Array .of(3 ,4 ,5 ,6 ,7 ); console .log('arr=' ,arr); let empty=Array .of(); console .log('empty' ,empty); }
Array.from Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。1 2 3 4 5 6 7 8 9 10 { let p=document .querySelectorAll('p' ); let pArr=Array .from(p); pArr.forEach(function (item ) { console .log(item.textContent); }); console .log(Array .from([1 ,3 ,5 ],function (item ) {return item*2 })); }
entries(),keys() 和 values()
keys()是对键名的遍历
values()是对键值的遍历
entries()是对键值对的遍历。
1 2 3 4 5 6 7 8 9 10 11 { for (let index of ['1' ,'a' ,'bc' ].keys()){ console .log('keys' ,index); } for (let value of ['1' ,'a' ,'bc' ].values()){ console .log('values' ,value); } for (let [index,value] of ['1' ,'a' ,'bc' ].entries()){ console .log('entries' ,index,value); } }
find() findIndex() 和includes()
find()找出第一个符合条件的数组成员
findIndex()返回第一个符合条件的数组成员的位置
includes()返回一个布尔值,表示某个数组是否包含给定的值
1 2 3 4 5 6 7 8 9 { console .log([1 ,2 ,3 ,4 ,5 ,6 ].find(function (item ) {return item>3 })); console .log([1 ,2 ,3 ,4 ,5 ,6 ].findIndex(function (item ) {return item>3 })); console .log('number' ,[1 ,2 ,NaN ].includes(1 )); console .log('number' ,[1 ,2 ,NaN ].includes(NaN )); }
函数的拓展 默认值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 { function log (x, y ) { y = y || 'World' ; console .log(x, y); } function test (x, y = 'world' ) { console .log('默认值' ,x,y); } test('hello' ); test('hello' ,'kill' ); } { let x='test' ; function test2 (x,y=x ) { console .log('作用域' ,x,y); } test2('kill' ); } { var x='test' ; function test2 (x,y ) { y = x; console .log('作用域' ,x,y); } test2('kill' ); }
rest参数 rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { function test3 (...arg ) { for (let v of arg){ console .log('rest' ,v); } } test3(1 ,2 ,3 ,4 ,'a' ); } { console .log(...[1 ,2 ,4 ]); console .log('a' ,...[1 ,2 ,4 ]); }
rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
箭头函数 箭头函数有几个使用注意点。
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var f = v => v;var f = function (v ) { return v; }; var f = () => 5 ;var f = function ( ) { return 5 };var sum = (num1, num2 ) => num1 + num2;var sum = function (num1, num2 ) { return num1 + num2; }; { let arrow = v => v*2 ; let arrow2 = () => 5 ; console .log('arrow' ,arrow(3 console .log(arrow2()); }
简化回调函数1 2 3 4 5 6 7 [1 ,2 ,3 ].map(function (x ) { return x * x; }); [1 ,2 ,3 ].map(x => x * x);
改变this指向1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function foo ( ) { setTimeout(() => { console .log('id:' , this .id); }, 100 ); } function foo ( ) { var _this = this ; setTimeout(function ( ) { console .log('id:' , _this.id); }, 100 ); }
尾调用 某个函数的最后一步是调用另一个函数,就是尾调用1 2 3 function f (x ) { return g(x); }
尾调用的好处:尾调用优化
尾调用优化,就是使用尾递归,对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
ES6规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。
1 2 3 4 5 6 7 8 9 { function tail (x ) { console .log('tail' ,x); } function fx (x ) { return tail(x) } fx(123 ) }
对象的拓展 简洁表示法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { let o=1 ; let k=2 ; let es5={ o:o, k:k }; let es6={ o, k }; console .log(es5,es6); let es5_method={ hello:function ( ) { console .log('hello' ); } }; let es6_method={ hello(){ console .log('hello' ); } }; console .log(es5_method.hello(),es6_method.hello()); }
属性表达式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { let a='x' ; let es5_obj={ a:'c' , b:'c' }; let es6_obj={ [a]:'c' } console .log(es5_obj,es6_obj); }
注意,属性名表达式与简洁表示法,不能同时使用,会报错。
1 2 3 4 5 6 7 8 const foo = 'bar' ;const bar = 'abc' ;const baz = { [foo] };const foo = 'bar' ;const baz = { [foo]: 'abc' };
Object.is(),Object.assign()
Object.is()用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
Object.assign()可以实现对象的浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 { console .log('字符串' ,Object .is('abc' ,'abc' ),'abc' ==='abc' ); console .log('数组' ,Object .is([],[]),[]===[]); console .log('拷贝' ,Object .assign({a :'a' },{b :'b' })); let test={k :123 ,o :456 }; for (let [key,value] of Object .entries(test)){ console .log([key,value]); } }
1 2 3 4 5 6 7 8 { let {a,b,...c}={a :'test' ,b :'kill' ,c :'ddd' ,d :'ccc' }; c={ c:'ddd' , d:'ccc' } }
参考 阮一峰 ECMAScript 6 入门