From 71af30def18573f73e6d75df7c288cabd2ce04e0 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Wed, 12 May 2021 01:07:14 +0800 Subject: [PATCH] =?UTF-8?q?docs(function):=20fixed=20=E7=AE=AD=E5=A4=B4?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=9A=84this=20#1050?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/function.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/function.md b/docs/function.md index 792a458..a826c88 100644 --- a/docs/function.md +++ b/docs/function.md @@ -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`。