下面我尝试了上面使用 Object 和 this 所做的所有操作,但首先创建函数而不是直接编写对象。
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + " "); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + " "); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + " "); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + " "); //v2
document.write(obj1.getVersion() + " "); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + " "); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+" ");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4。在构造函数内部使用时。
当函数用作构造函数时(即使用 new 关键字调用时),函数体内的 this 指向正在构造的新对象。
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5。当在原型链上定义的函数内部使用时
如果该方法位于对象的原型链上,则该方法内的 this 引用该方法被调用的对象,就像该方法是在该对象上定义的一样。
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6。内部call()、apply()和bind()函数
所有这些方法均在 Function.prototype 上定义。
这些方法允许编写一次函数并在不同的上下文中调用它。换句话说,它们允许指定在执行函数时将使用的 this 值。它们还可以在调用原始函数时将任何参数传递给原始函数。
const g = (f) => f(); // No base ref.
const h = refObj.func;
const j = () => refObj.func;
g(refObj.func);
h(); // No base ref.
j()(); // No base ref.
(0, refObj.func)(); // Another common pattern to remove the base ref.
function f1(){
console.log(this);
}
function f2(){
console.log(this);
}
function f3(){
console.log(this);
}
const o = {
f1,
f2,
[Symbol.unscopables]: {
f2: true
}
};
f1(); // Logs `globalThis`.
with(o){
f1(); // Logs `o`.
f2(); // `f2` is unscopable, so this logs `globalThis`.
f3(); // `f3` is not on `o`, so this logs `globalThis`.
}
和:
"use strict";
function f(){
console.log(this);
}
f(); // Logs `undefined`.
// `with` statements are not allowed in strict-mode code.
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);
使用 new 运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,它调用 [[Construct]] 方法。如果函数是基本构造函数(即不是 class extends...{...}),它会设置 thisArgument到从构造函数的原型创建的新对象。构造函数中 this 上设置的属性最终将出现在生成的实例对象上。 this 会隐式返回,除非您显式返回自己的非原始值。
与其他语言相比,
this关键字在 JavaScript 中的行为有所不同。在面向对象语言中,this关键字指的是该类的当前实例。在 JavaScript 中,this的值由函数的调用上下文 (context.function()) 及其调用位置决定。 p>1。在全局上下文中使用时
当您在全局上下文中使用
this时,它会绑定到全局对象(浏览器中的window)当您在全局上下文中定义的函数内使用
this时,this仍然绑定到全局对象,因为该函数实际上是全局上下文的方法。function f1() { return this; } document.write(f1()); //[object Window]上面的
f1是一个全局对象的方法。因此我们也可以在window对象上调用它,如下所示:function f() { return this; } document.write(window.f()); //[object Window]2。当在对象方法内部使用时
当您在对象方法中使用
this关键字时,this会绑定到“直接”封闭对象。var obj = { name: "obj", f: function () { return this + ":" + this.name; } }; document.write(obj.f()); //[object Object]:obj上面我已将“立即”一词放在双引号中。这是为了表明,如果将对象嵌套在另一个对象中,则
this会绑定到直接父对象。var obj = { name: "obj1", nestedobj: { name:"nestedobj", f: function () { return this + ":" + this.name; } } } document.write(obj.nestedobj.f()); //[object Object]:nestedobj即使你将 function 作为方法显式添加到对象中,它仍然遵循上述规则,即
this仍然指向直接父对象。var obj1 = { name: "obj1", } function returnName() { return this + ":" + this.name; } obj1.f = returnName; //add method to object document.write(obj1.f()); //[object Object]:obj13。调用无上下文函数时
当您在没有任何上下文(即不在任何对象上)的情况下调用的函数内部使用
this时,它会绑定到全局对象(浏览器中的window)(即使该函数是在对象内部定义的)。var context = "global"; var obj = { context: "object", method: function () { function f() { var context = "function"; return this + ":" +this.context; }; return f(); //invoked without context } }; document.write(obj.method()); //[object Window]:global用函数尝试一切
我们也可以用函数来尝试以上几点。但还是有一些差异。
this向函数添加成员。来指定它们。new运算符创建其实例。下面我尝试了上面使用 Object 和
this所做的所有操作,但首先创建函数而不是直接编写对象。/********************************************************************* 1. When you add variable to the function using this keyword, it gets added to the function prototype, thus allowing all function instances to have their own copy of the variables added. *********************************************************************/ function functionDef() { this.name = "ObjDefinition"; this.getName = function(){ return this+":"+this.name; } } obj1 = new functionDef(); document.write(obj1.getName() + ""); //[object Object]:ObjDefinition /********************************************************************* 2. Members explicitly added to the function protorype also behave as above: all function instances have their own copy of the variable added. *********************************************************************/ functionDef.prototype.version = 1; functionDef.prototype.getVersion = function(){ return "v"+this.version; //see how this.version refers to the //version variable added through //prototype } document.write(obj1.getVersion() + "
"); //v1 /********************************************************************* 3. Illustrating that the function variables added by both above ways have their own copies across function instances *********************************************************************/ functionDef.prototype.incrementVersion = function(){ this.version = this.version + 1; } var obj2 = new functionDef(); document.write(obj2.getVersion() + "
"); //v1 obj2.incrementVersion(); //incrementing version in obj2 //does not affect obj1 version document.write(obj2.getVersion() + "
"); //v2 document.write(obj1.getVersion() + "
"); //v1 /********************************************************************* 4. `this` keyword refers to the immediate parent object. If you nest the object through function prototype, then `this` inside object refers to the nested object not the function instance *********************************************************************/ functionDef.prototype.nestedObj = { name: 'nestedObj', getName1 : function(){ return this+":"+this.name; } }; document.write(obj2.nestedObj.getName1() + "
"); //[object Object]:nestedObj /********************************************************************* 5. If the method is on an object's prototype chain, `this` refers to the object the method was called on, as if the method was on the object. *********************************************************************/ var ProtoObj = { fun: function () { return this.a } }; var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj //as its prototype obj3.a = 999; //adding instance member to obj3 document.write(obj3.fun()+"
");//999 //calling obj3.fun() makes //ProtoObj.fun() to access obj3.a as //if fun() is defined on obj3
4。在构造函数内部使用时。
当函数用作构造函数时(即使用
new关键字调用时),函数体内的this指向正在构造的新对象。var myname = "global context"; function SimpleFun() { this.myname = "simple function"; } var obj1 = new SimpleFun(); //adds myname to obj1 //1. `new` causes `this` inside the SimpleFun() to point to the // object being constructed thus adding any member // created inside SimipleFun() using this.membername to the // object being constructed //2. And by default `new` makes function to return newly // constructed object if no explicit return value is specified document.write(obj1.myname); //simple function5。当在原型链上定义的函数内部使用时
如果该方法位于对象的原型链上,则该方法内的
this引用该方法被调用的对象,就像该方法是在该对象上定义的一样。var ProtoObj = { fun: function () { return this.a; } }; //Object.create() creates object with ProtoObj as its //prototype and assigns it to obj3, thus making fun() //to be the method on its prototype chain var obj3 = Object.create(ProtoObj); obj3.a = 999; document.write(obj3.fun()); //999 //Notice that fun() is defined on obj3's prototype but //`this.a` inside fun() retrieves obj3.a6。内部call()、apply()和bind()函数
Function.prototype上定义。this值。它们还可以在调用原始函数时将任何参数传递给原始函数。fun.apply(obj1 [, argsArray])将obj1设置为this内的值code>fun() 并调用fun(),传递argsArray的元素作为其参数。fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- 设置 obj1 作为fun()内this的值,并调用fun()传递arg1, arg2, arg3, ... 作为其参数。fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- 返回对函数的引用fun,其中 fun 内的this绑定到obj1,并且fun的参数绑定到指定的参数arg1、arg2, arg3,...。apply、call和bind之间的区别一定已经很明显了。apply允许将参数指定为类似数组的对象,即具有数字length属性和相应的非负整数属性的对象。而call允许直接指定函数的参数。apply和call都会立即在指定上下文中并使用指定参数调用该函数。另一方面,bind 只是返回绑定到指定 this 值和参数的函数。我们可以通过将返回函数分配给变量来捕获对此返回函数的引用,然后我们可以随时调用它。function add(inc1, inc2) { return this.a + inc1 + inc2; } var o = { a : 4 }; document.write(add.call(o, 5, 6)+""); //15 //above add.call(o,5,6) sets `this` inside //add() to `o` and calls add() resulting: // this.a + inc1 + inc2 = // `o.a` i.e. 4 + 5 + 6 = 15 document.write(add.apply(o, [5, 6]) + "
"); //15 // `o.a` i.e. 4 + 5 + 6 = 15 var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6 document.write(g()+"
"); //15 var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ? document.write(h(6) + "
"); //15 // 4 + 5 + 6 = 15 document.write(h() + "
"); //NaN //no parameter is passed to h() //thus inc2 inside add() is `undefined` //4 + 5 + undefined = NaN
7.事件处理程序内的
thisthis来引用相应的元素。这种直接的函数分配可以使用addeventListener方法或通过onclick等传统事件注册方法来完成。)内使用this时,它指的是元素。this会解析为全局对象window。attachEvent将函数附加到事件处理程序时,可以实现与上述相同的行为。它不是将函数分配给事件处理程序(从而创建元素的函数方法),而是在事件上调用函数(在全局上下文中有效地调用它)。我建议在 JSFiddle中更好地尝试此操作>.
8。 ES6 箭头函数中的
this在箭头函数中,
this的行为类似于公共变量:它将从其词法范围继承。定义箭头函数的函数的this将是箭头函数的this。所以,这与以下行为相同:
(function(){}).bind(this)请参阅以下代码:
const globalArrowFunction = () => { return this; }; console.log(globalArrowFunction()); //window const contextObject = { method1: () => {return this}, method2: function(){ return () => {return this}; } }; console.log(contextObject.method1()); //window const contextLessFunction = contextObject.method1; console.log(contextLessFunction()); //window console.log(contextObject.method2()()) //contextObject const innerArrowFunction = contextObject.method2(); console.log(innerArrowFunction()); //contextObject此是JavaScript 中的关键字是执行上下文的属性。它的主要用途是在函数和构造函数中。this的规则非常简单(如果您坚持最佳实践)。规范中
this的技术描述ECMAScript 标准定义
this通过抽象操作(缩写为AO)ResolveThisBinding:全球环境记录,模块环境记录,以及 函数环境记录每个都有自己的 GetThisBinding 方法。
GetThisEnvironment AO 查找当前的运行执行上下文的 LexicalEnvironment 并查找最接近的上升环境记录(通过迭代访问其 [[OuterEnv]] 属性),该记录具有 this 绑定(即 HasThisBinding 返回 true)。此过程以三种环境记录类型之一结束。
this的值通常取决于代码是否处于 严格模式。GetThisBinding 的返回值反映当前执行上下文的
this值,因此每当建立新的执行上下文时,this都会解析为不同的值。当当前执行上下文被修改时,也会发生这种情况。以下小节列出了可能发生这种情况的五种情况。您可以将代码示例放入 AST 资源管理器中,以遵循规范详细信息。
1。脚本中的全局执行上下文
这是在顶层评估的脚本代码,例如直接在
内:当在脚本的初始全局执行上下文中时,评估
this会导致 GetThisBinding 采取以下步骤:全局环境记录的 [[GlobalThisValue]] 属性始终设置为主机定义的全局对象,可通过
globalThis(Web 上的 window,Node.js 上的global;MDN 上的文档)。按照 InitializeHostDefinedRealm 的步骤了解 [[GlobalThisValue]] 属性是如何产生的。2。 模块
中的全局执行上下文ECMAScript 2015 中引入了模块。
这适用于模块,例如直接位于
内部时,而不是简单的中。当在模块的初始全局执行上下文中时,评估
this会导致 GetThisBinding 采取以下步骤:在模块中,
this的值在全局上下文中始终是未定义。模块隐式处于严格模式。3。输入eval代码
有两种
eval调用:直接和间接。这种区别自 ECMAScript 第五版以来就存在。eval调用通常类似于eval(...);或(eval)(...); (或((eval))(…);等)。1 这只是 direct(如果调用表达式符合狭窄模式)。2eval调用涉及以任何其他方式调用函数引用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 对“(1, eval)('this') vs eval('this') in JavaScript?”的回答。 和 Dmitry Soshnikov 的 ECMA-262- 5 详细信息 – 第 2 章:严格模式 (已存档),适用于您可能使用间接
eval()调用的情况。PerformEval 执行
eval代码。它创建一个新的 声明性环境记录 作为其 LexicalEnvironment,这是 GetThisEnvironment 从中获取this值。然后,如果
this出现在eval代码中,则GetThisEnvironment 被调用并返回其值。创建的声明性环境记录取决于
eval 调用是直接或间接的:这意味着:
this值不会改变;它取自名为eval的词法作用域。this值是全局对象 (globalThis)。新函数怎么样? —new Function与eval类似,但它不会立即调用代码;它创建了一个函数。 this 绑定不适用于此处的任何地方,除非调用函数时,该函数正常工作,如下一小节所述。4。输入函数代码
在调用函数时输入函数代码。
调用函数的语法有四种类别。
实际的函数调用发生在 Call AO 处,使用 thisValue 调用 根据上下文确定;这个参数在一长串与调用相关的调用中传递。 Call 调用 [[Call]] 函数的内部槽。这会调用 PrepareForOrdinaryCall,其中新的 函数环境记录已创建:
此外,函数环境记录中还有[[ThisValue]]字段:
NewFunctionEnvironment 调用还会设置函数环境的 [[ThisBindingStatus]] 属性。
[[Call]] 还调用 OrdinaryCallBindThis,其中适当的 thisArgument 基于以下因素确定:
确定后,最终调用新创建函数环境记录的 BindThisValue 方法实际设置将 [[ThisValue]] 字段添加到 thisArgument。
最后,这个字段就是函数环境记录 GetThisBinding AO 从以下位置获取
this的值:同样,this 值的精确确定取决于许多因素;这只是一般性概述。有了这个技术背景,我们来看看所有的具体例子。
箭头函数
当计算箭头函数时,[[ThisMode]]内部槽函数对象的属性在 OrdinaryFunctionCreate 中设置为“lexical”。 p>
在 OrdinaryCallBindThis 处,它采用一个函数F:
这仅仅意味着绑定this的算法的其余部分被跳过。箭头函数不会绑定自己的 this 值。
那么,箭头函数中的
this是什么?回顾一下 ResolveThisBinding 和 GetThisEnvironment,HasThisBinding 方法显式返回 假。因此,我们会迭代地查找外部环境。该过程将在具有 this 绑定的三个环境之一结束。
这只是意味着,在箭头函数体中,
this来自箭头函数的词法范围,或者换句话说(来自 箭头函数与函数声明/表达式:它们是否等价/可交换?):函数属性
在普通函数中(
function、方法),this由函数的调用方式决定。这就是这些“语法变体”派上用场的地方。
考虑这个对象包含一个函数:
const refObj = { func: function(){ console.log(this); } };或者:
const refObj = { func(){ console.log(this); } };在以下任何函数调用中,
func内的this值将为refObj。1refObj.func()refObj["func"]()refObj?.func()refObj.func?.()refObj.func``如果被调用的函数在语法上是基对象的属性,则该基对象将是调用的“引用”,在通常情况下,它将是
this的值。上面链接的评估步骤对此进行了解释;例如,在refObj.func()(或refObj["func"]())中,CallMemberExpression 是整个表达式refObj.func(),它由 MemberExpressionrefObj.func和 参数()。而且,
refObj.func和refObj扮演三个角色,分别:refObj.func作为值是可调用的函数对象;相应的引用用于确定this绑定。可选链接和标记模板示例的工作方式非常相似:基本上,引用是
?.()之前、``之前或 ()代码>。EvaluateCall 使用 IsPropertyReference 以确定它在语法上是否是对象的属性。它试图获取引用的 [[Base]] 属性(例如,当应用于
refObj.func时为refObj;或foo.barcode> 当应用于foo.bar.baz时)。如果将其写为属性,则 GetThisValue 将获取此 [[Base]] 属性并使用它作为 this 值。注意:Getters / Setters 的工作方式与方法,关于
this。简单属性不会影响执行上下文,例如这里,this在全局范围内:const o = { a: 1, b: this.a, // Is `globalThis.a`. [this.a]: 2 // Refers to `globalThis.a`. };不带基引用、严格模式和
with没有基引用的调用通常是不作为属性调用的函数。例如:
当传递或分配方法,或使用逗号运算符时,也会发生这种情况。这就是参考记录和值之间的差异相关的地方。
注意函数
j:按照规范,您会注意到j只能返回函数对象(Value)本身,而不能返回引用记录。因此,基本引用refObj丢失。EvaluateCall 调用 调用,此处的thisValue为未定义。这在 OrdinaryCallBindThis 中有所不同(F:函数对象;thisArgument:传递给 Call 的 thisValue):
注意:第 5 步将
this的实际值设置为严格模式下提供的 thisArgument - 在本例中为undefined。在“草率模式”下,未定义或 null thisArgument 会导致this成为全局 this 值。如果IsPropertyReference返回false,则EvaluateCall 采取以下步骤:
这是未定义的 thisValue 可能来自:refEnv。WithBaseObject() 始终未定义,
with语句。在这种情况下,thisValue 将是绑定对象。还有
Symbol.unscopables(MDN 上的文档)来控制with绑定行为。总结一下,到目前为止:
function f1(){ console.log(this); } function f2(){ console.log(this); } function f3(){ console.log(this); } const o = { f1, f2, [Symbol.unscopables]: { f2: true } }; f1(); // Logs `globalThis`. with(o){ f1(); // Logs `o`. f2(); // `f2` is unscopable, so this logs `globalThis`. f3(); // `f3` is not on `o`, so this logs `globalThis`. }和:
"use strict"; function f(){ console.log(this); } f(); // Logs `undefined`. // `with` statements are not allowed in strict-mode code.请注意,在计算
this时,普通函数的定义位置并不重要。.call,.apply,.bind, thisArg 和基元OrdinaryCallBindThis 的步骤 5 的另一个结果,与步骤 6.2(在规范),即原始 this 值在“草率”模式下仅被强制转换为对象。
为了检查这一点,让我们引入 this 值的另一个来源:重写 this 绑定的三个方法:4
Function.prototype.apply(thisArg, argArray)Function.prototype.{调用,绑定}(thisArg, ...args)李>.bind创建一个绑定函数,其this 绑定已设置为 thisArg 并且无法再次更改。.call和.apply立即调用函数,并设置 this 绑定到 thisArg。.call和.apply直接映射到 Call ,使用指定的thisArg。.bind使用 BoundFunctionCreate 创建绑定函数。它们有自己的[[Call ]] 方法,它查找函数对象的 [[BoundThis]] 内部槽。设置自定义this值的示例:
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);对于对象,这在严格和非严格模式下是相同的。
现在,尝试提供一个原始值:
function f(){ console.log(this); } const myString = "s", g = f.bind(myString); g(); // Logs `String { "s" }`. f.call(myString); // Logs `String { "s" }`.在非严格模式下,基元被强制为其对象包装形式。它与调用
Object("s")或new String("s")时获得的对象类型相同。在严格模式下,您可以使用原语:"use strict"; function f(){ console.log(this); } const myString = "s", g = f.bind(myString); g(); // Logs `"s"`. f.call(myString); // Logs `"s"`.图书馆利用这些方法,例如jQuery 将
this设置为此处选择的 DOM 元素:$("button").click(function(){ console.log(this); // Logs the clicked button. });构造函数、类和
新使用
new运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,它调用 [[Construct]] 方法。如果函数是基本构造函数(即不是class extends...{...}),它会设置 thisArgument到从构造函数的原型创建的新对象。构造函数中this上设置的属性最终将出现在生成的实例对象上。this会隐式返回,除非您显式返回自己的非原始值。class是创建构造函数的新方法,在 ECMAScript 2015 中引入。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 }`.类定义隐式地处于严格模式中:
class A{ m1(){ return this; } m2(){ const m1 = this.m1; console.log(m1()); } } new A().m2(); // Logs `undefined`.超级H4>new行为的例外是class extends...{...},如上所述。派生类在调用时不会立即设置其 this 值;它们只有在通过一系列super调用到达基类后才会这样做(在没有自己的构造函数的情况下隐式发生)。不允许在调用super之前使用this。调用
super调用具有调用的词法范围(函数环境记录)的 this 值的超级构造函数。 GetThisValue 对于super调用有一个特殊的规则。它使用 BindThisValue 将this设置为该环境记录。class DerivedNew extends New{ constructor(a, a2){ // Using `this` before `super` results in a ReferenceError. super(a); this.p2 = a2; } } const n2 = new DerivedNew(1, 2); console.log(n2); // Logs `DerivedNew { p: 1, p2: 2 }`.5。评估类字段
ECMAScript 2022 中引入了实例字段和静态字段。
当评估
class时,ClassDefinitionEvaluation 为执行,修改运行执行上下文。对于每个 ClassElement:this指的是类本身,this引用实例。私有字段(例如
#x)和方法被添加到私有环境中。静态块目前是TC39 第 3 阶段提案。静态块的工作方式与静态字段和方法相同:其中的
this引用类本身。请注意,在方法和 getters/setters 中,
this的工作方式与普通函数属性中一样。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`.1:
(o.f)()等价于o.f();(f)()相当于f()。 这篇 2ality 文章 (已存档)。特别请参阅如何评估ParenthesizedExpression。2:它必须是MemberExpression em>,不能是属性,必须具有完全“eval”的[[ReferencedName]],并且必须是%eval%内在对象。
3:每当规范说“让 ref 成为评估 X 的结果”时,X 是您需要找到其求值步骤的某个表达式。例如,评估 MemberExpression 或 CallExpression 是 这些算法。其中一些会生成参考记录。
4:还有其他几种本机和主机方法允许提供 this 值,特别是
Array.prototype.map、Array.prototype.forEach 等接受 thisArg 作为第二个参数。任何人都可以创建自己的方法来更改this,例如(func, thisArg) => func.bind(thisArg)、(func, thisArg) => func。 call(thisArg)等。一如既往,MDN 提供了很棒的服务文档。只是为了好玩,用一些例子来测试你的理解
对于每个代码片段,回答以下问题:“标记行处
this的值是多少?为什么?”.要显示答案,请单击灰色框。
if(true){ console.log(this); // What is `this` here? }const obj = {}; function myFun(){ return { // What is `this` here? "is obj": this === obj, "is globalThis": this === globalThis }; } obj.method = myFun; console.log(obj.method());