suchen

Heim  >  Fragen und Antworten  >  Hauptteil

Verstehen Sie die Funktion und die angemessene Verwendung des Schlüsselworts „this“.

Ich hatte gehofft, eine klare Erklärung zu finden, was das Schlüsselwort „this“ bewirkt und wie man es richtig verwendet.

Es scheint sich seltsam zu verhalten und ich verstehe nicht ganz, warum.

thisWie funktioniert es und wann sollte man es anwenden?

P粉155551728P粉155551728441 Tage vor590

Antworte allen(2)Ich werde antworten

  • P粉087951442

    P粉0879514422023-10-13 14:03:41

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

    <强>1。在全局上下文中使用时

    当您在全局上下文中使用 this 时,它会绑定到全局对象(浏览器中的window

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

    当您在全局上下文中定义的函数内使用 this 时,this 仍然绑定到全局对象,因为该函数实际上是全局上下文的方法。< /p>

    function f1()
    {
       return this;
    }
    document.write(f1());  //[object Window]

    上面的f1是一个全局对象的方法。因此我们也可以在 window 对象上调用它,如下所示:

    function f()
    {
        return this;
    }
    
    document.write(window.f()); //[object Window]

    <强>2。当在对象方法内部使用时

    当您在对象方法中使用 this 关键字时,this 会绑定到“直接”封闭对象。

    var obj = {
        name: "obj",
        f: function () {
            return this + ":" + this.name;
        }
    };
    document.write(obj.f());  //[object Object]:obj

    上面我已将“立即”一词放在双引号中。这是为了表明,如果将对象嵌套在另一个对象中,则 this 会绑定到直接父对象。

    var obj = {
        name: "obj1",
        nestedobj: {
            name:"nestedobj",
            f: function () {
                return this + ":" + this.name;
            }
        }            
    }
    
    document.write(obj.nestedobj.f()); //[object Object]:nestedobj

    即使你将 function 作为方法显式添加到对象中,它仍然遵循上述规则,即 this 仍然指向直接父对象。

    var obj1 = {
        name: "obj1",
    }
    
    function returnName() {
        return this + ":" + this.name;
    }
    
    obj1.f = returnName; //add method to object
    document.write(obj1.f()); //[object Object]: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() + "
    "); //[object Object]:ObjDefinition /********************************************************************* 2. Members explicitly added to the function protorype also behave as above: all function instances have their own copy of the variable added. *********************************************************************/ functionDef.prototype.version = 1; functionDef.prototype.getVersion = function(){ return "v"+this.version; //see how this.version refers to the //version variable added through //prototype } document.write(obj1.getVersion() + "
    "); //v1 /********************************************************************* 3. Illustrating that the function variables added by both above ways have their own copies across function instances *********************************************************************/ functionDef.prototype.incrementVersion = function(){ this.version = this.version + 1; } var obj2 = new functionDef(); document.write(obj2.getVersion() + "
    "); //v1 obj2.incrementVersion(); //incrementing version in obj2 //does not affect obj1 version document.write(obj2.getVersion() + "
    "); //v2 document.write(obj1.getVersion() + "
    "); //v1 /********************************************************************* 4. `this` keyword refers to the immediate parent object. If you nest the object through function prototype, then `this` inside object refers to the nested object not the function instance *********************************************************************/ functionDef.prototype.nestedObj = { name: 'nestedObj', getName1 : function(){ return this+":"+this.name; } }; document.write(obj2.nestedObj.getName1() + "
    "); //[object Object]:nestedObj /********************************************************************* 5. If the method is on an object's prototype chain, `this` refers to the object the method was called on, as if the method was on the object. *********************************************************************/ var ProtoObj = { fun: function () { return this.a } }; var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj //as its prototype obj3.a = 999; //adding instance member to obj3 document.write(obj3.fun()+"
    ");//999 //calling obj3.fun() makes //ProtoObj.fun() to access obj3.a as //if fun() is defined on obj3

    <强>4。在构造函数内部使用时。

    当函数用作构造函数时(即使用 new 关键字调用时),函数体内的 this 指向正在构造的新对象。< /p>

    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 设置为 this 内的值code>fun() 并调用 fun(),传递 argsArray 的元素作为其参数。
    • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 设置 obj1 作为 fun()this 的值,并调用 fun() 传递 arg1, arg2, arg3, ...< /code> 作为其参数。
    • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 返回对函数的引用fun,其中 fun 内的 this 绑定到 obj1,并且 fun 的参数绑定到指定的参数 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)+"
    "); //15 //above add.call(o,5,6) sets `this` inside //add() to `o` and calls add() resulting: // this.a + inc1 + inc2 = // `o.a` i.e. 4 + 5 + 6 = 15 document.write(add.apply(o, [5, 6]) + "
    "); //15 // `o.a` i.e. 4 + 5 + 6 = 15 var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6 document.write(g()+"
    "); //15 var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ? document.write(h(6) + "
    "); //15 // 4 + 5 + 6 = 15 document.write(h() + "
    "); //NaN //no parameter is passed to h() //thus inc2 inside add() is `undefined` //4 + 5 + undefined = NaN

    7.事件处理程序内的 this

    • 当您将函数直接分配给元素的事件处理程序时,直接在事件处理函数内使用 this 来引用相应的元素。这种直接的函数分配可以使用 addeventListener 方法或通过 onclick 等传统事件注册方法来完成。
    • 同样,当您直接在元素的事件属性(如
    • 但是,通过在事件处理函数或事件属性内调用的其他函数间接使用 this 会解析为全局对象 window
    • 当我们使用 Microsoft 的事件注册模型方法 attachEvent 将函数附加到事件处理程序时,可以实现与上述相同的行为。它不是将函数分配给事件处理程序(从而创建元素的函数方法),而是在事件上调用函数(在全局上下文中有效地调用它)。

    我建议在 JSFiddle.

    
    
    

    Using `this` "directly" inside event handler or event property



    Using `this` "indirectly" inside event handler or event property



    IE only:

    <强>8。 ES6 箭头函数中的 this

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

    所以,这与以下行为相同:

    (function(){}).bind(this)

    请参阅以下代码:

    const globalArrowFunction = () => {
      return this;
    };
    
    console.log(globalArrowFunction()); //window
    
    const contextObject = {
      method1: () => {return this},
      method2: function(){
        return () => {return this};
      }
    };
    
    console.log(contextObject.method1()); //window
    
    const contextLessFunction = contextObject.method1;
    
    console.log(contextLessFunction()); //window
    
    console.log(contextObject.method2()()) //contextObject
    
    const innerArrowFunction = contextObject.method2();
    
    console.log(innerArrowFunction()); //contextObject 
    

    Antwort
    0
  • P粉156532706

    P粉1565327062023-10-13 11:53:32

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

    规范中this的技术描述

    ECMAScript 标准定义this 通过抽象操作(缩写为AOResolveThisBinding

    全球环境记录模块环境记录,以及 函数环境记录每个都有自己的 GetThisBinding 方法。

    GetThisEnvironment AO 查找当前的运行执行上下文的 LexicalEnvironment 并查找最接近的上升环境记录(通过迭代访问其 [[OuterEnv]] 属性),该记录具有 this< /em> 绑定(即 HasThisBinding 返回 true)。此过程以三种环境记录类型之一结束。

    this 的值通常取决于代码是否处于 严格模式

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

    您可以将代码示例放入 AST 资源管理器中,以遵循规范详细信息。

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

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

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

    全局环境记录的 [[GlobalThisValue]] 属性始终设置为主机定义的全局对象,可通过 globalThis ( Web 上的 window,Node.js 上的 globalMDN 上的文档)。按照 InitializeHostDefinedRealm 的步骤了解 [[GlobalThisValue]] 属性是如何产生的。

    2。 模块

    中的全局执行上下文

    ECMAScript 2015 中引入了模块。

    这适用于模块,例如直接位于