Open findxc opened 3 years ago
你不知道的JavaScript(上卷) - 图书 - 豆瓣 这本书对词法作用域和 this 写得挺详细的。
this
要知道 this 取值,首先要先理解词法作用域,因为对于箭头函数, this 值是取决于词法作用域的,而对于其它函数 this 值则取决于调用方式。
注意,以下例子均不考虑使用 eval 和 with 的场景,也不考虑严格模式。
eval
with
可以理解为静态的、固定的,作用域在书写代码时就已经被确定了。
name = 'xc_1' // ② function log() { console.log(name) // ① } function run() { const name = 'xc_2' log() } run()
在 ① 处 name 这个变量在函数 log 内未定义,所以会往外层作用域去找,然后找到 ② 处定义的 name 。
name
log
这个是只和代码书写有关的。接下来无论函数 log 在哪里被调用以及如何被调用,最终的打印值都会是 xc_1 。
xc_1
值为词法作用域中箭头函数所在位置的 this 。
// ② const log = () => { console.log('this: ', this) // ① } log() const obj = { name: 'xc' } log.bind(obj)()
① 处的 this 是 ② 处的 this 值,就是 Window 。
Window
为什么 bind 没有改变 this 的值呢,因为这个 this 是词法作用域决定的,书写代码的时候,作用域就已经固定了,后续无法改变。
bind
function wrapper() { // ② const log = () => { console.log('this: ', this) // ① } return log } wrapper()() const obj = { name: 'xc', wrapper, } obj.wrapper()() wrapper.bind(obj)()()
① 处的 this 是 ② 处的 this 值,而 ② 处的 this 值取决于函数 wrapper 被如何调用。
wrapper
可以用 Babel 来帮助理解箭头函数中的 this ,见下图。var _this = this 这种写法也是箭头函数这个语法出来之前很常见的一种写法。
var _this = this
在调用时 this 值是动态绑定的, this 值取决于调用方式,千万不要再去想词法作用域。
判断时按照以下顺序去判断即可。
先看有没有显示绑定,如果有显示绑定 this 就是显示绑定的那个对象。显示绑定指 bind 、 call 和 apply 。
call
apply
function log() { console.log('this: ', this) } const obj = { name: 'xc' } log.bind(obj)()
没有显示绑定的话再看有没有隐式绑定,如果有的话就是隐式绑定的那个对象。隐式绑定指 a.b() 的方式来执行函数 b 。隐式绑定的话只用关心最近的那个调用对象。
a.b()
b
function log() { console.log('this: ', this) } const obj = { name: 'xc_1', log, inner: { name: 'xc_2', log, }, } obj.log() obj.inner.log()
如果隐式绑定也没有,也就是函数是直接调用的,就是指向 Window 。
function log() { console.log('this: ', this) } function wrapper() { log() } wrapper()
function log() { console.log('this: ', this) } const obj = { name: 'xc', log, } obj.log() // 比如下面这两种奇奇怪怪的 ;(false || obj.log)() ;(obj.log = obj.log)()
可以参见 JavaScript深入之从ECMAScript规范解读this · Issue #7 · mqyqingfeng/Blog · GitHub 和 根治JavaScript中的this-ECMAScript规范解读 | leon的后花园 去读读规范。
补充一个有很多举例的文章:JavaScript: What is the meaning of this?
你不知道的JavaScript(上卷) - 图书 - 豆瓣 这本书对词法作用域和
this
写得挺详细的。要知道
this
取值,首先要先理解词法作用域,因为对于箭头函数,this
值是取决于词法作用域的,而对于其它函数this
值则取决于调用方式。注意,以下例子均不考虑使用
eval
和with
的场景,也不考虑严格模式。词法作用域
可以理解为静态的、固定的,作用域在书写代码时就已经被确定了。
在 ① 处
name
这个变量在函数log
内未定义,所以会往外层作用域去找,然后找到 ② 处定义的name
。这个是只和代码书写有关的。接下来无论函数
log
在哪里被调用以及如何被调用,最终的打印值都会是xc_1
。箭头函数中的 this 值
值为词法作用域中箭头函数所在位置的 this 。
① 处的
this
是 ② 处的this
值,就是Window
。为什么
bind
没有改变this
的值呢,因为这个this
是词法作用域决定的,书写代码的时候,作用域就已经固定了,后续无法改变。① 处的
this
是 ② 处的this
值,而 ② 处的this
值取决于函数wrapper
被如何调用。可以用 Babel 来帮助理解箭头函数中的
this
,见下图。var _this = this
这种写法也是箭头函数这个语法出来之前很常见的一种写法。非箭头函数的 this 值
在调用时
this
值是动态绑定的,this
值取决于调用方式,千万不要再去想词法作用域。判断时按照以下顺序去判断即可。
先看有没有显示绑定,如果有显示绑定
this
就是显示绑定的那个对象。显示绑定指bind
、call
和apply
。没有显示绑定的话再看有没有隐式绑定,如果有的话就是隐式绑定的那个对象。隐式绑定指
a.b()
的方式来执行函数b
。隐式绑定的话只用关心最近的那个调用对象。如果隐式绑定也没有,也就是函数是直接调用的,就是指向
Window
。如果还想知道更多
可以参见 JavaScript深入之从ECMAScript规范解读this · Issue #7 · mqyqingfeng/Blog · GitHub 和 根治JavaScript中的this-ECMAScript规范解读 | leon的后花园 去读读规范。