|
我注意到this网站上似乎没有明确解释关键词是什么,它是如何解释的 JavaScript 正确使用(和错误)。; z" k+ V6 @! v& x- s. B& J
我目睹了它的一些非常奇怪的行为,不明白它为什么会发生。
: R# T0 _) A( ~如何this什么时候工作应该用?8 R9 T: H1 q8 g( u6 R$ B) S
; V1 L6 P- D7 ~- I- U1 k) k* O1 H
解决方案: / q# y$ j% |5 P/ L0 M. o- C6 h
this是 JavaScript 中的关键字是执行上下文的属性。其主要用途是函数和构造函数。. U; }( t* \2 [5 l, x! Q% B
我建议先读Mike West的文章JavaScript 作用域(存档)。这是对的thisJavaScript 优秀友好地介绍了作用域链和作用域链的概念。this很简单(如果你坚持最好的练习)。. ?% ] m% C, m- C
this规范中的技术说明的ECMAScript标准定义this抽象操作(缩写)AO)ResolveThisBinding:7 d( @+ c. ^) r7 H. s
[AO] ResolveThisBinding […]this上下文使用正在运行的 LexicalEnvironment 确定关键词的绑定。[步骤]:* K5 i- o2 h6 w& Q
[ol]令envRec为GetThisEnvironment ()。
0 H1 F" a: L: p, K, k$ P返回 ?envRec .GetThisBinding()。[/ol]全球环境记录、模块环境记录和函数环境记录都有自己的 GetThisBinding 方法。
/ s# C& P! N6 F所述GetThisEnvironment AO找到目前正在运行的上下文执行情况LexicalEnvironment和查找最接近方兴未艾环境记录(通过迭代地访问他们的[[OuterEnv]]特性),它有这种结合(即HasThisBinding返回真)。这一过程以三种环境记录类型之一结束。
! g' n; C" M' P/ G的值this这通常取决于代码是否严格。
, Q( M& R0 ?" f2 c1 EGetThisBinding 反映了返回值this目前执行上下文的值,所以无论何时建立新的执行上下文,都会this分析是一个不同的值。这也可能发生在修改当前执行的上下文时。以下部分列出了可能发生的五种情况。, t# u. n) i( T H5 H
您可以在代码示例中放置代码示例AST 资源管理器遵循规范的详细信息。) s6 n7 f7 [3 Q0 K! J9 a' I8 f
1. 脚本中的全局执行上下文这是顶层评估的脚本代码,比如直接在 a 中[/code]在上下文中对脚本的初始全局进行评估时this会导致GetThisBinding采取以下步骤:
( ~; A0 z/ L1 m' B全局环境记录envRec […] GetThisBinding 具体方法:
( t. _; C+ e, D[ol]返回envRec .[[GlobalThisValue]]。[/ol]全局环境记录[[GlobalThisValue]] 属性总是设置为主机定义的全局对象,可以通过globalThis(window在 Web 上,global在 Node.js 上;MDN访问文档)访问对象。InitializeHostDefinedRealm了解 的步骤[[GlobalThisValue]] 属性是如何形成的。
! {, x& m. Y. z0 k2.模块中的全局执行如下模块已在 ECMAScript 引入2015 。
, t: d4 b% h; ]6 s) y2 q这适用于模块,如直接在 a 内部时,而不是简单.
6 A1 D) B: Y4 P6 D3 r在模块的初始全局实施中,求值this会导致GetThisBinding采取以下步骤:; z, J# e7 E% G$ R1 g
记录模块环境GetThisBinding 具体方法 […] [这样做]:
. D+ W& L6 _, U L8 [( ]) e x[ol]返回undefined。[/ol]在模块中,值this总是undefined全局上下文。模块隐式严格。% Z9 n! R+ |2 y* U" T
3. 输入评估码有两种eval调用:直接调用和间接调用。这种区别自 ECMAScript 第 5 版存在。) ]% N! Q0 A: D5 h4 _' N2 \
直接eval调用通常看起来像eval(……);或(eval)(…… );(或((eval))(……);等等。直接的。2
0 @" H. S* B/ z5 }$ e- c间接eval调用涉及eval以任何其他方式调用函数引用。这可能是eval?.(… ),(… ,eval)(… ),window.eval(… ),eval.call(… ,…)等。考虑const aliasEval1 = eval; window.aliasEval2 = eval;,它也将是aliasEval1(… ),aliasEval2(… )。另外,给定const originalEval = eval; window.eval = (x) => originalEval(x);,调用eval(…)也会间接。请参阅chuckj 对“) JavaScript 中的](1,eval)(‘this’) vs eval(‘this’)”的回答?和Dmitry Soshnikov 的 ECMA-262-5 详细信息-第 2 章:严格模式(已存档),知道何时间接使用eval()调用。+ J9 h4 z7 ?; O/ }1 d1 f
PerformEval执行eval代码。它创建了一个新的声明环境记录作为 LexicalEnvironment,这是GetThisEnvironment 从中获取this值的地方。
5 {5 J# m6 ^* E k0 B f v然后,如果this出现在eval环境记录在代码中GetThisBinding方法发现GetThisEnvironment它被称为返回值。
" r! _( g6 Y) S z N+ K3 G; O% v声明环境记录的创建取决于eval调用是直接还是间接:7 Q& h( H3 N d* j3 Y. a4 ]
在直接 eval 中,它将基于当前操作的上下文LexicalEnvironment。# y7 N+ M# H3 W5 q& j1 z- _7 q
在间接评估中,它将记录在基于间接评估的领域[[GlobalEnv]] 属性(全局环境记录)。意思是:
% d+ i1 S9 _4 ]在直接 eval 中,this值不会改变;它自称是eval.
* q( r/ z% v$ s, v+ H' R, K# K在间接 eval 中,this ( )globalThis)。怎么样new Function??—?new Function类似于eval,但它不会立即调用代码;它创建了一个函数。本除非函数被调用,否则任何地方都不适用于装订,如下一节解释其正常工作。
W7 J& X8 S$ a! w7 @4. 输入功能码调用输入函数代码将出现在函数中。; b2 {0 H5 s+ b+ Q) @* s C& ]2 j
调用函数有四种语法。5 z" u* Y! k. o8 I" ^2 k* [9 s Q+ U
该EvaluateCall
; {3 {3 J3 e5 nAO这三种执行:
9 [/ d5 P$ u1 x6 X# p9 o u9 l3+ x5 u) ~- Y* P) a1 v4 O. a( F
调用普通函数& f$ A {, |" D9 V3 F' n; f; J
可选链接调用
/ y/ ^. q* T: N+ c c M标记模板
" ~- x. H3 B9 h f5 o! ~5 Y% M* c并为此执行+ D$ T" ?; G; g* ?9 `. r
EvaluateNew
6 v- j0 C) ?- Q( Y4 r/ x" X:
% q0 K" X$ h: s& N4 q$ w5 g3
' U2 K6 e- c9 S# J调用结构函数实际函数调用发生在Call AO 处,调用时使用根据上下文确定的thisValue;该参数在与调用相关的长串调用中传递。Call调用函数的[[Call]]内槽。这将被调用PrepareForOrdinaryCall,创建了新的函数环境记录:
2 e- w* q- t9 |; `甲功能环境记录如果函数不是,则声明环境记录用于表示功能的顶层范围和ArrowFunction,提供了一种this如果函数不是ArrowFunction函数并引用super,还包括函数环境记录super调用函数内部执行方法的状态。
5 a4 u3 \% p6 R8 [7 z+ e! q- V另外,在函数 Environment Record 中有 [[ThisValue]] 字段:3 G- [8 K5 G5 J2 e9 @6 f o
这是this用于此函数调用的值。/ Y8 Y$ }, t1 f# x4 j, I
该NewFunctionEnvironment通话还设置了功能环境[[ThisBindingStatus]]属性。4 z2 L( R9 x" w, z
[[Call]]还调用OrdinaryCallBindThis,其中适当的thisArgument基于以下因素:
+ v5 G l8 W! U原始参考,
B" m6 O" I3 _- u函数的类型,以及
1 P4 Y9 l- ^" R. _7 |; H& H. y代码是否严格。一旦确定,新创建的函数 Environment Record的BindThisValue实际上,方法的最终调用会 [[ThisValue]] 字段设置为thisArgument。1 _+ }7 T1 R4 C @" ~& H
最后,这个字段是函数 Environment Record 的 GetThisBinding AOthis从以下位置获取值: _' M0 f6 X% g" b( S! v
函数 Environment Record envRec […] GetThisBinding 具体方法:
: l! I' W; c! d2 d4 @[…]/ }+ u; c& |' Z+ o; P
\3. 返回envRec .[[ThisValue]]。
9 w3 L7 V) z) q4 r1 D# u" O同样,该确定值的方法取决于许多因素;这只是一个总体概述。有了这个技术背景,让我们检查一下所有具体的例子。
' |# l) V4 X/ s- ?箭头函数在评估箭头函数时,函数对象 [[ThisMode]] 内部槽在OrdinaryFunctionCreate 中设置为“词法”。! `/ R( C' C6 x6 r h
在OrdinaryCallBindThis,它接受函数F:
5 I9 q9 C$ S Y) l[ol]令thisMode为F .[[ThisMode]]。
3 b) k" s g3 P+ `如果thisMode是词法的,则返回 NormalCompletion( undefined)。[…][/ol]这只意味着跳过绑定this的算法的其余部分。箭头函数不绑定自己的this值。- i# [! ~- W! ~+ [* ~: j
那么,this箭头函数内部是什么?ResolveThisBinding和GetThisEnvironment,HasThisBinding 方法显式返回false。: g& n4 M8 T4 F2 Q1 c( y
HasThisBinding 函数的具体方法 Environment Record envRec […] [这样做]:
7 T) J8 ^" y! ]8 n[ol]如果envRec .[[ThisBindingStatus]] 是lexical,则返回false;否则,返回true。[/ol]因此,外部环境被迭代地发现。这个过程将有this三个环境之一的绑定结束了。) {" G7 |, E5 u5 e M, E
这只是意味着,在箭头函数体中,this箭头函数的词法范围,或者换句话说(箭头函数和函数声明/表达式:它们等效/可交换吗?
: r+ e& t* Q: l: _" L" X2 x箭头函数没有自己的this[…] 绑定。相反,[此标识符]在词法范围内像任何其他变量一样进行分析。这意味着在箭头函数中,this[引用] 到定义this在箭头函数的环境中[值] (即箭头函数的外部)。
1 ]& t) S8 ^/ V9 l; b功能属性在正常功能(function,方法),this来确定如何调用所述函数?。
4 d/ d& U& P6 K+ i2 f8 g这些语法变体派上用场。& P) n- v$ K6 f- G. J7 Z
考虑包含函数的对象:
( m0 C u5 q. b+ L% r& ~" Y: }8 a/ J# J4 d* E
- const refObj = func: function(){ console.log(this); } }code]或者:
0 X- C1 [1 O6 `4 f5 h9 s - [code]const refObj = func(){ console.log(this); } }code]在以下任何函数调用中,this里面的值func都是refObj. 1
( L* ~# @( H# a- S+ m - : K8 K2 f! m1 a* H4 Y
- refObj.func()) b U, ^" D4 J
- refObj["func"]()
' d; w( c: Y r# Z% K - refObj?.func()
& z5 \# f3 v+ b4 G$ C- L8 p+ d - refObj.func?.()# `) ^% P, ]0 t* x
- `refObj.func```
如果被调用的函数在语法上是一个基对象的属性,那么这个基将是调用的“引用”,在通常情况下,它是 的值this。解释了上述链接的评估步骤;例如,在refObj.func()(或refObj["func"]())中,CallMemberExpression是整个表达式refObj.func(),它由MemberExpression refObj.func和Arguments 组成 ()。: x9 x _/ j. r
- 而且,refObj.func并refObj扮演三个角色,每个角色:
, c/ p+ Y: k1 K
- N, P! m8 K2 k- 都是表达,' ]' ]) ~2 n, L
- 而且都是参考
% p+ a/ m' H! S( a# G" `% m1 I - 都是价值观。
refObj.func作为值可调函数对象;相应的参考用于确定this绑定。/ W% G4 T2 G: q5 F
- 可选链接的工作方式与标记模板示例非常相似:基本上,引用是在?.(), 之前```或 以前的所有内容()`。0 m% F5 Q/ H5 O9 g( u$ A# B/ }/ r+ ^
- EvaluateCall使用此引用IsPropertyReference确定它是否是语法上的对象属性。它试图获得引用 [[Base]] 属性(例如refObj,当应用于refObj.func; 或foo.bar应用于 时foo.bar.baz)。假如把它写成属性,那么GetThisValue将获取此 [[Base]] 属性并将其用作此值。
5 P- P \9 ?9 E5 F8 a/ U - 注意:关于.getter/setter 的工作方式和方法相同this。例如,简单的属性不会影响上下文的执行this在全局范围内:0 c) {8 J! A2 W% e8 D8 b5 a) ]
- [code]const o = { a: 1, b: this.a,// Is `globalThis.a`. [this.a]: 2 // Refers to `globalThis.a`. }code]没有基本引用,模式严格, with没有基引的调用通常是不作为属性调用的函数。[code]func(); // As opposed to `refObj.func();`.
) P# Y7 u0 `$ ~$ J# t0 ^ 这种情况也发生在传输或分配方法或使用逗号操作符时。这是参考记录和值之间的差异。4 n, ?( o+ s& K/ @
const g = (f) => f(); // No base ref.const h = refObj.func;g(refObj.func);h(); // No base ref.(0,refObj.func)(); // Another common pattern to remove the base ref.
Z/ ~) G, }& w EvaluateCall电话呼叫与thisValue的不确定这里。这在OrdinaryCallBindThis(F:函数对象;thisArgument:传递给Call的thisValue)不同:+ G' ^+ k( w) B/ G8 |/ N, b3 \
[ol]令thisMode为F .[[ThisMode]]。[/ol][…], G8 q7 E+ G: }6 o9 S0 ^$ Y
[ol]如果thisMode是严格的,则让thisValue为thisArgument。) f, W+ }3 E* z. r1 p$ `& q5 |
别的,8 X, E6 i4 A! G3 y# N) d6 Y, E6 g
如果
$ ?, G6 U. O* YthisArgument# t4 b3 P) H; Y0 V1 T4 N
为
3 K2 y* j, Y& Xundefined
' m! j$ N1 |) ~4 I% R4 {2 f( z8 M. H或" v2 N4 A) e( H& U& D! H
null
6 N& z0 z3 D% g: l. V* c,则
( z) {7 n( X! _5 F1 C+ y* W* p( q[ol]令globalEnv为calleeRealm .[[GlobalEnv]]。
0 ~, V; u( d3 |" N) o _+ E[…]
; M1 r1 f* h- Q7 q- J' V6 D令thisValue为globalEnv .[[GlobalThisValue]]。[/ol]
8 i- g. @! P7 ~7 g$ P' y' i别的,
! G" M1 L2 g& i; {[ol]让thisValue成为!ToObject (thisArgument)。
; m" R8 M4 O$ o" A% N3 Y* G. l O注意:ToObject生成包装对象 […]。[/ol][/ol][…]
* L7 R) N4 k/ ^1 q1 L注:第 5 步在严格模式下设置 的实际值this为提供的thisArgument -?undefined在这种情况下。在草率模式中,模式thisArgument导致this成为全局this值。
' m# \2 q8 A) [1 q$ y( L5 N如果IsPropertyReference返回false,则EvaluateCall采取以下步骤:
4 ^: n: m. E9 s& `[ol]让refEnv为ref .[[Base]]。2 |4 u1 Q% ~- c
断言:refEnv是环境记录。
# i0 [+ x- X: q; _! c ^; ~& t: {让thisValue为refEnv .WithBaseObject()。[/ol]这是未定义的thisValue可能来自:refEnv。WithBaseObject()总是不确定的,除了在with声明。在这种情况下,thisValue将是绑定对象。
( I) D3 o& C( r0 f还有Symbol.unscopables(MDN控制 文档)with绑定行为。2 F! J' \5 ?0 \5 B3 n
综上所述,到目前为止:$ }' o! s/ F8 s$ S1 s$ ?
function f1(){ console.log(this);}function f2(){ console.log(this);}function f3(){ console.log(this);}const o = f1, f2, [symbol.unscopables]: f2: true f(); / Logs `globalThis`.with(o){ f(); / Logs `o`. f(); / `f2` is unscopable,so this logs `globalThis`. f(); / `f3` is not on `o`,so this logs `globalThis`.}
5 Z) s+ F) I7 C& [ ?4 I 和:7 K. X0 L& E0 n$ M# `
"use strict";function f(){ console.log(this);}f(); // Logs `undefined`.// `with` statements are not allowed in strict-mode code.
9 \5 c: ?1 t( m1 B0 ~3 n5 |, `. @ 评估时应注意this,它并不重要*,其中*函数定义正常。
6 e5 q3 l; B: G! g1 A$ h5 p.call,.apply,.bind,thisArg和原语OrdinaryCallBindThis第 5 步和第 6步.2 步(规范中的 6.b)另一的另一个结果是,仅在草率模式下才将原始this值强制转换为对象。: ~- L" N. ^7 ^* X" {. H4 X8 V
为了检查这一点,让我们this价值引入的另一个来源覆盖this三种绑定方法:4! Q; o3 J' `# e/ o
Function.prototype.apply(thisArg,argArray)
* D$ T) Q/ z; U! kFunction.prototype.{ call,bind}(thisArg,...args).bind创建绑定函数this绑定设置为thisArg而且不能再改了。.call并.apply立即调用函数并将其调用this绑定设置为thisArg。
" s5 q8 s [& G& A$ k6 p.call`并使用指定的*thisArg*`.apply`直接映射到[Call](https://tc39.es/ecma262/#sec-call)。使用[BoundFunctionCreate](https://tc39.es/ecma262/#sec-boundfunctioncreate)创建绑定函数。*自己的*[[[Call\]] 方法](https://tc39.es/ecma262/#sec-bound-function-exotic-objects-call-thisargument-argumentslist), 用于搜索函数对象[[BoundThis]] 内部插槽。`.bind设置自定义this值的示例:: |; _) C, P5 k* F
function f(){ console.log(this);}const myObj = {}, g = f.bind(myObj), h = (m) => m();// All of these log `myObj`.g();f.bind(myObj)();f.call(myObj);h(g);0 ^+ K0 y+ ]' v$ o5 h. B0 l
在严格模式和非严格模式下,对象是一样的。* l, T- j# C! x) b4 [" J
试着提供一个原始值:
% R$ O- x* w. D& E, d. Yfunction f(){ console.log(this);}const myString = "s", g = f.bind(myString);g();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Logs `String { "s" }`.f.call(myString); // Logs `String { "s" }`.3 o. \! @9 B* B9 v' W
在非严格模式下,原语被迫转换为其对象包装形式。它正在调用你Object("s")or获得相同类型的对象new String("s")。在严格的模式下,你可以使用原语:. j4 ?* w5 i. `8 k$ P/ {* R
"use strict";function f(){ console.log(this);}const myString = "s", g = f.bind(myString);g();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Logs `"s"`.f.call(myString); // Logs `"s"`.
! f- M6 f! F5 c* D% t* I+ ^ 如 jQuery 设置 this 在这里选择DOM 元素:
9 R& M6 i _/ O2 \" b6 L$("button").click(function(){ console.log(this); // Logs the clicked button.});
$ B+ }( ]& f% u8 o$ L+ X8 J9 r 构造函数,类和new当使用new当运算符调用函数作为构造函数时,EvaluateNew调用Construct,后者调用[[Construct]] 方法。如果函数是基本结构(即,不是class extends… {… },它的设置thisArgument从构造函数的原型创建新对象。this构造函数中设置的属性最终会出现在生成的实例对象上。this隐式返回,除非你显式返回自己的非原始值。
# d0 A. o( j$ }. X8 I0 ZAclass在 ECMAScript 引入2015 。
: p' \9 C: Q5 g0 x$ Tfunction Old(a){ this.p = a;}const o = new Old(1);console.log(o); // Logs `Old { p: 1 }`.class New{ constructor(a){ this.p = a; }}const n = new New(1);console.log(n); // Logs `New { p: 1 }`.
! \/ T& g. Q! C6 p( S) g' C 严格模式中隐含类定义:2 f2 _% n0 }! s* i* F
class A{ m(){ return this; } m(){ const m1 = this.m1. console.log(m();new A().m(); / Logs `undefined`.
" ` _1 [0 c( P# o! D super行为的例外new是class extends… {… },如上所述。调用时不会立即设置衍生类this值;他们只在super调用后这样做(在没有自己的情况下隐式发生constructor)。使用this呼叫之前super不允许。
: y" }7 J% a7 C+ s调用使用super调用词法范围(函数环境记录)this值调用超级结构函数。GetThisValue有一个特别的super调用规则。使用它BindThisValue设置this记录环境。1 L( ]5 v/ ^, _- I- t9 }
class DerivedNew extends New{ constructor(a,a(2){ / )Using `this` before `super` results in a ReferenceError. super(a); this.p2 = a2; }}const n2 = new DerivedNew(1,2);console.log(n二、 / Logs `DerivedNew { p: 1,p2: 2 }`.
9 J: K, @* g- k ?: |% ?. G 5. 评价字段ECMAScript实例字段和静态字段引入 2022 。
1 q2 ^# A+ `# ]1 l) ^/ Q8 j' X当class评估 a 时,执行ClassDefinitionEvaluation,修改正在运行的上下文。对于每个人ClassElement:
* B* \9 ?8 t% D9 e若字段静态,则this指类本身,
& `4 V. C1 z |& J" j* N若字段不静态,则this引用实例。私有字段(例如#x)添加到 的方法PrivateEnvironment。
4 ^9 r& i+ }5 B0 g目前静态块是TC39 第 3 阶段提案。静态块的工作方式与静态字段和方法相同:this它们内部是指类本身。% t) r+ n4 v% K4 @2 G
方法和 请注意getter/setter 中,this就像在普通函数属性中一样工作。
" N% W, a% i" _2 ?class Demo{ a = this; b(){ return this; } static c = this; static d(){ return this; / Getters,setters,private modifiers are also possible.}const demo = new Demo;console.log(demo.a,demo.b(); / Both log `demo`.console.log(Demo.c,Demo.d(); / Both log `Demo`.9 h! M! C' O% I' E
1 o.f)()相当于o.f(); (f)()相当于f()。这篇文章 2ality 文章存档)解释。特别是查看ParenthesizedExpression如何计算。
2 h! j0 ^ K- ]8 P, r' W4 B* U2:它必须是MemberExpression,不能是属性,必须有 [[ReferencedName]] 正好是“eval”,必须是 %eval% 内在对象。3 H5 Z: m" c9 g/ F2 ~
三、每当规范说“让ref成为对X求值的结果。”,那么X是一些表达式,你需要找到求值步骤。例如,评估MemberExpression或CallExpression结果是这些算法之一。其中一些导致参考记录。
8 A; q# w- x* `- J( a' D3 N4:还允许提供其他本地和主机方法这个值,特别是Array.prototype.map,Array.prototype.forEach等接受一个thisArg作为他们的第二个参数。任何人都可以用自己的方法来改变this一样(func,thisArg) => func.bind(thisArg),(func,thisArg) => func.call(thisArg)像往常一样,MDN提供巨大的文档。
. A4 P6 ]; E5 U" E只是为了好玩,用一些例子来测试你的理解回答每个代码片段的问题:“this标记行的值是多少?为什么? .9 R3 V4 {1 ` Z+ q- U" d) q
单击灰色框以显示答案。" x+ V/ N& t: {( r5 |! O) h. D) z
[ol]js if(true){ console.log(this); // What is `this` here? }[/ol]``
+ W& r: A/ c0 h T[ol][/ol]```js* U! @/ `* E7 q l8 v4 r" P& ] i
const obj = {};2 Z$ H( t# F' U$ n
function myFun(){
4 P+ ^6 s2 C4 W# F return { // What is this here?
/ S+ e6 n1 D! ]2 Z' J+ H! b# L “is obj”: this === obj,
! m* K. }8 A# E: k- g “is globalThis”: this === globalThis
# Q9 }1 F+ w1 u/ a5 l" ~& [1 W4 h4 K3 s ;
1 ]2 e& q# m. X, L }( S1 \4 B/ M7 R
obj.method = myFun;5 L* D/ C: b/ G. v
console.log(obj.method());- H7 P0 E& \2 e( x& D0 W2 J
```: M( [- @& T! ~, d9 K* e. G
Run code snippetExpand snippet4 t7 ^ W& B5 Y7 ]/ t9 s+ Q
``````# P( J& i# O6 s% F
[ol][/ol]``js const obj = { myMethod: function()()()(){ return { // What isthis` here?1 ]6 n9 r+ C+ V
“is obj”: this === obj,
$ o V+ @+ L- k “is globalThis”: this === globalThis8 Z5 |# _+ q. f, i; V
: B9 Z0 r6 x: h p* G9 P 3 {8 t0 Q ^4 N% f3 G
. ?9 x+ `) a7 Q: f# ]
myFun = obj.myMethod;
% t- p0 q$ t* K# wconsole.log(myFun());
T( ]. I+ e0 w5 n```
Q( F; p( J1 G b' RRun code snippetExpand snippet1 H: f$ p# R- I6 }. x8 S4 d4 s# q$ x
``````````
( x0 R1 O. P g8 g$ d& l6 F: g[ol][/ol]``js const obj = myFun: () => ({ / What isthis` here?; k( H0 _2 b1 a2 a. k& `
“is obj”: this === obj,0 m# }% M& i; z2 e. K' j" x/ Q, z- G" @
“is globalThis”: this === globalThis- D# X& x! U: s" b1 [
7 _1 m9 I: D3 X1 Y, M ;. J* ?; b) A. {5 B
console.log(obj.myFun());6 V) R" Y5 F/ X8 l5 T& r
```
* C. Y+ d: X, b, \- v: ARun code snippetExpand snippet% k' z- `6 o( q& B0 c5 f) C
`````` Q- R+ Z' [$ ~" Y
[ol]``js function myFun(){ console.log(this); // What isthis` here?, ^, g& X5 J6 a9 u r; R% [
}[/ol]const obj = {5 _: O+ E* ^: c& r& b$ P9 Q
myMethod: function(){
/ q/ b# N5 g( Q$ {% r$ j7 {( p$ S- w eval(“myFun()”);
; f' T4 ?+ O' }8 A; ~+ q
5 q% Y8 G) ?: W" r/ g ;
# N4 A* z0 `4 P, c2 l: Uobj.myMethod();/ ^( A' {1 |! M; g( `. n
```1 \4 Z5 f" o- A; u
````````
% Z2 P. j% C5 X* \7 w! s5 Q0 B" ?[ol][/ol]``js function myFun()()(){ / / / / What isthis` here?
( a7 g# ~8 L# l$ Z J1 Z; g' h return {
; U) M y3 f+ f) d( t7 _/ m+ ^( N “is obj”: this === obj,0 S& Y, b9 b7 K& E" G
“is globalThis”: this === globalThis
* w2 `" z P& x8 y D };* I/ @, L* }7 U# p
}; T$ g2 k, S; V$ g' V5 @+ c
const obj = {};
$ Q& c) u) a- j5 U8 tconsole.log(myFun.call(obj));0 n( N& U3 e. t! D4 F' B+ q% Q( b
```
$ o2 D+ u) K" @Run code snippetExpand snippet; }, i+ l' P- y" d
````````7 R" z) W) _! `# Q4 u
[ol][/ol]``js class MyCls{ arrow = () => ({ / What isthis` here?
2 e' S/ T- _: D$ I$ a* R “is MyCls”: this === MyCls,
+ b9 d; t/ L5 j “is globalThis”: this === globalThis,0 n7 c& K( T) ~4 g w0 p' R8 f
“is instance”: this instanceof MyCls% p! ^& F- s& z9 K) n4 ~$ K
};6 U; I8 F3 v$ {) J8 m; ~" D% M* B
}% t- C; ~3 o5 S) a& c2 t* \
console.log(new MyCls().arrow());3 g; ~7 m5 k0 k, N
``` |
|