“this”关键字如何工作,何时应使用?
我希望找到一个关于“this”关键字的作用以及如何正确使用它的清晰解释。
它似乎表现得很奇怪,我不完全理解为什么。
如何工作,何时应使用?this
我希望找到一个关于“this”关键字的作用以及如何正确使用它的清晰解释。
它似乎表现得很奇怪,我不完全理解为什么。
如何工作,何时应使用?this
这是
JavaScript 中的一个关键字,它是执行上下文的属性。它的主要用途是函数和构造函数。的规则非常简单(如果你坚持最佳实践)。this
this
ECMAScript 标准通过抽象操作(缩写为 AO)ResolveThisBinding 对此进行了定义:
[AO] ResolveThisBinding [...] 使用正在运行的执行上下文的词法环境确定关键字的绑定。[步骤]:
this
- Let envRec be GetThisEnvironment().
- 返回?envRec.GetThisBinding().
全局环境记录、模块环境记录和函数环境记录都有自己的 GetThis 绑定方法。
GetThisEnvironment AO 查找当前正在运行的执行上下文的 LexicalEnvironment,并查找最接近的上升环境记录(通过迭代访问其 [[OuterEnv]] 属性),该记录具有此绑定(即 HasThisBinding 返回 true)。此过程以三种环境记录类型之一结束。
的值通常取决于代码是否处于严格模式。this
GetThisBinding 的返回值反映了当前执行上下文的值,因此每当建立新的执行上下文时,都会解析为不同的值。修改当前执行上下文时,也会发生这种情况。以下小节列出了可能发生这种情况的五种情况。this
this
可以将代码示例放在 AST 资源管理器中,以便遵循规范详细信息。
这是在顶层评估的脚本代码,例如直接在:<script>
<script>
// Global context
console.log(this); // Logs global object.
setTimeout(function(){
console.log("Not global context");
});
</script>
在脚本的初始全局执行上下文中,评估会导致 GetThisBinding 执行以下步骤:this
GetThisBinding具体方法的全球环境记录环境[...][做这个]:
- Return envRec.[[GlobalThisValue]]。
全局环境记录的 [[GlobalThisValue]] 属性始终设置为主机定义的全局对象,该对象可通过 globalThis
(在 Web 上,在 Node 上.js;MDN上的文档)。按照 InitializeHostDefinedRealm 的步骤,了解 [[GlobalThisValue]] 属性是如何形成的。window
global
模块已在 ECMAScript 2015 中引入。
这适用于模块,例如,当直接在 a 中时,而不是简单的 。<script type="module">
<script>
在模块的初始全局执行上下文中,评估会导致 GetThisBinding 执行以下步骤:this
该模块环境记录的具体方法 [...][做这个]:
- 未定义返回。
在模块中,的值始终位于全局上下文中。模块隐式处于严格模式。this
undefined
有两种类型的呼叫:直接呼叫和间接呼叫。这种区别自 ECMAScript 第 5 版以来就存在。eval
eval
eval(
);
(eval)(
);
((eval))(
);
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 – Chapter 2: Strict Mode (archived),了解何时可以使用间接调用。eval()
执行Val 执行代码。它创建一个新的声明性环境记录作为其词法环境,这是 GetThisEnvironment 获取值的位置。eval
this
然后,如果出现在代码中,则调用 GetThis 环境找到的环境记录的 GetThisBinding 方法,并返回其值。this
eval
创建的声明性环境记录取决于调用是直接的还是间接的:eval
这意味着:
this
eval
this
globalThis
新功能
呢?— new Function
与 类似,但它不会立即调用代码;它创建一个函数。此绑定不适用于此处的任何位置,除非调用函数时,该函数工作正常,如下一小节所述。eval
调用函数时,将发生输入函数代码的情况。
有四类语法可用于调用函数。
实际的函数调用发生在调用AO上,该调用是使用从上下文中确定的 thisValue 调用的;此参数在一长串与调用相关的调用中传递。调用调用函数的 [[调用]] 内部插槽。这将调用 PrepareForOrdinaryCall,其中创建了一个新的函数环境记录:
函数环境记录是声明性环境记录,用于表示函数的顶级作用域,如果该函数不是 ArrowFunction,则提供绑定。如果一个函数不是 ArrowFunction 函数和引用,它的函数环境记录也包含用于从函数内部执行方法调用的状态。
this
super
super
此外,在函数环境记录中还有 [[ThisValue]] 字段:
这是用于函数调用的值。
this
NewFunctionEnvironment 调用还设置函数环境的 [[ThisBindingStatus]] 属性。
[[调用]]也调用普通调用BindThis,其中适当的此参数是根据以下因素确定的:
确定后,对新创建的函数环境记录的 BindThisValue 方法的最终调用实际上会将 [[ThisValue]] 字段设置为 thisArgument。
最后,正是这个字段是函数环境记录的 GetThisBinding AO 从以下位置获取值的位置:this
GetThisBinding 函数的具体方法 环境记录 envRec [...][做这个]:
[...]
3. 返回环境。[[此值]]。
同样,如何确定此值取决于许多因素;这只是一个一般的概述。有了这个技术背景,让我们来看看所有的具体例子。
当计算箭头函数时,函数对象的 [[ThisMode]] 内部槽在普通函数创建中设置为“词法”。
在普通呼叫BindThis,它采用函数F:
- 让这个模式成为F。[[此模式]]。
- 如果此模式是词法模式,则返回 NormalCompletion()。[...]
undefined
这只是意味着绑定此的算法的其余部分被跳过。箭头函数不绑定自己的此值。
那么,箭头函数内部是什么呢?回顾 ResolveThisBinding 和 GetThisEnvironment,HasThisBinding 方法显式返回 false。this
HasThis绑定功能的具体方法 环境记录环境 [...][做这个]:
- 如果 envRec.[[ThisBindingStatus]] 是词法,返回 false;否则,返回 true。
因此,外部环境被反复查找。该过程将在具有此绑定的三个环境之一中结束。
这只是意味着,在箭头函数体中,这
来自箭头函数的词法范围,或者换句话说(来自箭头函数与函数声明/表达式:它们是等效的/可交换的吗?
箭头函数没有自己的 [...] 绑定。相反,[此标识符]在词法范围内解析,就像任何其他变量一样。这意味着在箭头函数内部,[引用]在环境中定义箭头函数的[值](即箭头函数的“外部”)。
this
this
this
在普通函数(,方法)中,由函数的调用方式决定。function
this
这就是这些“语法变体”派上用场的地方。
考虑这个包含函数的对象:
const refObj = {
func: function(){
console.log(this);
}
};
或者:
const refObj = {
func(){
console.log(this);
}
};
在以下任何函数调用中,其中的值为 。1 个this
func
refObj
refObj.func()
refObj["func"]()
refObj?.func()
refObj.func?.()
refObj.func``
如果被调用的函数在语法上是基对象的属性,则此基函数将是调用的“引用”,在通常情况下,该调用的值将是 。这可以通过上面链接的评估步骤来解释;例如,在 (or) 中,CallMemberExpression 是整个表达式 ,它由 MemberExpression 和 Arguments 组成。this
refObj.func()
refObj["func"]()
refObj.func()
refObj.func
()
但是,也扮演三个角色,每个角色:refObj.func
refObj
refObj.func
因为值是可调用的函数对象;相应的引用用于确定绑定。this
可选的链式和标记模板示例的工作方式非常相似:基本上,引用是 之前 、之前或 之前的所有内容。?.()
``
()
EvaluateCall 使用该引用的 IsPropertyReference 来确定它是否是语法上对象的属性。它试图获取引用的 [[Base]] 属性(例如,当应用于 ; 或应用于 时)。如果它被编写为属性,则 GetThisValue 将获取此 [[Base]] 属性并将其用作 this 值。refObj
refObj.func
foo.bar
foo.bar.baz
注意:Getters / Setters 的工作方式与方法相同,关于 .简单属性不影响执行上下文,例如,此处位于全局范围内:this
this
const o = {
a: 1,
b: this.a, // Is `globalThis.a`.
[this.a]: 2 // Refers to `globalThis.a`.
};
模式和
没有基引用的调用通常是不作为属性调用的函数。例如:
func(); // As opposed to `refObj.func();`.
在传递或分配方法或使用逗号运算符时,也会发生这种情况。这就是参考记录和值之间的差异相关的地方。
注意函数:遵循规范,您会注意到只能返回函数对象(Value)本身,而不能返回参考记录。因此,基本引用将丢失。j
j
refObj
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.
EvaluateCall 调用此处的 this 值未定义。这在普通呼叫BindThis(F:函数对象;thisArgument: thisValue 传递给 Call):
- 让这个模式成为F。[[此模式]]。
[...]
- 如果此模式是严格的,则让此值成为此参数。
- 埃尔默
[...]
注意:步骤 5 将 的实际值设置为严格模式下提供的 thisArgument — 在本例中。在“草率模式”中,未定义或为 null this 参数会导致成为全局 this 值。this
undefined
this
如果 IsPropertyReference 返回 false,则 EvaluateCall 将执行以下步骤:
- 让 refEnv 成为 ref。[[基地]]。
- 断言:refEnv 是环境记录。
- Let thisValue be refEnv.WithBaseObject().
这就是未定义的 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 和基元OrdinaryCallBind的步骤5的另一个结果,结合步骤6.2(规范中的6.b),是一个基元这个值仅在“草率”模式下被强制到对象。
为了检查这一点,让我们介绍 this 值的另一个源:重写 this 绑定的三个方法:4
Function.prototype.apply(thisArg, argArray)
Function.prototype.
{call
,bind
} (thisArg, ...args)
.bind
创建一个绑定函数,其此绑定设置为 thisArg 并且无法再次更改。.call
和 .apply
会立即调用该函数,并将 this 绑定设置为 thisArg。
.call
并直接映射到调用,使用指定的 thisArg。 使用 BoundFunctionCreate 创建绑定函数。它们有自己的 [[Call]] 方法,用于查找函数对象的 [[BoundThis]] 内部槽。.apply
.bind
设置自定义此值的示例:
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 将 设置为此处选择的 DOM 元素:this
$("button").click(function(){
console.log(this); // Logs the clicked button.
});
新的
使用运算符将函数作为构造函数调用时,EvaluateNew 调用 Construct,后者调用 [[Construct]] 方法。如果函数是基构造函数(即不是 ......),则它将 thisArgument 设置为从构造函数的原型创建的新对象。在构造函数中设置的属性将最终出现在生成的实例对象上。 隐式返回,除非您显式返回自己的非基元值。new
class extends
{
}
this
this
类
是一种创建构造函数的新方法,在 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`.
super
行为的例外是 ......,如上所述。派生类在调用时不会立即设置其 this 值;它们仅在通过一系列调用到达基类时才这样做(在没有自己的的情况下隐式发生)。不允许在呼叫前使用。new
class extends
{
}
super
constructor
this
super
调用 super
调用具有调用的词法作用域(函数环境记录)的此值的超级构造函数。GetThisValue 对调用有特殊规则。它使用 BindThisValue 设置为该环境记录。super
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 }`.
实例字段和静态字段在 ECMAScript 2022 中引入。
计算 时,将执行类定义评估,并修改正在运行的执行上下文。对于每个类元素:class
this
this
私有字段(例如 )和方法被添加到私有环境中。#x
静态块目前是 TC39 第 3 阶段的提案。静态块的工作方式与静态字段和方法相同:它们内部引用类本身。this
请注意,在方法和 getters/setter 中,其工作方式与在正常函数属性中一样。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:相当于; 等效于 。这在这篇2ality文章(存档)中进行了解释。特别要了解如何计算括号表达式。(o.f)()
o.f()
(f)()
f()
2:它必须是 MemberExpression,不能是属性,必须具有完全“eval”的 [[ReferencedName]],并且必须是 %eval% 内部对象。
3:每当规范说“让 ref 成为计算 X 的结果”时,X 就是你需要找到其评估步骤的某个表达式。例如,评估成员表达式或 CallExpression 是这些算法之一的结果。其中一些会产生参考记录。
4:还有其他几个本机和宿主方法允许提供此值,特别是 、等,它们接受 thisArg 作为其第二个参数。任何人都可以自己制作方法来改变,如,等。与往常一样,MDN提供了出色的文档。Array.prototype.map
Array.prototype.forEach
this
(func, thisArg) => func.bind(thisArg)
(func, thisArg) => func.call(thisArg)
对于每个代码片段,回答以下问题:“在标记行处,此
值是多少?为什么?
要显示答案,请单击灰色框。
if(true){
console.log(this); // What is `this` here?
}
globalThis
.标记的行在初始全局执行上下文中进行评估。
const obj = {};
function myFun(){
return { // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
obj.method = myFun;
console.log(obj.method());
obj
.当调用一个函数作为对象的属性时,它被调用,并将 this 绑定集到引用的基,即 。obj.method
obj
const obj = {
myMethod: function(){
return { // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
},
myFun = obj.myMethod;
console.log(myFun());
globalThis
.由于函数值 / 不是从对象中调用的,因此作为属性,此绑定将为 。这与Python不同,在Python中,访问方法()会创建绑定的方法对象。myFun
obj.myMethod
globalThis
obj.myMethod
const obj = {
myFun: () => ({ // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
})
};
console.log(obj.myFun());
globalThis
.箭头函数不会创建自己的此绑定。词法作用域与初始全局作用域相同,也是如此。this
globalThis
function myFun(){
console.log(this); // What is `this` here?
}
const obj = {
myMethod: function(){
eval("myFun()");
}
};
obj.myMethod();
globalThis
.评估直接评估调用时,为 。但是,在评估代码中,不会从对象中调用,因此 this 绑定设置为全局对象。this
obj
myFun
function myFun() {
// What is `this` here?
return {
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
const obj = {};
console.log(myFun.call(obj));
obj
.该行调用特殊的内置函数,该函数接受作为第一个参数。myFun.call(obj);
Function.prototype.call
thisArg
class MyCls{
arrow = () => ({ // What is `this` here?
"is MyCls": this === MyCls,
"is globalThis": this === globalThis,
"is instance": this instanceof MyCls
});
}
console.log(new MyCls().arrow());
它是 的实例。箭头函数不会更改此绑定,因此它来自词法范围。因此,这与上面提到的类字段完全相同,例如 。请尝试将其更改为 。你得到你期望的结果吗?
MyCls
a = this;
static arrow
与其他语言相比,该关键字在JavaScript中的行为不同。在面向对象的语言中,关键字引用类的当前实例。在 JavaScript 中,的值由函数 (context.function()
) 的调用上下文和调用位置确定。this
this
this
1. 在全球上下文中使用时
在全局上下文中使用时,它被绑定到全局对象(在浏览器中)this
window
document.write(this); //[object 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
即使您将函数作为方法显式添加到对象中,它仍然遵循上述规则,即仍然指向直接父对象。this
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. 调用无上下文功能时
当您使用在没有任何上下文的情况下调用的内部函数(即不在任何对象上)时,它被绑定到全局对象(在浏览器中)(即使该函数是在对象内部定义的)。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() + "<br />"); //[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() + "<br />"); //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() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //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() + "<br />"); //[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()+"<br />");//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. 内部调用()、apply() 和 bind() 函数
Function.prototype
this
fun.apply(obj1 [, argsArray])
设置为 内部 的值,并调用 传递的元素 作为其参数。obj1
this
fun()
fun()
argsArray
fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 设置为 inside 的值,调用传递作为其参数。obj1
this
fun()
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)+"<br />"); //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]) + "<br />"); //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()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. 此
内部事件处理程序
this
addeventListener
onclick
this
<button onclick="...this..." >
this
window
attachEvent
我建议在JSFiddle中更好地尝试一下。
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
8.这在
ES6中箭头功能
在箭头函数中,将像公共变量一样运行:它将从其词法范围继承。定义箭头函数的 函数将是箭头函数的 。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