8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

'this' 关键字如何工作?何时使用?

NasusCoder 1月前

99 0

我正在寻找一个清晰的解释,说明 \'this\' 关键字的作用以及如何正确使用它。它似乎表现得很奇怪,我不完全明白为什么。它是如何工作的,

我正在寻找对“this”关键字的作用以及如何正确使用它的清晰解释。

它的行为似乎很奇怪,我不完全明白为什么。

如何 this 工作以及何时使用?

帖子版权声明 1、本帖标题:'this' 关键字如何工作?何时使用?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由NasusCoder在本站《object》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 关键字 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 将绑定到\'immediate\'封闭对象。

    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 内部 this 的值 fun() 并调用 fun() 传递的元素作为 argsArray 其参数。
    • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - 设置 obj1 内部 this 的值 fun() 并调用 fun() 传递 arg1, arg2, arg3, ... 的参数。
    • fun.bind(obj1 [, arg1 [, arg2 [, arg3 [, ...]]]]) 绑定到内部 fun this 引用 obj1 ,并将参数 fun 绑定到指定的参数 arg1, arg2, arg3,... .
    • 现在 apply , call bind 一定已经很明显了。 apply 允许将函数的参数指定为类似数组的对象,即具有数字 length 属性和相应的非负整数属性的对象。而 call 允许直接指定函数的参数。 apply call 在指定的上下文中使用指定的参数立即调用该函数。另一方面, bind 只是返回与指定值和参数绑定的函数 this 。我们可以通过将这个返回函数的引用分配给一个变量来捕获它,然后我们可以随时调用它。
    function add(inc1, inc2)
    {
        return this.a + inc1 + inc2;
    }
    
    var o = { a : 4 };
    document.write(add.call(o, 5, 6)+"<br />"); //15
          //above add.call(o,5,6) sets `this` inside
          //add() to `o` and calls add() resulting:
          // this.a + inc1 + inc2 = 
          // `o.a` i.e. 4 + 5 + 6 = 15
    document.write(add.apply(o, [5, 6]) + "<br />"); //15
          // `o.a` i.e. 4 + 5 + 6 = 15
    
    var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
    document.write(g()+"<br />");    //15
    
    var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
    document.write(h(6) + "<br />"); //15
          // 4 + 5 + 6 = 15
    document.write(h() + "<br />");  //NaN
          //no parameter is passed to h()
          //thus inc2 inside add() is `undefined`
          //4 + 5 + undefined = NaN</code>
    

    7. 事件处理程序中的 this

    • 当您将函数直接分配给元素的事件处理程序时,事件处理函数内部的直接使用 this 方法或通过传统的事件注册方法 addeventListener 完成, onclick .
    • 类似地,当您 this 直接在元素的事件属性(如 <button onclick="...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. 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 
    
返回
作者最近主题: