|
我注意到this网站上似乎没有明确解释关键词是什么,它是如何解释的 JavaScript 正确使用(和错误)。
3 F- H2 ?5 A* w J我目睹了它的一些非常奇怪的行为,不明白它为什么会发生。
3 v4 D! ~( p) z如何this什么时候工作应该用?
0 z& J4 R( @$ i* I8 T( z& U
1 a/ r# @/ `6 y O: o/ o. h+ J 解决方案: . l( x5 F2 I c
this是 JavaScript 中的关键字是执行上下文的属性。其主要用途是函数和构造函数。
$ _9 X4 k1 y3 W x, G7 }( k& x2 Y3 _我建议先读Mike West的文章JavaScript 作用域(存档)。这是对的thisJavaScript 优秀友好地介绍了作用域链和作用域链的概念。this很简单(如果你坚持最好的练习)。3 a7 l. U6 k; J* c" C" f
this规范中的技术说明的ECMAScript标准定义this抽象操作(缩写)AO)ResolveThisBinding:
( ^' z- o7 w7 f3 u4 {1 C[AO] ResolveThisBinding […]this上下文使用正在运行的 LexicalEnvironment 确定关键词的绑定。[步骤]:5 p4 T- K7 T# ?' {$ U' I
[ol]令envRec为GetThisEnvironment ()。' X. e: y6 r) y9 k( }7 h
返回 ?envRec .GetThisBinding()。[/ol]全球环境记录、模块环境记录和函数环境记录都有自己的 GetThisBinding 方法。7 N( X3 U" i% A
所述GetThisEnvironment AO找到目前正在运行的上下文执行情况LexicalEnvironment和查找最接近方兴未艾环境记录(通过迭代地访问他们的[[OuterEnv]]特性),它有这种结合(即HasThisBinding返回真)。这一过程以三种环境记录类型之一结束。* P% F( x4 S5 `2 E/ k9 l% c
的值this这通常取决于代码是否严格。) \: O7 K! K7 P( ?' ]
GetThisBinding 反映了返回值this目前执行上下文的值,所以无论何时建立新的执行上下文,都会this分析是一个不同的值。这也可能发生在修改当前执行的上下文时。以下部分列出了可能发生的五种情况。
3 Y7 r$ ~, ], L1 v3 m您可以在代码示例中放置代码示例AST 资源管理器遵循规范的详细信息。
9 o3 v7 u( i4 H1. 脚本中的全局执行上下文这是顶层评估的脚本代码,比如直接在 a 中[/code]在上下文中对脚本的初始全局进行评估时this会导致GetThisBinding采取以下步骤:! F. @+ b% i- K: ]6 R! A8 U
全局环境记录envRec […] GetThisBinding 具体方法:: d: f0 F9 U8 B' _- X& l7 t) N9 S
[ol]返回envRec .[[GlobalThisValue]]。[/ol]全局环境记录[[GlobalThisValue]] 属性总是设置为主机定义的全局对象,可以通过globalThis(window在 Web 上,global在 Node.js 上;MDN访问文档)访问对象。InitializeHostDefinedRealm了解 的步骤[[GlobalThisValue]] 属性是如何形成的。& F7 l) {& k1 g1 \! H
2.模块中的全局执行如下模块已在 ECMAScript 引入2015 。; d9 R) A0 F# n
这适用于模块,如直接在 a 内部时,而不是简单.7 j& P$ x+ Y# j' h" x4 G
在模块的初始全局实施中,求值this会导致GetThisBinding采取以下步骤:
3 O! d- t2 b* M, D记录模块环境GetThisBinding 具体方法 […] [这样做]:7 V, q* N3 l' q
[ol]返回undefined。[/ol]在模块中,值this总是undefined全局上下文。模块隐式严格。 `$ Z. N! Z# G
3. 输入评估码有两种eval调用:直接调用和间接调用。这种区别自 ECMAScript 第 5 版存在。5 w# t1 t1 J. e7 O b
直接eval调用通常看起来像eval(……);或(eval)(…… );(或((eval))(……);等等。直接的。2# x# j5 j! E3 ?6 E/ G. v& s+ X. `
间接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()调用。5 Q0 c6 ^; ^9 j/ M6 e6 C$ ]
PerformEval执行eval代码。它创建了一个新的声明环境记录作为 LexicalEnvironment,这是GetThisEnvironment 从中获取this值的地方。
; D2 d6 x- C- {/ I然后,如果this出现在eval环境记录在代码中GetThisBinding方法发现GetThisEnvironment它被称为返回值。& Y$ x: p$ d7 W' R
声明环境记录的创建取决于eval调用是直接还是间接:& h6 c3 Y: ~1 s4 m) U) k
在直接 eval 中,它将基于当前操作的上下文LexicalEnvironment。
9 t8 `& U: B( ~6 ?5 k z在间接评估中,它将记录在基于间接评估的领域[[GlobalEnv]] 属性(全局环境记录)。意思是:
7 ^; z# R4 ]$ F7 Q8 l在直接 eval 中,this值不会改变;它自称是eval.! p7 `. W* }1 W
在间接 eval 中,this ( )globalThis)。怎么样new Function??—?new Function类似于eval,但它不会立即调用代码;它创建了一个函数。本除非函数被调用,否则任何地方都不适用于装订,如下一节解释其正常工作。
# \2 E7 T% E. _' l8 v7 }- P' L4. 输入功能码调用输入函数代码将出现在函数中。3 j$ J2 S+ Q8 a5 Y9 @$ _& l
调用函数有四种语法。1 d2 N9 f% q' K
该EvaluateCall) t! y$ J6 C& K1 | E" {1 m( v
AO这三种执行:4 r0 o1 o9 _$ _7 P: s" A Y1 P0 x
3
, L8 @% z1 G9 U8 {* B; O' J调用普通函数
) }$ @! `5 L3 T可选链接调用
% w- C" h, _) [5 `; B标记模板
' Y" u& u9 K( [2 r- [ R* F: X4 ]( N并为此执行5 ^; O1 L3 d8 r( D8 @2 u
EvaluateNew5 c3 H- G9 i) M3 ~) V& a
:, A8 G/ M9 C. T% e
3
+ y, V4 @1 `- Q. B% o调用结构函数实际函数调用发生在Call AO 处,调用时使用根据上下文确定的thisValue;该参数在与调用相关的长串调用中传递。Call调用函数的[[Call]]内槽。这将被调用PrepareForOrdinaryCall,创建了新的函数环境记录:
, ^/ k1 R$ }+ B: h甲功能环境记录如果函数不是,则声明环境记录用于表示功能的顶层范围和ArrowFunction,提供了一种this如果函数不是ArrowFunction函数并引用super,还包括函数环境记录super调用函数内部执行方法的状态。
& A _6 E6 e0 g8 M$ V( R7 j- J M另外,在函数 Environment Record 中有 [[ThisValue]] 字段:) L2 T) x5 l1 F
这是this用于此函数调用的值。2 ^0 [ X1 Y( Z/ R3 y
该NewFunctionEnvironment通话还设置了功能环境[[ThisBindingStatus]]属性。1 f) U$ L6 y' w E$ C
[[Call]]还调用OrdinaryCallBindThis,其中适当的thisArgument基于以下因素:
4 ]9 @- I9 ?. A @1 [/ V+ I2 n/ F( s原始参考,
; L6 R) Y4 w' b% H D函数的类型,以及, F! J$ T/ n$ R5 k! ~! U4 n8 _
代码是否严格。一旦确定,新创建的函数 Environment Record的BindThisValue实际上,方法的最终调用会 [[ThisValue]] 字段设置为thisArgument。
1 p" R" t) g* a7 j& }最后,这个字段是函数 Environment Record 的 GetThisBinding AOthis从以下位置获取值:; ^ T! }& O/ c
函数 Environment Record envRec […] GetThisBinding 具体方法:
4 Y/ F. g% {& j. W J/ A[…], m7 W2 R$ h+ N: }0 u
\3. 返回envRec .[[ThisValue]]。
& A3 A7 R& A$ m8 x: u+ Q同样,该确定值的方法取决于许多因素;这只是一个总体概述。有了这个技术背景,让我们检查一下所有具体的例子。9 {% ?' y, I# Y8 D& R0 m
箭头函数在评估箭头函数时,函数对象 [[ThisMode]] 内部槽在OrdinaryFunctionCreate 中设置为“词法”。6 {( s4 E* x$ T1 R; T! O
在OrdinaryCallBindThis,它接受函数F:
, o; `: n7 y& f; G[ol]令thisMode为F .[[ThisMode]]。7 {+ R) p6 Z2 w" s5 v0 o% `' ]
如果thisMode是词法的,则返回 NormalCompletion( undefined)。[…][/ol]这只意味着跳过绑定this的算法的其余部分。箭头函数不绑定自己的this值。$ ~; T: ~! [' U5 y
那么,this箭头函数内部是什么?ResolveThisBinding和GetThisEnvironment,HasThisBinding 方法显式返回false。
z8 E2 }$ Q, ^) }4 O8 x1 LHasThisBinding 函数的具体方法 Environment Record envRec […] [这样做]:
, S% j u" {- G, H[ol]如果envRec .[[ThisBindingStatus]] 是lexical,则返回false;否则,返回true。[/ol]因此,外部环境被迭代地发现。这个过程将有this三个环境之一的绑定结束了。
% O# `' I' _) d* A4 f# B: H这只是意味着,在箭头函数体中,this箭头函数的词法范围,或者换句话说(箭头函数和函数声明/表达式:它们等效/可交换吗?) n! f" a* \( ?( [! ^ T
箭头函数没有自己的this[…] 绑定。相反,[此标识符]在词法范围内像任何其他变量一样进行分析。这意味着在箭头函数中,this[引用] 到定义this在箭头函数的环境中[值] (即箭头函数的外部)。' o; O" w% q# z$ N* M. O
功能属性在正常功能(function,方法),this来确定如何调用所述函数?。
! Q ]8 B! F9 y' q这些语法变体派上用场。6 G/ f6 q" X4 H2 a4 A
考虑包含函数的对象:
* U9 F, i! R e7 Z* e' b: @ h8 R! x$ J f- Q1 [1 ^1 _
- const refObj = func: function(){ console.log(this); } }code]或者:- y% R L. Q6 r- A7 h
- [code]const refObj = func(){ console.log(this); } }code]在以下任何函数调用中,this里面的值func都是refObj. 1+ \* x x/ L" S4 x, p5 e; ]
; _% h& m+ I& A P) b* {- refObj.func()5 d9 Y' n+ ~ M9 H9 k
- refObj["func"]()
; L. W& v. k- u) Z- | M6 H - refObj?.func()
9 y9 R' Q% Y! l- w3 ] - refObj.func?.()6 A/ v, h( {( @* O' l
- `refObj.func```
如果被调用的函数在语法上是一个基对象的属性,那么这个基将是调用的“引用”,在通常情况下,它是 的值this。解释了上述链接的评估步骤;例如,在refObj.func()(或refObj["func"]())中,CallMemberExpression是整个表达式refObj.func(),它由MemberExpression refObj.func和Arguments 组成 ()。
9 ]' Z: @" y- `8 J- 而且,refObj.func并refObj扮演三个角色,每个角色:
* `6 P: k/ d3 B9 f! S& G" u' m - 3 K9 s/ c( |3 v' V: b2 t% q( f
- 都是表达,8 J# J% V9 l1 y) A5 V0 g/ p
- 而且都是参考
% Z" S' ~5 F* Y9 C4 e+ q! `7 z1 Z! i - 都是价值观。
refObj.func作为值可调函数对象;相应的参考用于确定this绑定。
% I6 u3 G6 X! H3 Z5 _0 n5 } - 可选链接的工作方式与标记模板示例非常相似:基本上,引用是在?.(), 之前```或 以前的所有内容()`。
! X8 @7 @+ Y; v8 k0 ?/ a' w+ v3 i" n - EvaluateCall使用此引用IsPropertyReference确定它是否是语法上的对象属性。它试图获得引用 [[Base]] 属性(例如refObj,当应用于refObj.func; 或foo.bar应用于 时foo.bar.baz)。假如把它写成属性,那么GetThisValue将获取此 [[Base]] 属性并将其用作此值。* H7 e- V+ R1 a, t
- 注意:关于.getter/setter 的工作方式和方法相同this。例如,简单的属性不会影响上下文的执行this在全局范围内:
1 j8 m0 b' l$ |3 L j3 Y - [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();`.
8 O, V/ u: n' T 这种情况也发生在传输或分配方法或使用逗号操作符时。这是参考记录和值之间的差异。) I2 u( p; w3 P/ x( b* U6 U. P
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.
! P7 E. v p) D. N EvaluateCall电话呼叫与thisValue的不确定这里。这在OrdinaryCallBindThis(F:函数对象;thisArgument:传递给Call的thisValue)不同:
' B O1 v! o/ ?& \5 o+ D3 d/ |1 d[ol]令thisMode为F .[[ThisMode]]。[/ol][…]
/ M- m9 w# j3 i[ol]如果thisMode是严格的,则让thisValue为thisArgument。
i$ f1 Q" M; R! i别的,5 c0 _& \' a1 q
如果8 Y9 d# u9 v& H4 N$ R
thisArgument+ i% B! T5 |1 O
为2 b8 w$ h8 C, _7 c# l; g
undefined/ v6 }4 ?, V9 t; y' }
或) w6 _* U2 s, @
null
; ?$ q3 X. G' S6 Y,则
( A$ N+ V1 M. F M4 x) i' |[ol]令globalEnv为calleeRealm .[[GlobalEnv]]。/ }8 A, y" d( l/ C; ?; g3 h( B9 Z+ n
[…]
4 C+ n- F. K0 S令thisValue为globalEnv .[[GlobalThisValue]]。[/ol]
/ p" j5 W* o( A1 e# I ^别的,9 m5 X0 s2 }% q4 t$ x3 Y
[ol]让thisValue成为!ToObject (thisArgument)。9 Y9 _( A! ^( n' E& l* B
注意:ToObject生成包装对象 […]。[/ol][/ol][…]
Q: O6 H X9 B& i( Q3 N+ E7 [7 B注:第 5 步在严格模式下设置 的实际值this为提供的thisArgument -?undefined在这种情况下。在草率模式中,模式thisArgument导致this成为全局this值。6 X8 \8 _7 g! U: J% w
如果IsPropertyReference返回false,则EvaluateCall采取以下步骤:
0 R6 Z+ W# w7 c0 M! K[ol]让refEnv为ref .[[Base]]。
! X' O$ A/ O7 o6 F; N断言:refEnv是环境记录。. e* @& x9 ^1 z6 B
让thisValue为refEnv .WithBaseObject()。[/ol]这是未定义的thisValue可能来自:refEnv。WithBaseObject()总是不确定的,除了在with声明。在这种情况下,thisValue将是绑定对象。/ K# k9 c2 F" v& n/ A
还有Symbol.unscopables(MDN控制 文档)with绑定行为。6 z( A" w- Q0 a5 G( G6 Z1 }& e
综上所述,到目前为止:
) k" P7 E# e7 ?- ofunction 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`.}3 |9 \$ }4 h! U
和:, p1 C5 r: x7 _% D. ^& Q
"use strict";function f(){ console.log(this);}f(); // Logs `undefined`.// `with` statements are not allowed in strict-mode code.7 [ j7 a, D8 O- b
评估时应注意this,它并不重要*,其中*函数定义正常。
' s, Y3 U) V0 F: ?; Z7 L' s, ~.call,.apply,.bind,thisArg和原语OrdinaryCallBindThis第 5 步和第 6步.2 步(规范中的 6.b)另一的另一个结果是,仅在草率模式下才将原始this值强制转换为对象。
7 r2 m6 U) s7 j* A! N2 b为了检查这一点,让我们this价值引入的另一个来源覆盖this三种绑定方法:47 t" e/ r) a6 V2 {5 Z, M
Function.prototype.apply(thisArg,argArray)/ L8 j- O, F. H/ K" ~
Function.prototype.{ call,bind}(thisArg,...args).bind创建绑定函数this绑定设置为thisArg而且不能再改了。.call并.apply立即调用函数并将其调用this绑定设置为thisArg。
0 e+ K" Y% O L7 \6 t.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值的示例:' a+ v# s7 r, C0 Y( m) y0 h
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);
/ ?4 D: a+ E. ` 在严格模式和非严格模式下,对象是一样的。5 w& U% o0 _% e, ?5 ?; C6 N, c
试着提供一个原始值:
/ N/ H+ h; a8 q7 F _; ?- Cfunction f(){ console.log(this);}const myString = "s", g = f.bind(myString);g();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Logs `String { "s" }`.f.call(myString); // Logs `String { "s" }`.
% H# F, T# X* P; n2 q2 u% }6 A 在非严格模式下,原语被迫转换为其对象包装形式。它正在调用你Object("s")or获得相同类型的对象new String("s")。在严格的模式下,你可以使用原语: @) r( }7 _3 \: V) C, l' T
"use strict";function f(){ console.log(this);}const myString = "s", g = f.bind(myString);g();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Logs `"s"`.f.call(myString); // Logs `"s"`.% o$ b( D( W1 t+ r% P1 T* d
如 jQuery 设置 this 在这里选择DOM 元素:5 ~% c/ A; {: t9 c. a, x
$("button").click(function(){ console.log(this); // Logs the clicked button.});
; I+ l6 j# r6 L$ n: A6 O! H 构造函数,类和new当使用new当运算符调用函数作为构造函数时,EvaluateNew调用Construct,后者调用[[Construct]] 方法。如果函数是基本结构(即,不是class extends… {… },它的设置thisArgument从构造函数的原型创建新对象。this构造函数中设置的属性最终会出现在生成的实例对象上。this隐式返回,除非你显式返回自己的非原始值。8 Q7 S) s- P' I( d
Aclass在 ECMAScript 引入2015 。3 K% H- P8 Y6 o8 _: B6 S" j' B
function 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 }`./ Q8 Q' V% t. n6 x: f, K
严格模式中隐含类定义:
' f7 y0 X- S x Z' @# Hclass A{ m(){ return this; } m(){ const m1 = this.m1. console.log(m();new A().m(); / Logs `undefined`.
G2 N- W+ L2 z1 N+ Y6 _. g super行为的例外new是class extends… {… },如上所述。调用时不会立即设置衍生类this值;他们只在super调用后这样做(在没有自己的情况下隐式发生constructor)。使用this呼叫之前super不允许。0 z; d' F7 Z4 Y& I
调用使用super调用词法范围(函数环境记录)this值调用超级结构函数。GetThisValue有一个特别的super调用规则。使用它BindThisValue设置this记录环境。( g. \" H! G m4 h' N) x' E3 e1 M
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 }`.
) k4 r2 o( {5 f2 \" H/ y8 a( V 5. 评价字段ECMAScript实例字段和静态字段引入 2022 。
2 |' S# M! D% A0 ]6 Q- ]当class评估 a 时,执行ClassDefinitionEvaluation,修改正在运行的上下文。对于每个人ClassElement:
( B e x6 M# `$ O T6 o2 X, X9 G若字段静态,则this指类本身,
; |5 m7 _# ]: B0 ~: ~% r若字段不静态,则this引用实例。私有字段(例如#x)添加到 的方法PrivateEnvironment。
4 } w, k3 @/ x$ f2 P- @' r( K( O目前静态块是TC39 第 3 阶段提案。静态块的工作方式与静态字段和方法相同:this它们内部是指类本身。5 x+ i2 T8 l& A3 c3 [7 R
方法和 请注意getter/setter 中,this就像在普通函数属性中一样工作。$ m2 i" I% U: y& f* m$ L& f# F3 L) }
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`.
, P( Y4 G) I, H# D) H/ ~1 ^ 1 o.f)()相当于o.f(); (f)()相当于f()。这篇文章 2ality 文章存档)解释。特别是查看ParenthesizedExpression如何计算。& u/ L/ x' K" f4 C2 t! O/ h
2:它必须是MemberExpression,不能是属性,必须有 [[ReferencedName]] 正好是“eval”,必须是 %eval% 内在对象。- u" J2 k# H/ r7 |
三、每当规范说“让ref成为对X求值的结果。”,那么X是一些表达式,你需要找到求值步骤。例如,评估MemberExpression或CallExpression结果是这些算法之一。其中一些导致参考记录。5 G7 ?; G/ ]* P
4:还允许提供其他本地和主机方法这个值,特别是Array.prototype.map,Array.prototype.forEach等接受一个thisArg作为他们的第二个参数。任何人都可以用自己的方法来改变this一样(func,thisArg) => func.bind(thisArg),(func,thisArg) => func.call(thisArg)像往常一样,MDN提供巨大的文档。
% l" c! T# G* A; L, f: g只是为了好玩,用一些例子来测试你的理解回答每个代码片段的问题:“this标记行的值是多少?为什么? .! T$ h/ N" a4 P
单击灰色框以显示答案。9 ~0 B. Y) f3 d$ J3 _8 Q" `
[ol]js if(true){ console.log(this); // What is `this` here? }[/ol]``
8 P! q" M B$ X; m% R[ol][/ol]```js
: B! y6 L" D- A+ @ const obj = {};
7 \6 Q' N6 R5 b* O$ q1 {8 A& Wfunction myFun(){
7 o7 O' A( v/ J. y+ L return { // What is this here?
4 t# B: F8 U# j3 B# C9 V* Y “is obj”: this === obj,
; Y2 t2 r& b+ {: ]8 V' D “is globalThis”: this === globalThis- L2 ^0 j7 S, m8 M9 _: n( f
;
) M+ Q& A9 N2 }6 n! ]: c* t }
: X) G( B& w0 X* F: ~( w8 Iobj.method = myFun;
+ b, r# l) V' b+ c) |0 yconsole.log(obj.method());
1 x3 ~, c0 o, }* U# b5 g8 p```+ E8 L2 i: A# F- g
Run code snippetExpand snippet
8 X. x" @# h5 Y2 [``````4 Y1 B. C6 `/ Y& ~( c+ b
[ol][/ol]``js const obj = { myMethod: function()()()(){ return { // What isthis` here?% h4 [# I' |2 B& k
“is obj”: this === obj,
5 T& X4 t4 \. A9 }$ H “is globalThis”: this === globalThis7 @" w, c. x/ m4 S
$ Z( ^ S2 u; X" o( F
- O0 `& S/ O' l4 o0 h3 D0 I6 u
$ Y' O5 b7 y2 ^. |" Y) o g' E/ M
myFun = obj.myMethod;
) B3 T7 c' r$ L; Kconsole.log(myFun());" t5 Q5 ^5 P, C
```) o, @( b9 e$ I" ?6 r* c
Run code snippetExpand snippet
0 h1 x# {2 P& v) r``````````
5 @2 K+ s: a" Y; s+ C[ol][/ol]``js const obj = myFun: () => ({ / What isthis` here?2 [* r' `( n* S8 z. P: q. H
“is obj”: this === obj,
# R) A$ V" J1 T2 ~- B “is globalThis”: this === globalThis
; h( K$ q/ G% B. W; F 3 h: M* v9 t4 i" D5 z$ t ~& t
;
0 C6 Z+ o, [: s; uconsole.log(obj.myFun());
3 v/ P7 \ Z5 [9 {" u0 R```, g2 @6 W6 u1 d: y, E" R1 e4 @
Run code snippetExpand snippet
3 O) W3 f9 Q8 E3 B``````" N. N* d7 B( ?9 k/ c' |
[ol]``js function myFun(){ console.log(this); // What isthis` here?
7 A8 a' ]' c) y( F0 A Q" \ }[/ol]const obj = {! W1 `- O7 z2 T7 o( T
myMethod: function(){
6 c1 T9 b) {7 l, t; ?& f$ G$ ?! |" e: O eval(“myFun()”);
3 F+ P) Y Q' ^* X7 D" N; K# @ 5 d- z4 m7 P" y E+ F$ h, t
;$ m7 L4 F) t2 r u
obj.myMethod();
; W6 g( }& ]" i* \5 I ```9 i. k. s/ }0 r4 H& G9 r
````````2 @+ k/ N1 e0 w) z- z/ S# \. E, j* V
[ol][/ol]``js function myFun()()(){ / / / / What isthis` here?
- J" v6 w. L) t6 d8 i" b" p: V return {
* T9 N/ f& b/ s1 r: w$ @+ D “is obj”: this === obj,
# S1 ?% a! g4 e& {* {2 i “is globalThis”: this === globalThis1 J# T. T' d8 {. r, t+ D% B
};6 t2 C. L7 t: p! W r% j
}
! M& i* q1 h% O* T; Econst obj = {}; ^. q5 z5 F: y: x# P$ C& e' E. ^
console.log(myFun.call(obj));
F* D; x5 N' t```
0 a" a( b9 D5 R& u6 yRun code snippetExpand snippet: Q3 D$ w- K& H( c; w: A
````````
2 {, B: [" A' d& n; D[ol][/ol]``js class MyCls{ arrow = () => ({ / What isthis` here?
& y2 u7 R5 p- D+ [/ q3 U, J: D. b “is MyCls”: this === MyCls,
" y2 h6 C& I- ]. B3 x' k' H7 ~% | “is globalThis”: this === globalThis,+ O+ i' G% ?$ V' Z; a
“is instance”: this instanceof MyCls
! g c5 H2 g1 ~5 [; u. Q- Y };6 K( c$ X: o& T: B
}
6 _' e. B* k+ Jconsole.log(new MyCls().arrow());
R9 A# a8 z0 E& o$ c``` |
|