Javascript “this”关键字是如何工作的?

Javascript “this”关键字是如何工作的?,javascript,this,Javascript,This,我注意到,对于this关键字是什么以及它如何在堆栈溢出站点的JavaScript中正确和错误地使用,似乎没有一个明确的解释 我目睹了它的一些非常奇怪的行为,但我不明白为什么会发生这种情况 这是如何工作的,何时使用?javascript中的每个执行上下文都有一个this参数,该参数由以下参数设置: 如何调用函数,包括作为对象方法、调用和应用的使用、新函数的使用 绑定的使用 从词汇上讲,对于arrow函数,它们采用外部执行上下文的这种形式 代码处于严格模式还是非严格模式 是否使用 可以使用func.

我注意到,对于this关键字是什么以及它如何在堆栈溢出站点的JavaScript中正确和错误地使用,似乎没有一个明确的解释

我目睹了它的一些非常奇怪的行为,但我不明白为什么会发生这种情况

这是如何工作的,何时使用?

javascript中的每个执行上下文都有一个this参数,该参数由以下参数设置:

如何调用函数,包括作为对象方法、调用和应用的使用、新函数的使用 绑定的使用 从词汇上讲,对于arrow函数,它们采用外部执行上下文的这种形式 代码处于严格模式还是非严格模式 是否使用 可以使用func.call、func.apply或func.bind设置此值

默认情况下,最让初学者困惑的是,当在DOM元素上引发事件后调用侦听器时,函数的this值就是DOM元素

jQuery使得使用jQuery.proxy进行更改变得非常简单。

是JavaScript中的一个关键字,用于获取代码执行的当前“上下文”。 它主要用于函数和构造函数

我建议先读一读他的文章。 这是对JavaScript中的范围链和范围链概念的极好、友好的介绍。 如果您坚持最佳实践,那么这方面的规则非常简单

规范中对此的技术说明 通过抽象操作定义:

抽象操作ResolveThisBinding[…]使用的LexicalEnvironment确定关键字this的绑定。 调用时,它将执行以下步骤:

让envRec去吧。 回来envRec.GetThisBinding。 ,并且每个都有自己的GetThisBinding方法

抽象操作查找当前的LexicalEnvironment,并通过迭代访问其[[OuterEnv]]属性来查找最近的上升环境记录,该属性具有this绑定,即HasThisBinding返回true。 此过程以三种环境记录类型之一结束

这个值通常取决于代码是否在

GetThisBinding的返回值反映了当前执行上下文的值,因此每当建立新的执行上下文时,它都会解析为一个不同的值。 当修改当前执行上下文时也会发生这种情况。 以下小节列出了可能发生这种情况的五种情况

您可以将代码示例与规范详细信息一起放入以遵循

1.脚本中的全局执行上下文 这是在顶层评估的脚本代码,例如直接在:

//全球环境 console.logthis;//记录全局对象。 setTimeoutfunction{ console.logNot全局上下文; }; 在脚本的初始全局执行上下文中,对此进行评估将导致采取以下步骤:

全局环境记录envRec[…]的GetThisBinding具体方法在调用时执行以下步骤:

返回envRec。[[GlobalThisValue]]。 全局环境记录的[[GlobalThisValue]]属性始终设置为定义的主机,可通过Web上的窗口、Node.js上的全局访问该主机。 按照的步骤学习[[GlobalThisValue]]属性是如何产生的

2.中的全局执行上下文 ECMAScript 2015中引入了模块

这适用于模块,例如,当模块直接位于内部时,而不是简单的

在模块的初始全局执行上下文中,对此进行评估将导致采取以下步骤:

模块环境记录[…]的GetThisBinding具体方法在调用时执行以下步骤:

返回未定义。 没错:在模块中,这个值在全局上下文中总是未定义的

function f1()
{
   return this;
}
document.write(f1());  //[object Window]
模块隐式地位于中

3.输入代码 有两种评估调用:和。 这种区别自ECMAScript第5版以来就存在

直接评估呼叫通常看起来像评估…;或评估…;或评估…;,等等 只有当调用表达式符合一个狭窄的模式时,它才是直接的 间接eval调用涉及以任何其他方式调用函数引用eval。 它可能是eval?…,…,eval…,window.eval…,eval.call…,等等。 给定常量别名eval1=eval;window.aliasEval2=eval;,它也将是别名eval1…,别名eval2…。 分别给出常数originalEval=eval;window.eval=x=>originalEvalx;,调用eval…也是间接的。 请参阅和,了解何时可以使用间接评估调用

执行评估代码。 它创建了一个新的作为其词典环境,从中获取该值

然后,如果这出现在eval代码中,将调用找到的环境记录的GetThisBinding方法并返回其值

所创建的值取决于eval调用是直接调用还是间接调用:

在直接评估中,它将基于t 他现在的环境很好。 在间接评估中,它将基于执行间接评估的[[GlobalEnv]]属性a。 这意味着:

在直接评估中,此值的值不变;它来自于称为eval的词法范围。 在间接评估中,此值是全局对象globalThis。 新功能呢? —  类似于eval,但它不会立即调用代码;它创建了一个函数。 A此绑定不适用于此处的任何地方,除非调用函数,该函数正常工作,如下一小节所述

4.输入代码 调用函数时会输入函数代码

调用函数有四类语法

对这三个对象执行抽象操作:3 并对这一个执行:3 实际的函数调用发生在抽象操作中,该操作使用上下文确定的thisValue进行调用;此参数在一长串与调用相关的调用中传递。 调用函数的内部插槽。 这将调用创建新文件的位置:

函数环境记录是一种声明性环境记录,用于表示函数的顶级作用域,如果函数不是ArrowFunction,则提供此绑定的声明性环境记录。 如果函数不是ArrowFunction函数并引用super,则其函数环境记录还包含用于从函数内执行super方法调用的状态

此外,函数环境记录中还有[[ThisValue]]字段:

这是用于此函数调用的This值

该调用还设置函数环境的[[ThisBindingStatus]]属性

还调用,其中相应的thisArgument是根据以下内容确定的:

原始参考, 函数的类型,以及 无论代码是否在。 一旦确定,对新创建的函数环境记录的方法的最后调用实际上会将[[ThisValue]]字段设置为thisArgument

最后,这个字段就是抽象操作从中获取该值的位置:

函数环境记录envRec[…]的GetThisBinding具体方法在调用时执行以下步骤:

[……] 3.返回envRec。[[ThisValue]]

同样,如何准确地确定该值取决于许多因素;这只是一个总体概述。 有了这个技术背景,让我们来看看所有的具体例子

在计算时,函数对象的[[ThisMode]]内部插槽在中设置为“词法”

At,它采用函数F:

设thisMode为F.[thisMode]]。 如果此模式是词法模式,则返回NormalCompletionundefined。 […] 这就意味着,绑定它的算法的其余部分被跳过了。 arrow函数不会将自己的函数绑定到此值

那么,箭头函数中的这个是什么呢? 回首过去,我们看到了

函数环境记录envRec[…]的HasThisBinding具体方法在调用时执行以下步骤:

如果envRec。[[ThisBindingStatus]]是词法性的,则返回false;否则,返回true。 因此,外部环境被迭代地查找。 该过程将在具有此绑定的三个环境中的一个环境中结束

这仅仅意味着这是由箭头函数体的词汇决定的,或者换句话说,是由:

箭头函数没有自己的此[…]绑定。 相反,[此标识符]与任何其他变量一样在词法范围内解析。 这意味着在箭头函数内部,这[指]是指箭头函数在环境中定义的[此值],即箭头函数的“外部”

作用 在普通函数中,这取决于函数的调用方式

这就是这些“语法变体”派上用场的地方

考虑这个包含函数的对象:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function
    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>
常数REOBJ={ func:函数{ console.logthis; } }; 或者:

常数REOBJ={ func{ console.logthis; } }; 在以下任何函数调用中,func中的this值都将是REFBJ.1

refObj.func REFBJ[func] refObj?.func 重新定义功能?。 refObj.func`` 如果被调用函数在语法上是基对象的属性,那么这个基将是调用的“引用”,在通常情况下,它将是这个对象的值。 这可以通过上面链接的评估步骤来解释;例如,在refObj.func或refObj[func]中,是整个表达式refObj.func,它包括refObj.func和

但是,refObj.func和refObj也分别扮演三个角色:

它们都是表情, 他们都是推荐人,而且 它们都是价值观。 refObj.func作为值是可调用的函数对象;相应的引用用于确定此绑定的类型

可选的 链接和标记模板示例的工作原理非常相似:基本上,引用是?、``之前或之前的所有内容

使用该引用确定它在语法上是否是对象的属性。 当应用于refObj.func时,它试图获取引用的[[Base]]属性,例如refObj;或应用于foo.bar.baz时的foo.bar。 如果将其写入属性,则将获取此[[Base]]属性并将其用作this值

注意:关于这一点,工作方式与方法相同

无上下文函数调用、严格模式和 无上下文调用通常是一种调用,其中函数在语法上不是对象的属性;例如:

func;//与“refObj.func;”相反。 传递方法时也会发生这种情况:

常数g=f=>f;//看见“f”处没有上下文。 grefObj.func;//实际上与'f=refObj.func;'相同。 调用thisValue为undefined的函数。 这使得F不同,F是函数对象,thisArgument是传递给以下对象的thisValue:

设thisMode为F.[thisMode]]。 [……]

如果thisMode是strict,则将thisValue设为thisArgument。 其他的 如果此参数未定义或为null,则 让globalEnv被称为alm。[[globalEnv]]。 […] 将此值设为globalEnv。[[GlobalThisValue]]。 其他的 让这个价值成为现实吧!这个论点。 注意:生成包装器对象[…]。 [……]

注意:步骤5在严格模式下将this的实际值设置为提供的thisArgument — 在本例中未定义。 在“sloppy模式”中,未定义或为null的this参数将导致this成为全局this值

如果返回false,则执行以下步骤:

让refEnv为ref.[Base]]。 断言:refEnv是一个环境记录。 将此值设为refEnv.WithBaseObject。 这就是未定义的thisValue可能来自的位置:refEnv。始终未定义,语句中除外。 在这种情况下,thisValue将是绑定对象

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj
还有一种方法可以控制绑定行为

总而言之,到目前为止:

函数f1{ console.logthis; } 功能f2{ console.logthis; } 功能f3{ console.logthis; } 常数o={ f1, f2, [符号.不可分割]:{ f2:对 } }; f1;//日志“globalThis”。 维索{ f1;//记录“o”。 f2;/`f2`是不可分的,因此此日志记录了`globalThis`。 f3;//'f3'不在'o'上,因此此日志记录'globalThis'。 } 以及:

严格使用; 函数f{ console.logthis; } f、 //日志“未定义”。 //严格模式代码中不允许使用`with`语句。 请注意,在计算时,在何处定义正常函数并不重要

、thisArg和基元 的步骤5以及规范中的步骤6.2 6.b的另一个结果是,此值的原语仅在“sloppy”模式下强制为对象

为了检验这一点,让我们介绍this值的另一个来源:覆盖this绑定的三个方法:4

Function.prototype.applythisArg,argArray 功能。原型。{call,bind}thisArg,…args 创建绑定函数,其此绑定设置为thisArg,不能再次更改。 并立即调用该函数,将该绑定设置为thisArg

.call和.apply映射直接应用于,使用指定的thisArg。 .bind使用创建绑定函数。 它们有自己的查找函数对象的[[BoundThis]]内部插槽的窗口

设置自定义此值的示例:

函数f{ console.logthis; } 常量myObj={}, g=f.bindmyObj, h=m=>m; //所有这些日志都是“myObj”。 G f、 bindmyObj; f、 callmyObj; 汞; 对于对象,这在严格模式和非严格模式下是相同的

现在,尝试提供一个基本值:

函数f{ console.logthis; } const myString=s, g=f.bindmyString; g、 //记录'String{s}'。 f、 callmyString;//记录'String{s}'。 在非严格模式下,原语被强制为其对象包装形式。 它与调用对象或新字符串时得到的对象类型相同。 在严格模式下,可以使用基本体:

严格使用; 函数f{ console.logthis; } const myString=s, g=f.bindmyString; g、 //日志's`。 f、 callmyString;//日志's`。 库使用这些方法,例如jQuery将此设置为此处选择的DOM元素:

$button.clickfunction{ console.logthis;//记录单击的按钮。 }; 构造器,以及 当使用新运算符作为构造函数调用函数时,调用,这将调用。 如果函数是一个基本构造函数,即不是一个扩展了…{…}的类,它会将此参数设置为从构造函数的原型创建的新对象。 在构造函数中为此设置的属性将在生成的实例对象上结束。 这是隐式返回的,除非显式返回自己的非原语值

是一种新的创建构造函数的方法,在ECMAScript 2015中引入

函数Olda{ 这个p=a; } 常数o=新的旧的1; 安慰 标志;//记录'Old{p:1}'。 新类{ 构造器{ 这个p=a; } } 常数n=新的1; console.logn;//记录'New{p:1}'。 类定义隐式地包含在:

甲级{ m1{ 归还这个; } 平方米{ 常数m1=this.m1; console.logm1; } } 新A.m2;//日志“未定义”。 如上所述,new的行为的例外是类扩展…{…}。 派生类不会在调用时立即设置它们的this值;它们只在超级调用隐式发生且没有自己的构造函数之后才这样做。 不允许在调用super之前使用此选项

调用使用调用的函数环境记录中的词法范围值调用超级构造函数。 对超级呼叫有特殊规则。 它用于将此设置为该环境记录

派生的类New扩展了New{ 构造器,a2{ //在“super”之前使用“this”会导致引用错误。 supera; 这是p2=a2; } } 常数n2=新派生的new1,2; console.logn2;//日志'DerivedNew{p:1,p2:2}'。 5.评估类字段 有实例类字段和静态类字段。 这些是ECMAScript 2022中引入的已完成提案

计算类时,将执行,修改。 对于每个:

如果一个字段是静态的,那么它指的是类本身, 如果一个字段不是静态的,那么它引用实例。 私有字段(如x和方法)添加到私有环境中

目前是一个。 静态块的工作原理与静态字段和方法相同:其中的静态块指的是类本身

请注意,在方法和getter/setter中,这与普通函数属性中的工作方式相同

课堂演示{ a=这个; b{ 归还这个; } 静态c=此; 静态d{ 归还这个; } //也可以使用getter、setter和private修饰符。 } const demo=新的demo; console.logdemo.a、demo.b;//它们都记录“demo”。 console.logDemo.c、Demo.d;//它们都记录“Demo”。 1:o.f与o.f完全相等;f与f完全等价。 这一点在本文中进行了解释。 特别是看

2:它必须是,不能是属性,必须具有完全为eval的[[ReferencedName]],并且必须是%eval%内部对象

3:当规范说“让ref是计算X的结果”时,X是一些表达式,您需要为其找到计算步骤。 例如,评估or是以下操作之一的结果。 他们中的一些人导致了一场灾难

4:还有一些其他本机和主机方法允许提供this值,特别是Array.prototype.map、Array.prototype.forEach等,它们接受thisArg作为第二个参数。 任何人都可以使用自己的方法来修改它,如func、thisArg=>func.bindthisArg、func、thisArg=>func.callthisArg等。 和往常一样,它提供了很好的文档

只是为了好玩,用一些例子来测试你的理解 对于每个代码段,回答以下问题:“在标记的行中,这个值是多少?为什么?”

要显示答案,请单击灰色框

伊夫鲁{ console.logthis;//这里的'this'是什么? } 环球旅行社。在初始全局执行上下文中计算标记行

常量obj={}; 功能myFun{ return{//这里的'this'是什么? 是obj:this==obj, 是globalThis:this===globalThis }; } obj.method=myFun; console.logobj.method;
谁来帮忙?javascript中“this”最令人困惑的是,它通常不链接到您的对象,而是链接到当前的执行范围-这可能不是它的工作方式,但对我来说总是这样-有关范围的完整解释,请参阅本文。每个函数都有自己的作用域,因为JS中的所有内容都是一个对象,所以即使是函数也可以使用它将一些值存储到自身中。OOP 101告诉我们,这只适用于对象的实例。因此,每次执行一个函数时,该函数的一个新实例都具有新的含义

大多数人在尝试使用匿名闭包函数时会感到困惑,例如:

(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // uh oh!! possibly undefined }); })(2); 因此,在这里,在每一个内部,这并不包含你期望它从上面得到的值。因此,为了克服这个非双关语的问题,开发人员可以:

this.value = value; (function(value) { var self = this; // small change self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // phew!! == 2 }); })(2);
试试看;你会开始喜欢这种编程模式的

丹尼尔,精彩的解释!在事件处理程序的情况下,这个执行上下文指针的好列表上有几个字

换句话说,JavaScript中的这一点指向运行当前函数的对象或其执行上下文,并且它始终是只读的,您无论如何都无法设置它。这样的尝试将以“分配中的左侧无效”消息结束

对于事件处理程序:内联事件处理程序,例如,重写之前和之前附加的任何其他处理程序,因此要小心,最好不要使用内联事件委派。 多亏了Zara laverdyan通过一场持不同意见的辩论启发我列出了以下例子:

el.onclick=foo;//在foo-obj中 el.onclick=函数{this.style.color='fff';}//obj el.onclick=doSomething中的函数{doSomething;}//- 窗 el.addEventListener'click',foo,false//在foo-obj中 el.attachEvent'onclick,函数{//this}//window,所有 遵守IE: //obj //在foo-window中,但您可以 与其他语言相比,this关键字在JavaScript中的行为有所不同。在面向对象语言中,this关键字引用类的当前实例。在JavaScript中,其值由function context.function的调用上下文及其调用位置决定

一,。在全局上下文中使用时

在全局上下文中使用时,它将绑定到浏览器中的全局对象窗口

document.write(this);  //[object Window]

当您在全局上下文中定义的函数中使用它时,它仍然绑定到全局对象,因为函数实际上是全局上下文的方法

function f1()
{
   return this;
}
document.write(f1());  //[object Window]
上面f1是一个全局对象的方法。因此,我们也可以对window对象调用它,如下所示:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]
二,。在对象方法内部使用时

在对象方法中使用此关键字时,它将绑定到直接封闭对象

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj
在上面,我用双引号引了immediate这个词。这是为了说明,如果将对象嵌套在另一个对象中,则该对象将绑定到直接父对象

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使将函数显式地作为方法添加到对象中,它仍然遵循上述规则,也就是说,这仍然指向直接的父对象

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
三,。调用无上下文函数时

当您使用此在没有任何上下文(即不在任何对象上)的情况下调用的内部函数时,它将绑定到Browser中的全局对象窗口,即使该函数是在对象内部定义的

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 
尝试所有功能

我们也可以在函数中尝试以上几点。但也存在一些差异

上面我们使用对象文字符号向对象添加了成员。我们可以使用此函数向函数中添加成员。来指定它们。 对象文字符号创建了一个我们可以立即使用的对象实例。对于函数,我们可能需要首先使用new操作符创建它的实例。 同样,在对象文字方法中,我们可以使用点运算符向已定义的对象显式添加成员。这只会添加到特定实例中。但是,我已经向函数原型添加了变量,以便它反映在函数的所有实例中。 下面我尝试了所有我们使用Object和上面的方法,但是首先创建函数,而不是直接编写对象

/********************************************************************* 
  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
五,。在原型链上定义的函数内使用时

如果该方法位于对象的原型链上,则该方法内部引用调用该方法的对象,就好像该方法是在对象上定义的一样

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   
六,。内部调用、应用和绑定函数

所有这些方法都是在Function.prototype上定义的。 这些方法允许编写一次函数并在不同的上下文中调用它。换句话说,它们允许指定函数执行时使用的值。当调用原始函数时,它们也会将任何参数传递给原始函数。 fun.applyobj1[,argsArray]将obj1设置为该内部fun的值,并调用argsArray的fun传递元素作为其参数。 fun.callobj1[,arg1[,arg2[,arg3[,…]]]]]-将obj1设置为此内部fun的值,并调用通过arg1,arg2,arg3。。。作为它的论据。 fun.bindobj1[,arg1[,arg2[,arg3[,…]]]]]-返回对函数fun的引用,将此内部fun绑定到obj1,并将fun的参数绑定到指定的参数arg1,arg2,arg3,。。。。 到目前为止,apply、call和bind之间的区别肯定已经很明显了。apply允许指定参数作为类似数组的对象运行,即具有数字长度属性和相应非负整数属性的对象。而调用允许直接指定函数的参数。apply和call都会在指定的上下文中使用指定的参数立即调用函数。另一方面,bind只返回绑定到指定this值和参数的函数。我们可以通过将这个返回函数分配给一个变量来捕获它的引用,以后我们可以随时调用它。 八,。这是ES6中的箭头函数

在arrow函数中,它的行为类似于公共变量:它将从其词法范围继承。函数的this(其中定义了arrow函数)将是arrow函数的this

因此,这与以下行为相同:

(function(){}).bind(this)
请参阅以下代码:

常量globalArrowFunction==>{ 归还这个; }; console.logglobalArrowFunction//窗 常量上下文对象={ 方法1:=>{返回此}, 方法2:功能{ return=>{returnthis}; } }; console.logcontextObject.method1//窗 const contextLessFunction=contextObject.method1; console.logcontextLessFunction//窗 console.logcontextObject.method2//contextObject const innerArrowFunction=contextObject.method2; console.loginnerarrow函数//上下文对象 这在JavaScript中总是指正在执行的函数的“所有者”

如果未定义显式所有者,则引用最顶层的所有者,即窗口对象

所以如果我做了

function someKindOfFunction() {
   this.style = 'foo';
}
element.onclick=somekindoff函数

这将引用元素对象。但是要小心,很多人都会犯这个错误

在后一种情况下,只引用函数,而不是将其交给元素。因此,这将引用窗口对象。

这是JavaScript中被误解的概念之一,因为它的行为在不同的地方几乎没有什么不同。简单地说,这是指我们当前正在执行的函数的所有者

这有助于获得当前对象,即我们使用的执行上下文。如果您了解当前函数是在哪个对象中执行的,那么您就可以很容易地理解这是什么

上面我们创建了3个同名“val”的变量。一个在全局上下文中,一个在obj内部,另一个在obj的innerMethod内部。JavaScript通过从本地到全局向上扩展作用域链来解析特定上下文中的标识符

很少有地方可以区分这一点

调用对象的方法 当执行line1时,JavaScript为函数调用建立一个执行上下文EC,将其设置为上一次调用之前的对象所引用的对象。。因此,在最后一行中,您可以理解a是在全局上下文(即窗口)中执行的

带构造函数 这可用于引用正在创建的对象

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
当执行new Person时,将创建一个全新的对象。将调用Person并将其设置为引用该新对象

函数调用 如果我们错过了新的关键字,这指的是它能找到的最全局的上下文

使用事件处理程序 如果事件处理程序是内联的,则它引用全局对象

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>
通过JavaScript添加事件处理程序时,它引用生成事件的DOM元素

您还可以使用.apply.call和.bind操作上下文 jqueryproxy是另一种方法,您可以使用它来确保函数中的值符合您的要求。检查 这是什么 简单函数调用 考虑以下功能:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function
    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>
请注意,我们是在正常模式下运行的,即不使用严格模式

在浏览器中运行时,其值将作为窗口记录。这是因为window是web浏览器作用域中的全局变量

如果您在node.js这样的环境中运行这段代码,这将引用应用程序中的全局变量

现在,如果我们通过添加语句use strict在严格模式下运行它;在函数声明的开头,这将不再引用任何环境中的全局变量。这样做是为了避免严格模式下的混乱。在本例中,这将只是日志未定义,因为这就是它,它没有定义

在下面的例子中,我们将看到如何操纵这个值

对对象调用函数 有不同的方法可以做到这一点。如果您在Javascript中调用了本机方法,比如forEach和slice,那么您应该已经知道,在这种情况下,this变量指的是调用该函数的对象注意,在Javascript中,几乎所有东西都是对象,包括数组和函数。以下面的代码为例

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged
如果对象包含包含函数的属性,则该属性称为方法。调用此方法时,将始终将此变量设置为与其关联的对象。严格模式和非严格模式都是如此

请注意,如果在另一个变量中存储或复制了一个方法,则对该方法的引用将不再保留在新变量中。例如:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>
考虑一个更普遍的实际情况:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
新关键字 考虑Javascript中的构造函数:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
这是怎么回事?好吧,让我们看看当我们使用新关键字时会发生什么

使用new关键字调用函数将立即初始化Person类型的对象。 此对象的构造函数已将其构造函数设置为Person。另外,请注意typeof awal将仅返回对象。 这个新对象将被指定为Person.prototype的原型。这意味着Person原型中的任何方法或属性都可用于Person的所有实例,包括awal。 现在调用函数Person本身;这是对新构造的对象awal的引用。 很简单,是吗

请注意,官方的ECMAScript规范没有规定 函数的类型是实际的构造函数。它们只是普通函数,新函数可以用于任何函数。我们只是这样使用它们,所以我们只称它们为这样

在函数上调用函数:调用并应用 所以,是的,因为函数也是对象,事实上是Javascript中的第一类变量,所以即使函数也有。。。嗯,功能本身

所有函数都继承自全局函数,它的许多方法中有两个是call和apply,这两个方法都可以用于在调用它们的函数中操纵该函数的值

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
这是使用call的典型示例。它基本上接受第一个参数,并在函数foo中将其设置为对thisArg的引用。传递给call的所有其他参数都作为参数传递给函数foo。 因此,上面的代码将在控制台中记录{myObj:is cool},[1,2,3]。在任何函数中更改此值的非常好的方法

apply与call accept几乎相同,它只接受两个参数:thisArg和一个包含要传递给函数的参数的数组。因此,可以将上述调用转换为如下应用:

foo.apply(thisArg, [1,2,3])
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
请注意,call和apply可以覆盖我们在第二个项目符号中讨论的这个set by dot方法调用的值。 很简单:

呈现。。。。绑定 bind是call和apply的兄弟。它也是Javascript中所有函数从全局函数构造函数继承的方法。bind和call/apply之间的区别在于call和apply实际上都会调用函数。另一方面,bind返回一个预先设置了thisArg和arguments的新函数。让我们举一个例子来更好地理解这一点:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
看到三者之间的区别了吗?这是微妙的,但它们的使用方式不同。与call和apply一样,bind也将超越这个set by dot方法调用的值

还请注意,这三个函数都不会对原始函数进行任何更改。call和apply将从新构造的函数返回值,而bind将返回新构造的函数本身,以便调用

额外的东西,复制这个 有时,您不喜欢这样一个事实,即这会随着作用域的变化而变化,尤其是嵌套作用域。看看下面的例子

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };
在上面的代码中,我们看到它的值随嵌套范围的变化而变化,但我们希望它的值来自原始范围。所以我们把这个“复制”到那个,用这个来代替这个。聪明,嗯

索引:

默认情况下,此文件中包含哪些内容? 如果我们将函数称为带有对象点符号的方法,会怎么样? 如果我们使用新的关键字呢? 我们如何通过调用和应用来处理这个问题? 使用bind。 复制此项以解决嵌套范围问题。 由于这篇文章的篇幅越来越大,我为新接触这个话题的读者收集了一些要点

如何确定这一价值? 我们使用这个类似于我们在自然语言如英语中使用代词的方式:“约翰跑得很快,因为他想赶火车。”相反,我们可以写“…约翰想赶火车”

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}
在对象调用定义它的函数之前,不会为其赋值。在全局范围中,所有全局变量和函数都在窗口对象上定义。因此,该函数在全局函数中引用并具有全局窗口对象的值

使用strict时,在未绑定到任何对象的全局函数和匿名函数中,该值为undefined

this关键字是指:1我们借用了一个使用this的方法,2我们将一个使用this的方法分配给一个变量,3使用this的函数作为回调函数传递,4这在闭包内部使用-一个内部函数。二,

什么决定未来 在中定义,箭头函数采用 封闭函数或全局作用域

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
虽然箭头函数提供了一种使用bind的替代方法,但需要注意的是,它们本质上禁用了传统的这种机制,有利于更广泛地理解词法范围。一,

参考资料:

这是凯尔·辛普森的《对象原型》。©2014 Getify解决方案。 javascriptissexy.com- 安格斯·克罗尔- 在JavaScript中是一个很好的来源

总结如下:

全球本

在浏览器中,在全局范围内,这是windowobject

在从脚本执行的节点中,全局范围中的该节点以空对象开始。这和全球的不一样

作用于此

除DOM事件处理程序或提供thisArg的情况外,请参阅下一步,在节点和浏览器中,在不使用新引用调用全局范围的函数中使用this

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>
若您使用新的this调用函数,这将是一个新的上下文,它将不会引用全局this

在原型上分配数组或对象通常是错误的。如果你 如果希望每个实例都有自己的数组,请在函数中创建它们,而不是在原型中创建它们

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
反对这个 您可以在对象上的任何函数中使用它来引用该对象上的其他属性。这与使用new创建的实例不同

DOM事件 在HTMLDOM事件处理程序中,这始终是对事件附加到的DOM元素的引用

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();
HTML这个 在可以放置JavaScript的HTML属性中,这是对元素的引用

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>
用这个 您可以使用with将其添加到当前作用域中,以读取和写入此作用域中的值,而无需显式引用

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
jQuery这个 jQuery在很多地方都会引用DOM元素

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

这个作用域的用法就是这样

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
txt1和txt的值相同 在上面的例子中
$this=$'tbleName tbody tr'是相同的

这是我见过的最好的解释:

此引用始终引用并保存 对象—一个奇异对象,通常用于函数或 方法,尽管它可以在全局 范围注意,当我们使用strict模式时,它保持 在全局函数和非全局函数的匿名函数中未定义 绑定到任何对象

有四种情况会让人感到困惑:

当我们传递一个将其用作回调函数的参数的方法时。 当我们使用一个内部函数时,它就是一个闭包。需要注意的是,闭包不能使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。 当依赖于此的方法跨上下文分配给变量时,在这种情况下,此方法引用的对象不是最初预期的对象。 将其与bind、apply和call方法一起使用时。
他给出了代码示例、解释和解决方案,我认为这非常有帮助。

关于这方面最详细、最全面的文章可能是:

这背后的思想是理解函数调用类型在设置此值方面具有重要意义

在识别时遇到困难时,不要问自己:

这是从哪里拍的

但一定要问问自己:

如何调用该函数

对于箭头函数上下文透明的特殊情况,请自问:

在定义箭头函数的地方,该值是多少


在处理这个问题时,这种心态是正确的,它会让你免于头痛。

关于如何在JavaScript中解释这个关键字,存在很多困惑。希望本文能一劳永逸地解决所有这些问题。还有更多。请仔细阅读整篇文章。事先警告一下,这篇文章很长

不管使用它的上下文是什么,它总是引用Javascript中的当前对象。但是,当前对象的内容因上下文而异。上下文可能正好是以下6项中的1项:

全局的,即所有功能之外的 内部直接非绑定函数调用,即未通过调用functionName.bind绑定的函数 通过functionName.Call和functionName.apply进行的内部间接非绑定函数调用 内部绑定函数调用,即通过调用functionName.bind绑定的函数 通过新的 内联DOM事件处理程序 下面逐一介绍了这些上下文:

全局上下文,即在所有功能之外:

在所有功能之外,即在全球范围内,当前 对象,因此其值始终为 浏览器的窗口对象

内部直接非绑定函数调用:

在直接的非绑定函数调用中 调用的函数调用将成为当前对象,因此 这个的价值。如果在没有显式当前对象的情况下调用函数,则当前对象对于非严格模式是窗口对象,对于严格模式是未定义的。中定义的任何函数或变量 全局上下文自动成为窗口对象的属性。例如,假设函数在全局上下文中定义为

function UserDefinedFunction(){
    alert(this)
    }
它将成为窗口对象的属性,就像您已定义 它是

在非严格模式下,直接通过UserDefinedFunction调用/调用此函数将自动调用/调用 它作为窗口。用户定义函数使窗口作为 当前对象,从而在UserDefinedFunction中调用此函数的值

UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
UserDefinedFunction() // displays undefined
window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
在严格模式下,直接通过 UserDefinedFunction不会自动将其作为window.UserDefinedFunction调用/调用。因此当前 对象及其内部的值 UserDefinedFunction应为未定义函数。在严格模式下调用此函数将导致以下结果

UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
UserDefinedFunction() // displays undefined
window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
然而,invo 如果显式使用窗口对象,则会导致 以下

UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
UserDefinedFunction() // displays undefined
window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
让我们看另一个例子。请看下面的代码

 function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }

var o1={
            a:1,
            b:2,
            f:UserDefinedFunction
      }
var o2={
            c:3,
            d:4,
            f:UserDefinedFunction
       }

o1.f() // Shall display 1,2,undefined,undefined
o2.f() // Shall display undefined,undefined,3,4
在上面的示例中,我们看到当UserDefinedFunction 通过o1调用,它获取o1的值和 将显示其属性a和b的值。价值 与o1一样,c和d的值显示为未定义 不定义这些属性

类似地,当通过o2调用UserDefinedFunction时, 这将获取o2的值,并显示其属性c和d的值。a和b的值显示为未定义,因为o2未定义这些属性

通过functionName.Call和functionName.apply进行的内部间接非绑定函数调用:

当通过调用非绑定函数时 functionName.call或functionName.apply,当前对象,因此其值设置为 此参数是传递给调用/应用的第一个参数。下面的代码演示了相同的情况

function UserDefinedFunction()
{
    alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
}
var o1={
            a:1,
            b:2,
            f:UserDefinedFunction
       }
var o2={
            c:3,
            d:4,
            f:UserDefinedFunction
       }

UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined

UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4

o1.f.call(o2) // Shall display undefined,undefined,3,4
o1.f.apply(o2) // Shall display undefined,undefined,3,4

o2.f.call(o1) // Shall display 1,2,undefined,undefined
o2.f.apply(o1) // Shall display 1,2,undefined,undefined
上面的代码清楚地表明,对于任何非 绑定函数可以通过调用/应用进行更改。此外,如果 此参数未显式传递给当前对象的call/apply,因此其值在非严格模式下设置为window,在严格模式下设置为undefined

内部绑定函数调用,即通过调用functionName.bind绑定的函数:

绑定函数是其此值已被 固定的下面的代码演示了这种情况下的工作原理 有界函数

function UserDefinedFunction()
{
    alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
}
var o1={
          a:1,
          b:2,
          f:UserDefinedFunction,
          bf:null
       }
var o2={
           c:3,
           d:4,
           f:UserDefinedFunction,
           bf:null
        }

var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
bound1() // Shall display 1,2,undefined,undefined

var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
bound2() // Shall display undefined,undefined,3,4

var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
bound3() // Shall display undefined,undefined,3,4

var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
bound4() // Shall display 1,2,undefined,undefined

o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
o1.bf() // Shall display undefined,undefined,3,4

o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
o2.bf() // Shall display 1,2,undefined,undefined

bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function

bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function

o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
正如上面代码中给出的,这个值适用于任何绑定函数 无法通过调用/应用更改。另外,如果 参数未显式传递给绑定的当前对象 因此,它的值在非 严格模式和严格模式中的未定义。还有一件事。 绑定已绑定的函数不会更改此函数的值。 它仍然设置为第一个绑定函数设置的值

通过新建创建对象时:

在构造函数中,当前对象以及 这将引用当前正在创建的对象 无论函数的绑定状态如何,都可以通过new。然而 如果构造函数是绑定函数,则应使用 为绑定函数设置的预定义参数集

内部内联DOM事件处理程序:

请看下面的HTML代码片段

<button onclick='this.style.color=white'>Hello World</button>
<div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
上述示例中的“按钮”是指按钮元素和 分别是div元素

在第一个示例中,按钮的字体颜色应设置为 单击时为白色

在第二个示例中,单击div元素时 使用第二个参数调用OnDivClick函数 引用单击的div元素。然而,这一点的价值 在OnDivClick中,不得引用已单击的div 要素应将其设置为窗口对象或 如果OnDivClick是未绑定函数或设置为预定义值,则分别在非严格模式和严格模式下未定义 如果OnDivClick是绑定函数,则为绑定值

function UserDefinedFunction()
{
    alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
}
var o1={
          a:1,
          b:2,
          f:UserDefinedFunction,
          bf:null
       }
var o2={
           c:3,
           d:4,
           f:UserDefinedFunction,
           bf:null
        }

var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
bound1() // Shall display 1,2,undefined,undefined

var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
bound2() // Shall display undefined,undefined,3,4

var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
bound3() // Shall display undefined,undefined,3,4

var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
bound4() // Shall display 1,2,undefined,undefined

o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
o1.bf() // Shall display undefined,undefined,3,4

o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
o2.bf() // Shall display 1,2,undefined,undefined

bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function

bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function

o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
下面总结了整篇文章

在全局上下文中,这总是指窗口对象

无论何时调用函数,都会在 对象当前对象。如果未明确提供当前对象, 当前对象是非严格格式的窗口对象 默认情况下,模式和未定义为严格模式

非绑定函数中的该值是对当前对象调用函数的上下文中的对象的引用

非绑定函数中的此值可以由 调用并应用函数的方法

对于绑定函数,此值是固定的,不能更改 由函数的调用和应用方法重写

绑定和已绑定函数不会更改此函数的值。它仍然设置为第一个绑定函数设置的值

构造函数中的该值是正在执行的对象 创建并初始化

内联DOM事件处理程序中的该值为reference 到为其提供事件处理程序的元素


其值取决于执行函数的上下文。上下文可以是任何对象或全局对象,即窗口

因此,它的语义不同于传统的OOP语言。它会引起一些问题: 1.当一个函数被传递给另一个变量时,很可能是回调;二,。从类的成员方法调用闭包时


在这两种情况下,这都设置为window。

在伪经典术语中,许多讲座教授“this”关键字的方式是作为类或对象构造函数实例化的对象。每次从一个类构造一个新对象时,想象一下,在后台创建并返回一个“this”对象的本地实例。我记得它是这样教的:

foo.apply(thisArg, [1,2,3])
function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
关于这个关键字的一些信息

让我们在全局范围内将此关键字记录到控制台,而不使用 还有代码吗

console.log(this)
在客户端/浏览器中,该关键字是一个全局对象,它是一个窗口

在Server/Node/Javascript运行时中,该关键字也是一个全局对象,即module.exports

请记住,导出只是对模块的引用。导出

摘要此Javascript: 它的值取决于函数的调用方式,而不是函数的创建位置! 通常,该值由点左侧的对象确定。全球空间中的窗口 在事件侦听器中,该值引用调用事件的DOM元素。 当使用new关键字调用in函数时,其值引用新创建的对象 您可以使用以下函数操纵此值:call、apply、bind 例子: 让对象={ prop1:函数{console.logthis;} } object.prop1;//对象在点的左边,所以这就是对象 const myFunction=object.prop1//我们将函数存储在变量myFunction中 myFunction;//我们现在在全球空间 //myFunction是全局对象上的一个属性 //因此,它记录窗口对象
我对这个问题的看法与其他答案不同,我希望这些答案会有所帮助

查看JavaScript的一种方法是查看只有一种方法可以调用function1。是的

始终为objectForThis提供一些值

对于functionObject.call,其他一切都是语法糖

因此,其他一切都可以通过它如何转换为functionObject.call来描述

如果您只调用一个函数,那么这是全局对象,在浏览器中是窗口

函数foo{ console.logthis; }
foo;//这是窗口对象要正确理解这一点,必须理解上下文和范围以及它们之间的区别

作用域:在javascript中,作用域与变量的可见性相关,作用域通过使用函数实现。了解更多有关范围的信息

上下文:上下文与对象相关。它是指函数所属的对象。当您使用JavaScript“this”关键字时,它指的是函数所属的对象。例如,在函数内部,当您说:“this.accountnumber”时,您指的是属于该函数所属对象的属性“accountnumber”

如果对象“myObj”有一个名为“getMyName”的方法,当JavaScript关键字“this”在“getMyName”中使用时,它指的是“myObj”。如果函数“getMyName”是在全局范围内执行的,那么“this”指的是窗口对象,严格模式除外

现在让我们看一些例子:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>
在浏览器输出中运行abobve代码将:

根据您在窗口对象上下文中的输出,还可以看到窗口原型引用了该对象

现在,让我们在函数内部进行尝试:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function
    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>
输出:

输出是相同的,因为我们在全局范围内记录了'this'变量,在功能范围内记录了它,我们没有更改上下文。在这两种情况下,上下文都是相同的,和widow对象相关

现在让我们创建自己的对象。在javascript中,可以通过多种方式创建对象

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>
输出:

因此,从上面的示例中,我们发现“this”关键字指的是一个与myObj相关的新上下文,myObject还具有到对象的原型链

让我们再举一个例子:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>
输出: 有道理吧?阅读评论

如果您在理解上述示例时遇到困难,让我们尝试使用我们自己的回调函数

输出:

现在,让我们了解范围、自我、生活以及这些行为

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 
输出非常棒,对吗?

说每个函数调用都有一个作用域更为正确。换句话说,Javascript中令人困惑的是,它不是函数本身的固有属性,而是函数调用方式的产物。@pointy谢谢。JS中最混乱的原因是,在所有使用较早C、C++的语言中,这不能被操纵,总是指向对象实例,而在JS中,它依赖于使用函数调用、FraseBin等调用函数时会发生变化。Sushilthis不引用函数的作用域。这将引用特定对象或可能未定义的对象,正如您所说,可以使用.call或.apply更改这些对象。函数的作用域本质上是简化的,它可以访问哪些变量,这完全取决于函数的声明位置,不能更改。@Pointy:说每个函数调用都有一个作用域更为正确。更正确的说法是,函数和块都有作用域,函数调用有上下文。作用域定义了该作用域中的代码可以使用的标识符。上下文定义了这些标识符绑定到什么

它被这个引用了。不,在ES5和之前(例如,当编写此答案时),这与范围之间没有任何关系。在ES2015又称ES6中,this和scope是以一种相当简单的方式相互关联的wrt arrow函数中的this从其封闭的作用域继承而来,但这从来没有指作用域。JS中的一切都是对象不是真的,JavaScript也有原语值,请看原语值本身似乎有一些方法,例如Stringsubstring、NumbertoString等。。因此,可能与那篇文章的命名法不同,它们的行为就像它们是对象一样,它们都是原型,即Stringsubstring实际上是:String.prototype.substring=函数{…}。如果我错了,请纠正我。this关键字与范围无关。此外,它在不是对象属性的函数中也有意义。@arunjitsingh关于这一点有两个学派。我喜欢说一切都是对象的说法,但为了方便起见,有些可以用原语表示-这并不完全是关于范围。这都是关于执行上下文的,它与范围不同。JavaScript是词汇范围的,意思是范围由代码的位置决定,但这取决于包含它的函数的调用方式,而不是该函数所在的位置。我在谷歌上搜索一些有用的相关问题**时发现了这一点,这里有一篇不错的文章*Peter Michaux主张反对使用此方法MDN概述还不错。。。对这个关键字有一个有趣的解释:我认为@supertonsky在2左右是正确的-如果myFun是从全局范围调用的,而不是作为对象上的方法调用的,那么这将是全局对象,所以问题的措辞很重要。顺便说一句,我非常喜欢使用mouseover来获得这样的答案。但是,它显示了setTimeout示例有一个windowglobal.Hi@KevinMeredith的示例。符合事实的因此,要了解超时函数中的内容,应用的不是初始全局执行上下文规则,而是输入函数代码规则。因为没有对对象(例如someObject.someMethod)调用timeout函数,所以这是timeout函数中的窗口,正如JSFIDLE所示。来自Python,可以想象我遇到第三个示例时的沮丧程度。。SMH此答案可能应该更新以反映ES2020的实际情况,即使更改只是术语。当您在全局上下文中定义的函数中使用此选项时,它仍然绑定到全局对象,因为函数实际上是全局上下文的一种方法。这是不正确的。这取决于函数的调用方式或绑定,而不是定义函数的位置。在没有基引用上下文的情况下调用任何函数都会将其默认为全局对象,或者在严格模式下保持未定义状态。@RobG-hmm可能是,但我发现:在这种情况下,此值不是由调用设置的。由于代码未处于严格模式,因此其值必须始终为对象,因此默认为全局对象。事实上,这就是为什么我认为我们可以直接调用window.f1,这意味着f1已经连接到window对象,我是说在调用之前。我是不是弄错了?我可能不是很清楚地评论你把它的设置和函数联系起来,实际上它是一种全局上下文的方法,好像它被称为window.fn,而事实并非如此。这默认为全局对象,因为调用中没有使用基引用,而不是因为函数的定义位置,所以这仍然是由函数的调用方式设置的。如果您使用window.fn显式地调用它,则将其设置为window。相同的结果,不同的处理方式-上面我已经写了“立即”这个词。。。不,你没有。请你修改一下,这样错误就可以纠正了吗?答案似乎是语义上的,因此,在错误修复之前,我无法继续阅读,因为我担心会发现错误。@TylerH在浏览器的这个页面上执行Ctrl+F以查找包含双引号的字符串immediate。我认为如果我理解错了,最好说它链接到当前执行上下文。除了ES6草稿更改,它使用了箭头函数,在外部执行上下文中解决了这个问题。除了链接到您的博客外,也许您可以更深入地研究问这些问题如何帮助他人理解this关键字?你的解释非常有效。完全消除了我的困惑。
       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script>