在他的(伟大的)系列书籍中“You don't know JS" ,凯尔·辛普森 (Kyle Simpson) 指出动态作用域和这种
机制是“近亲”,他还说:
"the
this
mechanism is kind of like dynamic scope." (YDKJS, Scope and Closure, Appendix A)
是什么阻止他说这个
是简单明了的动态作用域?
此外,在《 this & Object Prototypes 》一书中,也是 YDKJS 系列的一部分,据我所知,Kyle 在讨论this< 时并没有提到一次动态作用域
正在工作,所以我有点惊讶为什么他决定不进一步进行类比......有人知道为什么吗?
谢谢
最佳答案
我 claim 的原因this
只是“有点像”动态作用域,实际上并不是动态作用域,它基于以下两个观察结果:
使用对象引用 (
this.foo = 1
) 显式访问“范围上下文”的美感不同于通过词法变量引用 (foo = 1
) 隐式访问它。充其量,这使得两个系统的“范围”是平行的,而不是相同的。但实际情况与表面看起来有更多不同!但更重要的是,动态作用域传统上被定义为基于调用堆栈的作用域链。也就是说,在动态作用域中,要按顺序查询哪些“作用域上下文”的决定正是当前的函数调用堆栈。但是
this
本身并不基于调用堆栈,而只是基于堆栈中最近调用的方式。考虑这种情况:
foo()
来电bar()
,bar()
来电baz()
,以及baz()
引用x
baz()
中 undefined variable .在词法范围内,查找将是
baz()
,那么无论baz()
的外部范围是什么是,等等。bar()
和foo()
根本不会被查询,除非它们碰巧是baz()
的词法周围范围。 .在动态范围内,调用堆栈
foo()
->bar()
->baz()
是作用域链,所以baz()
咨询后,则bar()
,然后foo()
,无论这 3 个函数按词法存在于代码库中的哪个位置。现在,考虑相同的场景,但是
this.x
是baz()
里面的引用。调用堆栈foo()
->bar()
->baz()
与解决this.x
并不特别相关。相反,唯一重要的是如何baz()
被调用。如果调用站点是baz()
,“默认绑定(bind)”规则适用。如果是this.baz()
,“隐式绑定(bind)”规则适用。如果是baz.call(..)
,“显式绑定(bind)”规则适用。如果是new baz()
,适用“新绑定(bind)”规则。就是这样。
实际上,这不是唯一的事情,这只是做出的第一个决定。一旦确定了哪个对象(又名范围上下文对象)
this
指出,现在唯一重要的是该对象的原型(prototype)链,因为这是将按照原型(prototype)链链接的顺序查询的“范围”。
摘要:
在词法作用域中,定义函数的位置是唯一确定使用哪些上下文以及以什么顺序来解析变量引用的因素。
在动态作用域中,调用自的函数是唯一确定使用哪些上下文以及以什么顺序解析变量引用的因素。
里>在
this
基于上下文,函数的定义位置和调用位置都不相关。因此,this
既不是词法作用域也不是动态作用域。这里唯一重要的是如何调用调用堆栈(堆栈顶部)中的当前函数。嗯,这是确定从哪个作用域链开始查找的唯一重要因素。但是,一旦确定了该对象,现在就由该对象的原型(prototype)链完全定义范围解析。
关于javascript - Kyle Simpson 的 YDKJS 中的动态范围和 `this`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44748400/