mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 10:22:23 +00:00
docs(function): fixed 箭头函数的this #1050
This commit is contained in:
parent
0163114de4
commit
71af30def1
@ -708,15 +708,15 @@ headAndTail(1, 2, 3, 4, 5)
|
||||
|
||||
箭头函数有几个使用注意点。
|
||||
|
||||
(1)函数体内的`this`对象,就是定义时所在的对象,而不是使用时所在的对象。
|
||||
(1)箭头函数没有自己的`this`对象(详见下文)。
|
||||
|
||||
(2)不可以当作构造函数,也就是说,不可以使用`new`命令,否则会抛出一个错误。
|
||||
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用`new`命令,否则会抛出一个错误。
|
||||
|
||||
(3)不可以使用`arguments`对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
|
||||
|
||||
(4)不可以使用`yield`命令,因此箭头函数不能用作 Generator 函数。
|
||||
|
||||
上面四点中,第一点尤其值得注意。`this`对象的指向是可变的,但是在箭头函数中,它是固定的。
|
||||
上面四点中,最重要的是第一点。对于普通函数来说,内部的`this`代表函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的`this`对象,内部的`this`就是一个普通变量,指向定义时上层函数所在的对象。也就是说,箭头函数内部的`this`指向是固定的,相比之下,普通函数的`this`指向是可变的。
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
@ -733,7 +733,7 @@ foo.call({ id: 42 });
|
||||
|
||||
上面代码中,`setTimeout()`的参数是一个箭头函数,这个箭头函数的定义生效是在`foo`函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时`this`应该指向全局对象`window`,这时应该输出`21`。但是,箭头函数导致`this`总是指向函数定义生效时所在的对象(本例是`{id: 42}`),所以打印出来的是`42`。
|
||||
|
||||
箭头函数可以让`setTimeout`里面的`this`,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子。
|
||||
下面例子是回调函数分别为箭头函数和普通函数,对比它们内部的`this`指向。
|
||||
|
||||
```javascript
|
||||
function Timer() {
|
||||
@ -757,7 +757,7 @@ setTimeout(() => console.log('s2: ', timer.s2), 3100);
|
||||
|
||||
上面代码中,`Timer`函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的`this`绑定定义时所在的作用域(即`Timer`函数),后者的`this`指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,`timer.s1`被更新了 3 次,而`timer.s2`一次都没更新。
|
||||
|
||||
箭头函数可以让`this`指向固定化,这种特性很有利于封装回调函数。下面是一个例子,DOM 事件的回调函数封装在一个对象里面。
|
||||
箭头函数实际上可以让`this`指向固定化,绑定`this`使得它不再可变,这种特性很有利于封装回调函数。下面是一个例子,DOM 事件的回调函数封装在一个对象里面。
|
||||
|
||||
```javascript
|
||||
var handler = {
|
||||
@ -774,11 +774,11 @@ var handler = {
|
||||
};
|
||||
```
|
||||
|
||||
上面代码的`init`方法中,使用了箭头函数,这导致这个箭头函数里面的`this`,总是指向`handler`对象。否则,回调函数运行时,`this.doSomething`这一行会报错,因为此时`this`指向`document`对象。
|
||||
上面代码的`init()`方法中,使用了箭头函数,这导致这个箭头函数里面的`this`,总是指向`handler`对象。如果回调函数是普通函数,那么运行`this.doSomething()`这一行会报错,因为此时`this`指向`document`对象。
|
||||
|
||||
`this`指向的固定化,并不是因为箭头函数内部有绑定`this`的机制,实际原因是箭头函数根本没有自己的`this`,导致内部的`this`就是外层代码块的`this`。正是因为它没有`this`,所以也就不能用作构造函数。
|
||||
总之,箭头函数根本没有自己的`this`,导致内部的`this`就是外层代码块的`this`。正是因为它没有`this`,所以也就不能用作构造函数。
|
||||
|
||||
所以,箭头函数转成 ES5 的代码如下。
|
||||
下面是 Babel 转箭头函数产生的 ES5 代码,就能清楚地说明`this`的指向。
|
||||
|
||||
```javascript
|
||||
// ES6
|
||||
@ -800,7 +800,7 @@ function foo() {
|
||||
|
||||
上面代码中,转换后的 ES5 版本清楚地说明了,箭头函数里面根本没有自己的`this`,而是引用外层的`this`。
|
||||
|
||||
请问下面的代码之中有几个`this`?
|
||||
请问下面的代码之中,`this`的指向有几个?
|
||||
|
||||
```javascript
|
||||
function foo() {
|
||||
@ -820,7 +820,7 @@ var t2 = f().call({id: 3})(); // id: 1
|
||||
var t3 = f()().call({id: 4}); // id: 1
|
||||
```
|
||||
|
||||
上面代码之中,只有一个`this`,就是函数`foo`的`this`,所以`t1`、`t2`、`t3`都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的`this`,它们的`this`其实都是最外层`foo`函数的`this`。
|
||||
答案是`this`的指向只有一个,就是函数`foo`的`this`,这是因为所有的内层函数都是箭头函数,都没有自己的`this`,它们的`this`其实都是最外层`foo`函数的`this`。所以不管怎么嵌套,`t1`、`t2`、`t3`都输出同样的结果。如果这个例子的所有内层函数都写成普通函数,那么每个函数的`this`都指向运行时所在的不同对象。
|
||||
|
||||
除了`this`,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:`arguments`、`super`、`new.target`。
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user