箭头函数的用法
ES6 允许使用“箭头”(=>)定义函数。
1 | let xxx = (p1,p2)=>{ |
2 | console.log(1) |
3 | return 2 |
4 | } |
5 | |
6 | // 只有一个参数,可以省略括号 |
7 | let xxx = p1 =>{ |
8 | console.log(1) |
9 | return 2 |
10 | } |
11 | |
12 | // 代码块只有一句话时,可以省略花括号和return |
13 | let xxx = (p1,p2) => p1+p2 |
14 | // 等同于 |
15 | let xxx = function(p1,p2) { |
16 | return p1 + p2; |
17 | }; |
18 | |
19 | // 只有一个参数,代码块只有一句话时,可以省略括号、花括号和return |
20 | let xxx = p1 => p1*2 |
21 | |
22 | // 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。 |
23 | let f = () => 5; |
24 | // 等同于 |
25 | let f = function () { return 5 }; |
箭头函数的一个用处是简化回调函数。
1 | // 正常函数写法 |
2 | [1,2,3].map(function (x) { |
3 | return x * x; |
4 | }); |
5 | |
6 | // 箭头函数写法 |
7 | [1,2,3].map(x => x * x); |
箭头函数 this 的用法
先看个 ES 3 this 的用法的例子
1 | let obj = { |
2 | name: 'obj', |
3 | hi:function(p1,p2){ |
4 | console.log(this.name) |
5 | } |
6 | } |
7 | obj.hi(1,2) //等价于 obj.hi.call(obj,1,2) |
可以看出 this 是 call 的第一个参数,如果不传call,很难知道 this 到底指向谁。
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
this对象的指向是可变的,但是在箭头函数中,它是固定的。
1 | function foo() { |
2 | setTimeout(() => { |
3 | console.log('id:', this.id); |
4 | }, 100); |
5 | } |
6 | |
7 | var id = 21; |
8 | |
9 | foo.call({ id: 42 }); |
10 | // id: 42 |
箭头函数可以让this指向固定化,这种特性很有利于封装回调函数。下面是一个例子,DOM 事件的回调函数封装在一个对象里面。
1 | var handler = { |
2 | id: '123456', |
3 | |
4 | init: function() { |
5 | document.addEventListener('click', |
6 | event => this.doSomething(event.type), false); |
7 | }, |
8 | |
9 | doSomething: function(type) { |
10 | console.log('Handling ' + type + ' for ' + this.id); |
11 | } |
12 | }; |
上面代码的init方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。否则,回调函数运行时,this.doSomething这一行会报错,因为此时this指向document对象。
箭头函数转成 ES5 的代码如下。
1 | // ES6 |
2 | function foo() { |
3 | setTimeout(() => { |
4 | console.log('id:', this.id); |
5 | }, 100); |
6 | } |
7 | |
8 | // ES5 |
9 | function foo() { |
10 | var _this = this; |
11 | |
12 | setTimeout(function () { |
13 | console.log('id:', _this.id); |
14 | }, 100); |
15 | } |
下面的代码之中有几个this
1 | function foo() { |
2 | return () => { |
3 | return () => { |
4 | return () => { |
5 | console.log('id:', this.id); |
6 | }; |
7 | }; |
8 | }; |
9 | } |
10 | |
11 | var f = foo.call({id: 1}); |
12 | |
13 | var t1 = f.call({id: 2})()(); // id: 1 |
14 | var t2 = f().call({id: 3})(); // id: 1 |
15 | var t3 = f()().call({id: 4}); // id: 1 |
上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。
除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。
1 | function foo() { |
2 | setTimeout(() => { |
3 | console.log('args:', arguments); |
4 | }, 100); |
5 | } |
6 | |
7 | foo(2, 4, 6, 8) |
8 | // args: [2, 4, 6, 8] |
上面代码中,箭头函数内部的变量arguments,其实是函数foo的arguments变量。
另外,由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。