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

Posted

技术标签:

【中文标题】“this”关键字是如何工作的?【英文标题】:How does the "this" keyword work? 【发布时间】:2021-04-08 01:12:31 【问题描述】:

我注意到在 Stack Overflow 网站上似乎没有明确解释 this 关键字是什么以及它在 javascript 中的正确(和错误)使用方式。

我目睹了它的一些非常奇怪的行为,但无法理解为什么会发生。

this 是如何工作的以及何时应该使用它?

【问题讨论】:

我在谷歌搜索“这个”quirksmode.org/js/this.html时发现了这个 一些有用的相关问题 * jQuery/JavaScript “this” pointer confusion * In Javascript, why is the “this” operator inconsistent? 和一篇不错的文章 * scope/context in javascript Peter Michaux 反对使用this peter.michaux.ca/articles/javascript-widgets-without-this MDN 概述还不错...developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/… this关键字的有趣解释:rainsoft.io/gentle-explanation-of-this-in-javascript 【参考方案1】:

this 是 JavaScript 中的关键字,是执行上下文的属性。它的主要用途是在函数和构造函数中。 this 的规则非常简单(如果您坚持最佳做法)。

规范中this的技术说明

ECMAScript standard 通过抽象操作定义this(缩写AO)ResolveThisBinding:

[AO] ResolveThisBinding [...] 使用 running execution context 的 LexicalEnvironment 确定关键字 this 的绑定。 【步骤】:

    envRec 为 GetThisEnvironment()。 返回 ? envRec.GetThisBinding().

Global Environment Records、module Environment Records 和 function Environment Records 都有自己的 GetThisBinding 方法。

GetThisEnvironment AO 找到当前running execution context 的 LexicalEnvironment 并找到最近的上升环境记录(通过迭代访问它们的 [[OuterEnv]] 属性),它具有 this 绑定(即HasThisBinding 返回 true)。此过程以三种环境记录类型之一结束。

this 的值通常取决于代码是否在strict mode 中。

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

您可以将代码示例放在AST explorer 中以跟随规范详细信息。

1。脚本中的全局执行上下文

这是在顶层评估的脚本代码,例如直接在<script>:

<script>
// Global context
console.log(this); // Logs global object.

setTimeout(function()
  console.log("Not global context");
);
</script>

在脚本的初始全局执行上下文中,评估 this 会导致 GetThisBinding 采取以下步骤:

全局环境记录的GetThisBinding具体方法envRec […] [这样做]:

    返回envRec。[[GlobalThisValue]]。

全局环境记录的 [[GlobalThisValue]] 属性始终设置为主机定义的global object,可通过globalThis 访问(Web 上为window,Node.js 上为global;@ 987654337@)。按照InitializeHostDefinedRealm的步骤来了解[[GlobalThisValue]]属性是怎么来的。

2。 modules 中的全局执行上下文

ECMAScript 2015 中引入了模块。

这适用于模块,例如当直接在&lt;script type="module"&gt; 中时,而不是简单的&lt;script&gt;

在模块的初始全局执行上下文中,评估 this 会导致 GetThisBinding 采取以下步骤:

模块环境记录的 GetThisBinding 具体方法 […] [这样做]:

    返回未定义

在模块中,this 的值在全局上下文中始终为 undefined。模块隐含在strict mode 中。

3。输入eval代码

eval 调用有两种:direct 和 indirect。这种区别从 ECMAScript 第 5 版开始就存在了。

直接的eval 调用通常看起来像eval();(eval)();(或((eval))(); 等)。1仅当调用表达式适合窄模式时才直接2 间接eval 调用涉及以任何其他方式调用函数引用eval。可能是eval?.()(, eval)()window.eval()eval.call(,),等等。它也将是aliasEval1()aliasEval2()。另外,给定const originalEval = eval; window.eval = (x) =&gt; originalEval(x);,调用eval() 也是间接的。

请参阅chuckj’s answer to “(1, eval)('this') vs eval('this') in JavaScript?” 和Dmitry Soshnikov’s ECMA-262-5 in detail – Chapter 2: Strict Mode (archived),了解何时可以使用间接eval() 调用。

PerformEval 执行eval 代码。它创建了一个新的declarative Environment Record 作为它的 LexicalEnvironment,GetThisEnvironment 从中获取this 的值。

那么,如果this出现在eval代码中,则调用GetThisEnvironment找到的Environment Record的GetThisBinding方法并返回其值。

而创建的declarative Environment Record 取决于eval 调用是直接还是间接:

在直接评估中,它将基于当前 running execution context 的 LexicalEnvironment。 在间接评估中,它将基于执行间接评估的Realm Record 的 [[GlobalEnv]] 属性(global Environment Record)。

这意味着:

在直接评估中,this 值不会改变;它取自名为 eval 的词法范围。 在间接评估中,this 值是全局对象 (globalThis)。

new Function 呢? — new Functioneval 类似,但不会立即调用代码;它创建了一个函数。 this 绑定不适用于此处的任何地方,除非调用该函数,该函数正常工作,如下一小节所述。

4。输入function代码

调用函数时输入函数代码。

调用函数的语法有四种。

EvaluateCall AO 针对这三个执行:3 Normal function calls Optional chaining calls Tagged templates 并为此执行EvaluateNew:3 Constructor invocations

实际的函数调用发生在Call AO,调用时使用了一个根据上下文确定的thisValue;此参数在与调用相关的一长串调用中传递。 Call 调用函数的[[Call]] 内部槽。这会调用PrepareForOrdinaryCall,其中会创建一个新的function Environment Record:

函数环境记录是一个声明性环境记录,用于表示函数的***范围,如果函数不是ArrowFunction,则提供this 绑定。如果函数不是 ArrowFunction 函数并引用 super,则其函数 Environment Record 还包含用于从函数内部执行 super 方法调用的状态。

另外,函数Environment Record中还有[[ThisValue]]字段:

这是用于此函数调用的this 值。

NewFunctionEnvironment 调用还设置了函数环境的 [[ThisBindingStatus]] 属性。

[[Call]] 也调用OrdinaryCallBindThis,其中合适的thisArgument 是基于:

原始参考, 函数的种类,以及 代码是否在strict mode中。

一旦确定,对新创建的函数 Environment Record 的 BindThisValue 方法的最终调用实际上会将 [[ThisValue]] 字段设置为 thisArgument

最后,这个字段是 function Environment Record’s GetThisBinding AO 获取 this 值的地方:

一个函数Environment Record的GetThisBinding具体方法envRec […] [这样做]:

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

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

Arrow functions

在评估arrow function 时,函数对象的[[ThisMode]] 内部槽在OrdinaryFunctionCreate 中设置为“lexical”

在OrdinaryCallBindThis,它接受一个函数F

    thisModeF.[[ThisMode]]. 如果 thisModelexical,则返回 NormalCompletion(undefined)。 […]

这只是意味着绑定 this 的算法的其余部分被跳过。箭头函数不绑定自己的 this 值。

那么,箭头函数中的this 是什么?回顾ResolveThisBinding和GetThisEnvironment,HasThisBinding method explicitly returns false

一个函数Environment Record的HasThisBinding具体方法envRec […] [这样做]:

    如果 envRec.[[ThisBindingStatus]] 是 lexical,则返回 false;否则,返回 true

因此,外部环境被迭代地查找。该过程将在具有 this 绑定的三个环境之一中结束。

这只是意味着,在箭头函数体中,this 来自箭头函数的词法范围,或者换句话说(来自Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?):

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

函数properties

在普通函数(function、methods)中,this由函数的调用方式决定

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

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

const refObj = 
    func: function()
      console.log(this);
    
  ;

或者:

const refObj = 
    func()
      console.log(this);
    
  ;

在以下任何函数调用中,func 中的 this 值将是 refObj1

refObj.func() refObj["func"]() refObj?.func() refObj.func?.() refObj.func``

如果被调用的函数在语法上是基础对象的属性,那么这个基础将是调用的“引用”,在通常情况下,它将是this 的值。上面链接的评估步骤对此进行了解释;例如,在refObj.func()(或refObj["func"]())中,CallMemberExpression 是整个表达式refObj.func(),它由MemberExpression refObj.funcArguments @987654536 组成@。

而且,refObj.funcrefObj 分别扮演三个角色:

它们都是表达式, 它们都是参考,并且 它们都是价值观。

refObj.func 作为 value 是可调用函数对象;对应的reference用于确定this绑定。

可选链接和标记模板示例的工作方式非常相似:基本上,引用是?.()``() 之前的所有内容。

EvaluateCall 在语法上使用该引用的IsPropertyReference 来确定它是否是对象的属性。它试图获取引用的 [[Base]] 属性(例如,refObj,应用于refObj.func;或foo.bar,应用于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 的调用

没有基引用的调用通常是一个不作为属性调用的函数。例如:

func(); // As opposed to `refObj.func();`.

passing or assigning methods 或使用 comma operator 时也会发生这种情况。这就是参考记录和价值之间的区别所在。

注意函数j:按照规范,你会注意到j只能返回函数对象(Value)本身,不能返回Reference Record。因此,基本引用 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 调用 Call 时,此处的 thisValueundefined。这在 OrdinaryCallBindThis 中有所不同(F:函数对象;thisArgument:传递给 Call 的 thisValue):

    thisModeF.[[ThisMode]].

[…]

    如果 thisModestrict,则让 thisValuethisArgument。 否则,
      如果 thisArgumentundefinednull,则
        globalEnvcalleeRealm.[[GlobalEnv]]. […] 让 thisValueglobalEnv。[[GlobalThisValue]]。
      否则,
        thisValue成为! ToObject(thisArgument)。 注意:ToObject 产生包装对象 […]。

[…]

注意:步骤 5 将 this 的实际值设置为在严格模式下提供的 thisArgument  — undefined 在这种情况下。在“草率模式”中,未定义或空的 thisArgument 会导致 this 成为全局 this 值。

如果IsPropertyReference 返回false,则EvaluateCall 采取以下步骤:

    refEnvref.[[Base]]. 断言:refEnv 是环境记录。 让 thisValuerefEnv.WithBaseObject()。

这是一个未定义的 thisValue 可能来自的地方:refEnv.WithBaseObject() 总是 undefinedexcept 在with 语句中。在这种情况下,thisValue 将是绑定对象。

还有Symbol.unscopables(Docs on 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.bindthisArg 和原语

OrdinaryCallBindThis 的第 5 步与第 6.2 步(规范中的 6.b)相结合的另一个结果是,原始 this 值被强制转换为对象only 处于“草率”模式。

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

Function.prototype.apply(thisArg, argArray) Function.prototype. call, bind (thisArg, ...args)

.bind 创建一个绑定函数,其 this 绑定设置为 thisArg 并且不能再次更改。 .call.apply 立即调用该函数,并将 this 绑定设置为 thisArg

.call.apply 使用指定的 thisArg 直接映射到 Call。 .bind 用BoundFunctionCreate 创建一个绑定函数。它们有它们自己的[[Call]] method,它会查找函数对象的 [[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.
);

构造函数,classes 和 new

当使用new 运算符将函数作为构造函数调用时,EvaluateNew 调用Construct,后者调用[[Construct]] method。如果函数是基本构造函数(即不是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 `.

类定义隐含在strict mode:

class A
  m1()
    return this;
  
  m2()
    const m1 = this.m1;
    
    console.log(m1());
  


new A().m2(); // Logs `undefined`.

super

new 的行为例外是 class extends,如上所述。派生类在调用时不会立即设置它们的 this 值;只有通过一系列super 调用(在没有自己的constructor 的情况下隐式发生)到达基类时,它们才会这样做。不允许在调用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,修改 running execution context。对于每个ClassElement

如果一个字段是静态的,那么this 指的是类本身, 如果字段不是静态的,则this 指的是实例。

将私有字段(例如 #x)和方法添加到 PrivateEnvironment。

Static blocks 当前是TC39 stage 3 proposal。静态块与静态字段和方法的工作方式相同:其中的this 指的是类本身。

请注意,在方法和 getter/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(o.f)() 等价于o.f()(f)() 等价于 f()。这在this 2ality article (archived) 中有解释。具体见how a ParenthesizedExpression is evaluated。

2:它必须是一个MemberExpression,不能是一个属性,必须有一个正好是“eval”的[[ReferencedName]],并且必须是 %eval% 内在对象。

3:只要规范说“让引用是评估 X的结果”,那么X 是您需要为其找到评估步骤的一些表达式。例如,评估 MemberExpressionCallExpression 是 these algorithms 之一的结果。其中一些导致Reference Record。

4:还有其他几种本地和宿主方法允许提供 this 值,特别是接受 thisArg 作为他们的第二个参数。任何人都可以创建自己的方法来更改 this,例如 (func, thisArg) =&gt; func.bind(thisArg)(func, thisArg) =&gt; func.call(thisArg) 等。与往常一样,MDN 提供了很好的文档。


只是为了好玩,用一些例子来测试你的理解

对于每个代码 sn-p,回答问题:“标记行处this 的值是多少?为什么?”

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

    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.methodbase,即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。由于函数值myFun / obj.myMethod 不是从对象调用的,因此作为属性,this 绑定将为globalThis。 这与 Python 不同,在 Python 中访问方法 (obj.myMethod) 会创建一个 bound method object。

    const obj = 
        myFun: () => ( // What is `this` here?
          "is obj": this === obj,
          "is globalThis": this === globalThis
        )
      ;
    
    console.log(obj.myFun());
    
       

    globalThis。箭头函数不会创建自己的 this 绑定。词法作用域与初始全局作用域相同,所以thisglobalThis

    function myFun()
      console.log(this); // What is `this` here?
    
    
    const obj = 
        myMethod: function()
          eval("myFun()");
        
      ;
    
    obj.myMethod();
    

    globalThis。在评估直接 eval 调用时,thisobj。但是,在 eval 代码中,myFun 不会从对象中调用,因此 this 绑定设置为全局对象。

    function myFun() 
      // What is `this` here?
      return 
        "is obj": this === obj,
        "is globalThis": this === globalThis
      ;
    
    
    const obj = ;
    
    console.log(myFun.call(obj));
    
       

    objmyFun.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 的实例。箭头函数不会更改 this 绑定,因此它来自词法范围。因此,这与上面提到的类字段完全相同,例如a = this;。尝试将其更改为static arrow。你得到了你期望的结果吗?

【讨论】:

另一种常见情况:调用 EventHandlers 时将this 设置为事件的currentTarget。这三个提案将来可以包括:Bind operator ::、Explicit this、this argument reflection。像onclick 这样的DOM 0 事件属性也值得注意:JS 代码被隐式包装在document 的一个with 范围内,以及一个用于单击元素的causing confusion; this 是具有该属性的元素。【参考方案2】:

与其他语言相比,this 关键字在 JavaScript 中的行为不同。在面向对象的语言中,this 关键字指的是类的当前实例。在 JavaScript 中,this 的值取决于函数的调用上下文 (context.function()) 以及调用它的位置。

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.在 call()、apply() 和 bind() 函数中

所有这些方法都在Function.prototype 上定义。 这些方法允许编写一次函数并在不同的上下文中调用它。换句话说,它们允许指定this 的值,该值将在函数执行时使用。它们还会在调用原始函数时接受要传递给原始函数的任何参数。 fun.apply(obj1 [, argsArray])obj1 设置为thisfun() 的值,并调用fun() 传递argsArray 的元素作为其参数。 fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 将obj1 设置为fun() 内部的this 的值,并调用fun(),将arg1, arg2, arg3, ... 作为其参数传递。 fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 返回对函数 fun 的引用,其中 fun 内的 this 绑定到 obj1fun 的参数绑定到指定的参数 arg1, arg2, arg3,...。 现在applycallbind 之间的区别一定已经很明显了。 apply 允许指定参数以用作类似数组的对象,即具有数字 length 属性和相应的非负整数属性的对象。而call 允许直接指定函数的参数。 applycall 都会立即在指定的上下文中使用指定的参数调用函数。另一方面,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 内部事件处理程序

当您将函数直接分配给元素的事件处理程序时,在事件处理函数中直接使用this 是指相应的元素。这种直接的函数分配可以使用addeventListener方法或通过onclick等传统的事件注册方法来完成。 同样,当您在元素的事件属性(如&lt;button onclick="...this..." &gt;)内直接使用this 时,它指的是该元素。 但是,通过在事件处理函数或事件属性中调用的其他函数间接使用 this 会解析为全局对象 window。 当我们使用 Microsoft 的事件注册模型方法 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. this 在 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 

【讨论】:

【参考方案3】:

Javascript 的this

简单的函数调用

考虑以下函数:

function foo() 
    console.log("bar");
    console.log(this);

foo(); // calling the function

请注意,我们是在正常模式下运行的,即不使用严格模式。

在浏览器中运行时,this 的值将记录为window。这是因为window 是 Web 浏览器范围内的全局变量。

如果您在 node.js 等环境中运行同一段代码,this 将引用您应用中的全局变量。

现在,如果我们通过在函数声明的开头添加语句 "use strict"; 在严格模式下运行它,this 将不再引用任一环境中的全局变量。这样做是为了避免严格模式下的混淆。 this 会,在这种情况下只记录 undefined,因为它就是这样,它没有定义。

在以下情况下,我们将了解如何操作this 的值。

在对象上调用函数

有不同的方法可以做到这一点。如果您在 Javascript 中调用了诸如 forEachslice 之类的本机方法,您应该已经知道在这种情况下,this 变量指的是您调用该函数的 Object(请注意,在 javascript 中,大约一切都是Object,包括Arrays 和Functions)。以下面的代码为例。

var myObj = key: "Obj";
myObj.logThis = function () 
    // I am a method
    console.log(this);

myObj.logThis(); // myObj is logged

如果Object 包含拥有Function 的属性,则该属性称为方法。此方法在调用时始终会将其this 变量设置为与之关联的Object。这对于严格模式和非严格模式都是如此。

请注意,如果将方法存储(或者更确切地说,复制)在另一个变量中,则对 this 的引用将不再保留在新变量中。例如:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation

考虑一个更常见的实际场景:

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

new 关键字

考虑 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 关键字时会发生什么。

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

很简单,嗯?

请注意,官方的 ECMAScript 规范没有说明此类函数是实际的 constructor 函数。它们只是普通函数,new 可以用于任何函数。只是我们这样使用它们,所以我们只这样称呼它们。

在 Functions 上调用函数:callapply

所以是的,因为 functions 也是 Objects(实际上是 Javascript 中的第一类变量),所以即使函数也有方法,它们本身就是......好吧,函数本身。

所有函数都继承自全局Function,它的众多方法中的两个是callapply,它们都可用于在调用它们的函数中操作this 的值。

function foo ()  console.log (this, arguments); 
var thisArg = myObj: "is cool";
foo.call(thisArg, 1, 2, 3);

这是使用call 的典型示例。它基本上采用第一个参数并在函数foo 中设置this 作为对thisArg 的引用。传递给call 的所有其他参数都作为参数传递给函数foo。 所以上面的代码会在控制台中记录myObj: "is cool", [1, 2, 3]。在任何函数中更改this 的值的好方法。

applycall 几乎相同,接受它只需要两个参数:thisArg 和一个包含要传递给函数的参数的数组。所以上面的call调用可以这样翻译成apply

foo.apply(thisArg, [1,2,3])

注意callapply 可以覆盖我们在第二个项目符号中讨论的点方法调用设置的this 的值。 很简单:)

正在演示中......bind!

bindcallapply 的兄弟。它也是Javascript中全局Function构造函数中所有函数继承的方法。 bindcall/apply 之间的区别在于 callapply 都将实际调用该函数。另一方面,bind 返回一个带有 thisArgarguments 预设的新函数。让我们举个例子来更好地理解这一点:

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]`

看到三者之间的区别了吗?这是微妙的,但它们的使用方式不同。与callapply 一样,bind 也将覆盖由点方法调用设置的this 的值。

另外请注意,这三个函数都不会对原始函数进行任何更改。 callapply 将返回新构建的函数的值,而 bind 将返回新构建的函数本身,准备好被调用。

额外的东西,复制一下

有时,您不喜欢 this 随作用域而变化的事实,尤其是嵌套作用域。看看下面的例子。

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"
        );
    
  ;

在上面的代码中,我们看到this 的值随着嵌套作用域的变化而变化,但我们希望this 的值从原始作用域改变。所以我们将this“复制”到that,并使用副本而不是this。聪明,嗯?

索引:

    this 默认保存什么? 如果我们将函数调用为使用对象点表示法的方法会怎样? 如果我们使用new 关键字会怎样? 我们如何使用callapply 操作this? 使用bind。 复制this 以解决嵌套范围问题。

【讨论】:

【参考方案4】:

“this”是关于范围的。每个函数都有自己的作用域,由于 JS 中的一切都是对象,因此即使是函数也可以使用“this”将一些值存储到自身中。 OOP 101 教导“this”仅适用于对象的instances。因此,每次执行一个函数时,该函数的一个新“实例”就有了一个新的“this”含义。

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

(函数(值) this.value = 值; $('.some-elements').each(function(elt) elt.innerHTML = this.value; // 哦哦!!可能未定义 ); )(2);

所以在这里,在 each() 中,“this”不包含您期望的“值”(来自

this.value = value;
上面)。因此,为了克服这个(不是双关语)问题,开发人员可以: (函数(值) 变种自我=这个; // 小变化 自我价值=价值; $('.some-elements').each(function(elt) elt.innerHTML = self.value; // 呸!! == 2 ); )(2);

试试看;你会开始喜欢这种编程模式

【讨论】:

“JS 中的一切都是对象”不正确,JavaScript 也有原始值,见bclary.com/2004/11/07/#a-4.3.2 原始值本身似乎有一些方法,如 String#substring()、Number#toString() 等。所以,也许与那篇文章的命名法不同,它们确实表现得很好就好像它们是对象一样(它们都是原型,即 String#substring() 实际上是:String.prototype.substring = function()...)。如果我错了,请纠正我。 this 关键字与作用域无关。此外,它在不是对象属性的函数中也有意义。 @arunjitsingh——对此有两种观点。我喜欢这样说“一切都是对象,但为了方便,有些可以用原语表示”。 ;-) this 不仅仅与范围有关。这完全是关于执行上下文,这与范围不同。 JavaScript 是词法范围的(意味着范围由代码的位置决定),但this 是由包含它的函数的调用方式决定的,而不是函数所在的位置。【参考方案5】:

自从这个话题出现以来,我为this主题的新读者整理了几点。

this的值是如何确定的?

我们使用这个类似于我们在英语等自然语言中使用代词的方式:“约翰跑得很快,因为 he 正试图赶上火车。”相反,我们可以写成“……John 正试图赶上火车”。

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);
    

this 在对象调用定义它的函数之前不会被赋值。在全局范围内,所有全局变量和函数都定义在window 对象上。因此,全局函数中的this 引用全局window 对象(并具有其值)。

use strictthis 在未绑定到任何对象的全局函数和匿名函数中的值为undefined

this 关键字是 most misunderstood,当:1) 我们借用一个使用 this 的方法,2) 我们将一个使用 this 的方法分配给一个变量,3) 一个使用 this 的函数作为回调函数传递,并且 4) this 在闭包内部使用 - 一个内部函数。 (2)

未来是什么

在ECMA Script 6 中定义,箭头函数采用this 绑定从 封闭(函数或全局)范围。

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() 的替代方法,但需要注意的是,它们本质上禁用了传统的 this 机制,以支持更广泛理解的词法作用域。 (1)


参考资料:

    this & Object Prototypes,作者 Kyle Simpson。 © 2014 Getify 解决方案。 javascriptissexy.com - http://goo.gl/pvl0GX 安格斯·克罗尔 - http://goo.gl/Z2RacU

【讨论】:

【参考方案6】:

this 在 JavaScript 中总是指正在执行的函数的“所有者”。

如果没有明确定义所有者,则引用最顶层的所有者,即窗口对象。

如果我这样做了

function someKindOfFunction() 
   this.style = 'foo';

element.onclick = someKindOfFunction;

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

&lt;element onclick="someKindOfFunction()"&gt;

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

【讨论】:

【参考方案7】:

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

    函数如何调用(包括作为对象方法,callapply的使用,new的使用) 使用绑定 词法上用于箭头函数(它们采用其外部执行上下文的 this) 代码是处于严格模式还是非严格模式 是否使用eval调用代码

您可以使用func.callfunc.applyfunc.bind 设置this 的值。

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

jQuery 让使用 jQuery.proxy 进行更改变得微不足道。

【讨论】:

说每个函数 call 都有一个作用域更正确一点。换句话说,JavaScript 中的 this 令人困惑的是,它不是函数本身的固有属性,而是函数调用方式的产物。 @pointy 谢谢。在 js 中导致最混乱的原因是,在之前使用的所有语言(c#,c++)中, - this 不能被操纵 n 总是指向对象实例,而在 js 中它取决于并且可以在调用时更改使用func.callfunc.bind 等的函数 – Sushil this 确实 not 引用函数的范围。 this 将引用一个特定对象(或者可能是undefined),正如您所说,可以使用.call().apply() 更改它。函数的作用域是(本质上,简化时)它可以访问哪些变量,这完全取决于函数的声明位置并且不能更改。 @Pointy: “说每个函数调用都有一个作用域更正确一点。” 更正确的说法是函数(现在是块)有 范围,函数调用上下文。范围定义了该范围内的代码可以使用的标识符。上下文定义了这些标识符的绑定对象。 “无论那个作用域是什么,都被“this”引用。” 不,this 和作用域在 ES5 和之前的版本中没有任何关系(例如,当这个答案被写出来时)。在 ES2015(又名 ES6)中,this 和作用域是相关的一个箭头函数的相当小方式(箭头函数中的this 是从其封闭作用域继承的),但this 从不指一个范围。【参考方案8】:

丹尼尔,很棒的解释!关于这个和this 执行上下文指针的好列表,以防事件处理程序。

简而言之,JavaScript 中的 this 指向运行当前函数的对象(或从其执行上下文中),并且它始终是只读的,无论如何您都无法设置它(这样的尝试将结束带有“分配中的左侧无效”消息。

对于事件处理程序: 内联事件处理程序,例如 &lt;element onclick="foo"&gt;,会覆盖之前和之前附加的任何其他处理程序,所以要小心,最好不要使用内联事件委托。 还要感谢 Zara Alaverdyan,他通过不同意见的辩论启发了我列出这个例子:)

el.onclick = foo; // in the foo - obj el.onclick = function () this.style.color = '#fff'; // obj el.onclick = function() doSomething(); // In the doSomething - Window el.addEventListener('click',foo,false) // in the foo - obj el.attachEvent('onclick, function () // this ') // window, all the compliance to IE :) &lt;button onclick="this.style.color = '#fff';"&gt; // obj <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

【讨论】:

【参考方案9】:

Here 是JavaScriptthis 的一个很好的来源。

总结如下:

全局这个

在浏览器中,在全局范围内,thiswindowobject

<script type="text/javascript">
  console.log(this === window); // true
  var foo = "bar";
  console.log(this.foo); // "bar"
  console.log(window.foo); // "bar"

在使用 repl 的 node 中,this 是***命名空间。您可以将其称为global

>this
   ArrayBuffer: [Function: ArrayBuffer],
    Int8Array:  [Function: Int8Array] BYTES_PER_ELEMENT: 1 ,
    Uint8Array:  [Function: Uint8Array] BYTES_PER_ELEMENT: 1 ,
    ...
>global === this
 true

在从脚本执行node 时,全局范围内的this 以空对象开始。和global不一样

\\test.js
console.log(this);  \\ 
console.log(this === global); \\ fasle

函数这个

除了在 DOM 事件处理程序或提供 thisArg 的情况下(请参阅下文),在节点和浏览器中使用 this 在未使用 new 调用的函数中引用全局范围……

<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>

如果您使用use strict;,在这种情况下this 将是undefined

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

    function testThis() 
      "use strict";
      this.foo = "foo";
    

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

如果您使用new 调用函数,this 将是一个新上下文,它不会引用全局this

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

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

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
对此进行原型制作

您创建的函数成为函数对象。它们会自动获得一个特殊的 prototype 属性,您可以为其赋值。当您通过使用new 调用函数来创建实例时,您可以访问分配给prototype 属性的值。您可以使用this 访问这些值。

function Thing() 
  console.log(this.foo);


Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

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

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 []
反对这个

您可以在对象的任何函数中使用this 来引用该对象的其他属性。这与使用new 创建的实例不同。

var obj = 
    foo: "bar",
    logFoo: function () 
        console.log(this.foo);
    
;

obj.logFoo(); //logs "bar"
DOM 事件

在 HTML DOM 事件处理程序中,this 始终是对事件附加到的 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();

除非你bind上下文

function Listener() 
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));

Listener.prototype.handleClick = function (event) 
    console.log(this); //logs Listener handleClick: function


var listener = new Listener();
document.getElementById("foo").click();
HTML 这个

在可以放置 JavaScript 的 HTML 属性中,this 是对元素的引用。

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
评估这个

您可以使用eval 访问this

function Thing () 

Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () 
    eval("console.log(this.foo)"); //logs "bar"


var thing = new Thing();
thing.logFoo();
有了这个

您可以使用withthis 添加到当前范围以读取和写入this 上的值,而无需显式引用this

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 在很多地方都会有this 引用一个DOM 元素。

<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>

【讨论】:

【参考方案10】:

关于 "this" 关键字在 JavaScript 中的解释方式存在很多混淆。希望这篇文章能让所有这些人一劳永逸。还有更多。请仔细阅读整篇文章。请注意,这篇文章很长。

无论在什么上下文中使用,"this" 总是引用 Javascript 中的 "current object"。但是,“当前对象”是什么,根据上下文而有所不同。 上下文可能恰好是以下 6 个中的 1 个

    全局(即在所有功能之外) Inside Direct "Non Bound Function" Call(即通过调用functionName.bind绑定的函数) 通过 functionName.callfunctionName.apply 内部间接“非绑定函数”调用 > 在“绑定函数”调用中(即通过调用functionName.bind已绑定的函数)李> 通过“new”创建对象时 内联 DOM 事件处理程序

下面一一描述了这些上下文中的每一个:

    全局上下文(即所有函数之外):

    在所有函数之外(即在全局上下文中)“当前 object"(因此 "this" 的值)始终是 "window" 浏览器对象。

    内部直接“非绑定函数”调用

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

    function UserDefinedFunction()
        alert(this)
        
    

    它变成了窗口对象的属性,就好像你已经定义了 它作为

    window.UserDefinedFunction=function()
      alert(this)
      
    

    在“非严格模式”下,直接通过"UserDefinedFunction()"调用/调用该函数会自动调用/调用 它作为 "window.UserDefinedFunction()" 使 "window" 作为 “当前对象”(以及 “this” 的值)在 “UserDefinedFunction” 中。在“非严格模式”中调用此函数将结果如下

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
    

    在“严格模式”下,直接通过调用/调用函数 "UserDefinedFunction()""NOT" 自动调用/调用它为 "window.UserDefinedFunction()"。因此 "当前的 object”(以及 “this” 的值) “UserDefinedFunction” 应为未定义。在“严格模式”中调用此函数将导致以下结果

    UserDefinedFunction() // displays undefined
    

    但是,使用 window 对象显式调用它会导致 以下

    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 调用,"this" 的值为 o1,而 其属性 "a""b" 的值会显示出来。价值 的 "c""d" 显示为 undefined,与 o1 一样 不定义这些属性

    类似地,当通过 o2 调用 "UserDefinedFunction" 时, "this"o2 的值,并显示其属性 "c""d" 的值. "a""b" 的值显示为 undefined 因为 o2 没有定义这些属性.

    内部间接“非绑定函数”调用通过functionName.callfunctionName.apply

    当一个 "Non Bound Function" 被通过 functionName.callfunctionName.apply“当前对象”(以及因此 "this") 的值设置为 “this” 参数(第一个参数)传递给 call/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
    

    上面的代码清楚地表明,任何“NON”的“this”值 Bound Function”可以通过call/apply来改变。另外,如果 "this" 参数未显式传递给 call/apply,设置了 "current object"(因此设置了 "this" 的值)到 "window" 在非严格模式和 "undefined" 在严格模式。

    “绑定函数”调用内部(即通过调用functionName.bind绑定的函数):

    绑定函数是其 "this" 值已被 固定的。下面的代码演示了 "this" 是如何工作的,以防万一 绑定函数

    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
    

    如上面的代码中给出的,任何“绑定函数”的“this”值 不能通过调用/应用进行更改。另外,如果 "this" 参数未显式传递给绑定,“当前对象” (因此 "this" 的值)在 Non 中设置为 "window" 严格模式和严格模式下的 "undefined"。还有一件事。 绑定一个已经绑定的函数不会改变 "this" 的值。 它仍然设置为第一个绑定函数设置的值。

    通过“new”创建对象时

    在构造函数中,“当前对象”(以及因此的值 "this") 引用当前正在创建的对象 通过 "new" 与函数的绑定状态无关。然而 如果构造函数是一个绑定函数,它应该被调用 为绑定函数设置的预定义参数集。

    内联 DOM 事件处理程序

    请看下面的 HTML Snippet

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
    

    上面例子中的“this”指的是“button”元素和 “div”元素。

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

    在第二个例子中,当点击 "div" 元素时,它应该 使用第二个参数调用 OnDivClick 函数 引用点击的 div 元素。然而 "this" 的值 在 OnDivClick 不得引用点击的 div 元素。应设置为“窗口对象”"undefined" 分别在 Non strictStrict Modes 中(如果 OnDivClick未绑定函数 strong>) 或设置为预定义的 绑定值(如果 OnDivClick绑定函数

以下是整篇文章的总结

    在全局上下文中 "this" 始终指代 "window" 对象

    每当调用函数时,都会在 对象(“当前对象”)。如果当前对象没有明确提供, 当前对象NON Strict中的“窗口对象” 模式“未定义”默认为严格模​​式。

    Non Bound 函数中 "this" 的值是对调用该函数的上下文中的对象的引用("current object"

    Non Bound 函数中 "this" 的值可以由 callapply 函数的方法。

    "this" 的值对于 Bound 函数是固定的,不能 被函数的 callapply 方法覆盖。

    绑定和已经绑定的函数不会改变“this”的值。它仍然设置为第一个绑定函数设置的值。

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

    内联 DOM 事件处理程序中 "this" 的值是引用 到为其指定事件处理程序的元素。

【讨论】:

【参考方案11】:

this 上可能最详细、最全面的文章如下:

Gentle explanation of 'this' keyword in JavaScript

this 背后的想法是要了解函数调用类型对设置this 值具有重要意义。


当无法识别this 时,不要问自己:

this 取自哪里

问问自己:

函数是如何调用的

对于箭头函数(上下文透明的特殊情况)问问自己:

定义了箭头函数this有什么值?

这种心态在处理this 时是正确的,并且会让你免于头痛。

【讨论】:

除了链接到您的博客之外,也许您可​​以更深入地研究提出这些问题如何帮助某人理解 this 关键字?【参考方案12】:

这是我见过的最好的解释:Understand JavaScripts this with Clarity

this 引用总是指(并持有)一个 对象——一个单一的对象——它通常用在一个函数或一个 方法,尽管它可以在全局函数之外使用 范围。请注意,当我们使用严格模式时,它的值是 在全局函数和未定义的匿名函数中未定义 绑定到任何对象。

有四种情况可能会造成混淆:

    当我们将方法(使用 this)作为参数传递时,该方法将用作回调函数。 当我们使用内部函数(闭包)时。需要注意的是,闭包不能使用 this 关键字访问外部函数的 this 变量,因为 this 变量只能被函数本身访问,不能被内部函数访问。 当一个依赖于 this 的方法被跨上下文分配给一个变量时,在这种情况下 this 引用了另一个对象,而不是原来的预期。 将 this 与绑定、应用和调用方法一起使用时。

他给出了代码示例、解释和解决方案,我认为这很有帮助。

【讨论】:

【参考方案13】:

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

this 有助于获取我们使用的当前对象(也称为执行上下文)。如果您了解当前函数在哪个对象中执行,您可以轻松理解当前this 是什么

var val = "window.val"

var obj = 
    val: "obj.val",
    innerMethod: function () 
        var val = "obj.val.inner",
            func = function () 
                var self = this;
                return self.val;
            ;

        return func;
    ,
    outerMethod: function()
        return this.val;
    
;

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

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


很少有可以区分this的地方

调用对象的方法

var status = 1;
var helper = 
    status : 2,
    getStatus: function () 
        return this.status;
    
;

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

当 line1 被执行时,JavaScript 为函数调用建立一个执行上下文 (EC),将 this 设置为 最后一个“.”之前所引用的对象。所以在最后一行你可以理解a()是在全局上下文中执行的,即window

使用构造函数

this 可用于引用正在创建的对象

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 被调用,其 this 被设置为引用该新对象。

函数调用

function testFunc() 
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;


var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

如果我们错过了 new 关键字,whatIsThis 指的是它可以找到的最全局上下文(window

带有事件处理程序

如果事件处理程序是内联的,this 指的是全局对象

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

<button id='thebutton' onclick='click_handler()'>Click me!</button>

通过 JavaScript 添加事件处理程序时,this 指的是生成事件的 DOM 元素。


您还可以使用.apply() .call().bind() 操作上下文 JQuery 代理是另一种您可以用来确保函数中的 this 是您想要的值的方法。 (查看Understanding $.proxy()、jQuery.proxy() usage) What does var that = this means in JavaScript

【讨论】:

【参考方案14】:

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

所以“this”的语义不同于传统的 OOP 语言。它会导致问题: 1. 当一个函数被传递给另一个变量时(很可能是一个回调); 2. 当从类的成员方法调用闭包时。

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

【讨论】:

【参考方案15】:

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

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;

【讨论】:

【参考方案16】:

this 需要帮助吗? (javascript中'this'的大部分混淆来自于它通常不链接到你的对象,而是链接到当前的执行范围——这可能不是它的工作原理,但对我来说总是这样——完整解释见文章)

【讨论】:

最好说它链接到“到当前执行上下文”。除了 ES6 (draft) 使用箭头函数进行的更改之外,这是在外部执行上下文中解决的。【参考方案17】:

关于this关键字的一些信息

让我们在全局范围内将 this 关键字记录到控制台,而不需要更多代码,但是

console.log(this)

Client/Browserthis关键字是一个全局对象window

console.log(this === window) // true

Server/Node/Javascript runtimethis关键字也是一个全局对象module.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

请记住,exports 只是对module.exports 的引用

【讨论】:

【参考方案18】:

我对 this 的看法与我希望对您有所帮助的其他答案不同。

查看 JavaScript 的一种方法是看到只有一种方法可以调用函数1。这是

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

总是为objectForThis 提供一些值。

其他一切都是functionObject.call的语法糖

因此,其他所有内容都可以通过将其转换为 functionObject.call 来描述。

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

function foo() 
  console.log(this);


foo();  // this is the window object

换句话说,

foo();

被有效地翻译成

foo.call(window);

请注意,如果您使用严格模式,则 this 将是 undefined

'use strict';

function foo() 
  console.log(this);


foo();  // this is the window object

意思是

换句话说,

foo();

被有效地翻译成

foo.call(undefined);

在 JavaScript 中有 +-* 这样的运算符。还有点运算符是.

. 运算符与右侧的函数和左侧的对象一起使用时,实际上意味着“将对象作为 this 传递给函数。

例子

const bar = 
  name: 'bar',
  foo()  
    console.log(this); 
  ,
;

bar.foo();  // this is bar

换句话说,bar.foo() 翻译成 const temp = bar.foo; temp.call(bar);

请注意,函数的创建方式并不重要(主要是...)。所有这些都会产生相同的结果

const bar = 
  name: 'bar',
  fn1()  console.log(this); ,
  fn2: function()  console.log(this); ,
  fn3: otherFunction,
;

function otherFunction()  console.log(this) ;

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

这些都只是语法糖

 const temp = bar.fn1; temp.call(bar); 
 const temp = bar.fn2; temp.call(bar); 
 const temp = bar.fn3; temp.call(bar); 

另一个问题是原型链。当您使用a.b 时,JavaScript 首先会在a 直接引用的对象上查找属性b。如果在对象上找不到b,那么JavaScript 将在对象的原型中查找b

定义对象原型的方法有很多种,2019 年最常见的是class 关键字。出于this 的目的,尽管这并不重要。重要的是,当它在对象a 中查找属性b 时,如果它在对象上或在其原型链中找到属性b,如果b 最终成为一个函数,则适用与上述相同的规则。函数b 引用将使用call 方法调用,并将a 作为objectForThis 传递,如本答案顶部所示。

现在。假设我们创建一个函数,在调用另一个函数之前显式设置this,然后使用.(点)运算符调用它

function foo() 
  console.log(this);


function bar() 
  const objectForThis = name: 'moo'
  foo.call(objectForThis);  // explicitly passing objectForThis


const obj = 
  bar,
;

obj.bar();  

翻译后使用callobj.bar()变成const temp = obj.bar; temp.call(obj);。当我们进入bar 函数时,我们调用foo,但是我们显式地为objectForThis 传入了另一个对象,所以当我们到达foo 时,this 就是那个内部对象。

这就是bind=&gt; 函数的有效作用。它们更像是语法糖。他们有效地构建了一个新的不可见函数,就像上面的 bar 一样,它在调用指定的任何函数之前显式设置 this。在绑定的情况下,this 设置为您传递给bind 的任何内容。

function foo() 
  console.log(this);


const bar = foo.bind(name: 'moo');

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call(name: 'other');

请注意,如果functionObject.bind 不存在,我们可以像这样制作自己的

function bind(fn, objectForThis) 
  return function(...args) 
    return fn.call(objectForthis, ...args);
  ;

然后我们可以这样称呼它

function foo() 
  console.log(this);


const bar = bind(foo, name:'abc');

箭头函数,=&gt; 运算符是绑定的语法糖

const a = () => console.log(this);

相同
const tempFn = function() console.log(this); 
const a = tempFn.bind(this);

就像bind 一样,创建了一个新的不可见函数,它使用objectForThis 的绑定值调用给定函数,但与bind 不同的是,要绑定的对象是隐式的。使用 =&gt; 运算符时,this 恰好是什么。

所以,就像上面的规则一样

const a = () =>  console.log(this);   // this is the global object
'use strict';
const a = () =>  console.log(this);   // this is undefined
function foo() 
  return () =>  console.log(this); 


const obj = 
  foo,
;
const b = obj.foo();
b();

obj.foo() 转换为const temp = obj.foo; temp.call(obj);,这意味着foo 中的箭头运算符将obj 绑定到一个新的不可见函数并返回分配给b 的新不可见函数。 b() 将像 b.call(window)b.call(undefined) 一样调用 foo 创建的新的不可见函数。那个不可见的函数会忽略传入它的 this,并将 obj 作为 objectForThis` 传递给箭头函数。

上面的代码翻译成

function foo() 
  function tempFn() 
    console.log(this);
  
  return tempFn.bind(this);


const obj = 
  foo,
;
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply是另一个类似call的函数

functionName.apply(objectForThis, arrayOfArgs);

但从 ES6 开始,你甚至可以将其翻译成

functionName.call(objectForThis, ...arrayOfArgs);

【讨论】:

你的解释很有效。彻底解决了我的困惑。【参考方案19】:

Scope 的这个用法就像这样

  <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') 相同

【讨论】:

【参考方案20】:

总结thisJavascript:

this 的值取决于函数的调用方式而非函数的创建位置! 通常this 的值由点左侧的对象确定。 (window 在全局空间中) 在事件侦听器中,this 的值指的是调用事件的 DOM 元素。 当使用 new 关键字调用 in 函数时,this 的值指的是新创建的对象 您可以使用以下函数操作this 的值:callapplybind

示例:

let object = 
  prop1: function () console.log(this);


object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

示例事件监听器:

document.querySelector('.foo').addEventListener('click', function () 
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
)


document.querySelector('.foo').addEventListener('click', () => 
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
)                    // Therefore this will log the global object
.foo:hover 
  color: red;
  cursor: pointer;
&lt;div class="foo"&gt;click me&lt;/div&gt;

示例构造函数:

function Person (name) 
  this.name = name;


const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.

【讨论】:

【参考方案21】:

JavaScript 中的“this” 这是执行上下文的属性之一。

每次执行函数时都会创建此属性,而不是 在此之前。 它的值不是静态的,而是取决于它的使用方式。 采用一个值,该值指向它所在的函数的所有者 用过

“this”关键字有多种使用方式,下面是它的示例(方法、常规函数、箭头函数、事件监听器、显式函数绑定)。

1.在方法内部。

this ===(对调用方法的对象)。

在上面的例子中,方法“fullName()”由对象“person”调用,因此方法“fullName()”中的 this 值将等于“person”对象。

2。在函数内部。

i) 函数声明/表达式

在松散模式下 this === 窗口(对象)

在严格模式下 this === undefined

注意:在使用函数声明或函数表达式方法定义函数时,此属性的作用相同。

ii) 箭头功能:

箭头函数没有自己的 this 属性,它们将 this 的值作为其周围的函数。 如果周围函数不存在,即如果它们是在全局级别定义的,那么 this === window (object)

3。事件监听器 this === 处理程序附加到的对象。 点击事件绑定到 Document 对象

在上面的示例中,由于单击处理程序附加到“文档”对象,这将等于“文档”对象

4.显式函数绑定(调用、应用、绑定)

call() 和 apply() 方法是预定义的 JavaScript 方法。

它们都可以用于以另一个对象作为参数调用一个对象方法。

在上面的示例中,“printFullDetails()”中的 this 被明确设置为 personObj1 和 personObj2,方法是作为第一个参数传递给调用方法。

您可以探索更多关于调用、应用和绑定方法here。

【讨论】:

此处接受的答案是正确、最新且完整的。代码示例不应采用屏幕截图的形式,而应作为可复制的代码块(也适用于您之前的答案)。 “这个属性是在每次执行函数时创建的,而不是在此之前” 是不正确的:它错过了类和全局执行上下文。 “取决于它的使用方式” 是相当模糊的。 “函数的所有者” 在 JS 中并不是真正的语言结构。一个对象不能“调用”一个方法。一个方法可以被称为on(或“off of”)一个对象。 “普通模式”比严格模式普通... 一般来说,应该提到globalThis而不是window“箭头函数没有自己的 this 属性” 含糊不清。 this 不是对象的属性(ES 语言值),而是环境记录(ES 规范值)上的内部槽。箭头函数不绑定 this“如果它们是在全局级别定义的”,则适用严格与松散模式的相同规则。事件监听器实际上并不特殊; addEventListener 调用侦听器函数,this 绑定到接收到的 Event 的 currentTarget 属性。 有几个 API 可以绑定一些 this 值,但您可以创建自己的 API 来执行此操作。 “在上面的例子中”?示例在下面 @SebastianSimon 我真的很尊重您阅读我的答案所花费的时间。我非常感谢您的最新回答。但是我觉得对于初学者来说用处不大,因为篇幅太长了,另外,如果我想要一个详细的概念,我会去看 MDN 官方文档。我尽量让我的回答简短而简单。提供的截图只是为了快速查看,以后我也会尝试放代码。【参考方案22】:

要正确理解“这个”,必须了解它们的上下文、范围和区别。

作用域:在javascript中作用域与变量的可见性有关,作用域是通过使用函数来实现的。 (阅读有关范围的更多信息)

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

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

现在让我们看一些例子:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

在浏览器输出中运行上述代码将:

根据你在窗口对象的上下文中的输出,窗口原型引用对象也是可见的。

现在让我们在函数内部试试:

    <script>
        function myFunc()
            console.log('What is this: '+this);
            console.log(this);
        
        myFunc();
    </script>

输出:

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

现在让我们创建自己的对象。在 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也有指向Object的原型链。

让我们再举一个例子:

<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>

输出: 有道理吗? (读 cmets)

如果您无法理解上述示例,请尝试使用我们自己的回调;

<script>
        var myObj = 
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2)
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            
        
        var callback2 = function ()
            console.log(this);
        
        myObj.printName(function(data)
            console.log(data);
            console.log(this);
        , callback2);
    </script>

输出:

现在让我们了解 Scope、Self、IIFE 和 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> 

输出非常棒吧?

【讨论】:

以上是关于“this”关键字是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

Java 继承中的“this”关键字是如何工作的?

android编程下面上下文中的this关键字

如何理解 JavaScript 中的 this 关键字

如何理解 JavaScript 中的 this 关键字

如何理解 JavaScript 中的 this 关键字

如何避免 Javascript 中的 `this` 和 `new` 关键字? [关闭]