ES6 正式发布也久矣,2015年就发布了,所以赶紧用起来吧。相对来说,如果你会了TypeScript,那ES6也基本不是事儿了吧。
let和const
1、通用特性:声明不能提升,必须先声明后使用;只在声明所在的块级作用域内有效;不能重复声明。否则均会报错。
console.log(test); let test; for (let i = 0; i < 10; i++) { } console.log(i); let i=1; let i=2; console.log(it);
|
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) { tmp = 'abc'; console.log(tmp); let tmp; console.log(tmp); tmp = 123; console.log(tmp); }
|
2、let 和块级作用域
ES6通过let和{}来实现块级作用域,解决了for循环、if语句泄露变量到全局,内层变量不会覆盖外层变量。
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); }
|
注意:ES6虽然允许在块级作用域内声明函数,但是会和实现ES5的浏览器相冲突导致出错,所以不要在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
3、const:声明一个只读的常量。一旦声明,常量的值就不能改变,所以必须声明后立即赋值,否则报错。
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
const foo = {}; foo.prop = 123; foo.prop foo = {};
|
箭头函数
箭头函数相当于匿名函数,如果只包含一个表达式则可以省略{}和return语句,如果没有参数或者有多个参数则要用()括起来。
x => x*x () => 3.14 x => { return x*x } (a,b) => { return a+b }
|
箭头函数中的this
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,即箭头函数可以让this指向固定化。
- 不可以当作构造函数,也就是说,不可以使用new命令。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
- 用call()调用箭头函数时第一个参数会被忽略
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 });
|
Generator
生成器函数,类似一个状态机,通过next()会遍历每个yield后面的值,每次返回value和done的结果,一直遍历到最后得到return返回值,最后的状态才会返回done:true。
function* show(){ yield 'hello'; yield 'world'; return 'ok' } show(); console.log(show().next()); console.log(show().next()); console.log(show().next());
|
yield语句本身没有返回值,或者返回undefined
next()也可以有参数,但是参数的作用是作为上一个yield的返回值
可以用for…of循环来遍历Generator函数
function* show(){ yield 'hello'; yield 'world'; return 'ok' } for(let n of show()){ console.log(n); }
|
async
async是Generator函数的语法糖,配合await实现异步操作,async关键字表示后面的函数里面有异步操作,await表示紧跟在后面的表达式需要等待结果。async返回一个Promise对象,可以用then添加回调函数。async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 50);
|
class
类:
class Person{ constructor(name,age){ this.name=name; this.age=age; } showName(){ console.log(this.name) } showAge(){ console.log(this.age) } } let p1=new Person('Apple',10); let p2=new Person('Orange',20); p1.showName(); p1.showName ==p2.showName; p1.constructor==Person;
|
继承:extends
class Worker extends Person{ }
|
- 在构造函数内部实现继承父类的属性,并添加自己的方法,需要super()来实现
class Worker extends Person{ constructor(name,age,job){ super(name,age); this.job=job; } showJob(){ console.log(this.job); } } let w1=new Worker('iOS',10,'打杂的'); w1.showJob(); w1.showName();
|
###补充
1、ES6新增函数...rest
参数,可以获取指定参数之外的其他所有参数,返回一个数组。
function fn(a,b,...rest){ console.log(a); console.log(b); console.log(rest); } fn(1,2,3,4,5);
|
2、解构赋值:按照一定模式从数组或者对象中提取值,并对变量
进行赋值。解构时等号右边必须是可以遍历的对象。如果等号左右结构不一致,则会选取对应的位置进行解构赋值,不对应的返回undefined。
(1)数组解构:按照对应位置进行解构赋值,多个变量要用[]
包围起来
let a=1; let b=2; let c=3; let [a, b, c] = [1, 2, 3];
|
(2)对象解构:从等号右侧取同名属性的值,
let { foo, bar } = { foo: "aaa", bar: "bbb" }; foo bar let { foo: baz } = { foo: "aaa", bar: "bbb" }; baz foo let obj = {}; let arr = []; ({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true }); obj arr
|
(3)解构的应用
let x = 1; let y = 2; [x, y] = [y, x];
|
let jsonData = { id: 42, status: "OK", data: [867, 5309] }; let { id, status, data: number } = jsonData; console.log(id, status, number);
|
3、Proxy
可以理解成通过Proxy来对外部的访问进行过滤和改写。它有两个参数,第一个是目标对象,第二个是方法(get/set)
举个例子:
var person={ getMsg:function(){ console.log(this.name+' '+this.age) } };
|
4、Set 不允许重复元素的数组,通过 new Set()
来实现
let s=new Set([1,2,3,3]); s.add(4); s.delete(2); s.has(5); s.clear(); let arr = [3, 5, 2, 2, 5, 5]; let unique = [...new Set(arr)];
|
总结:ES6有的东西确实带来了很大方便,但是有的使用门槛较高,我这里只是简单的用法,复杂的还需要继续研究一下,我觉得可以直接学习TypeScript,再回过来看ES6的东西会感觉简单许多。
参考:阮一峰 ECMAScript6 入门