Javascript - this(节译)

本文详细解释了JavaScript中this关键字的含义及用法,包括在全局上下文、函数上下文、对象方法、构造器等不同场景下的表现,并探讨了strict mode下的特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

同其它语言相比,JavaScript中函数的this关键字略有不同。This在strict mode和non-strict下也有区别。

大多数情况下,this的值是由函数如何被调用决定的。This在strict mode下不能在运行期间赋值,每次函数调用可能也不尽相同。

  • Global context

    在全局执行的上下文(不在任何函数体之内),this指向global对象。

     console.log(this.document === document); // true
    
     // In web browsers, the window object is also the global object:
     console.log(this === window); // true
     this.a = 37;
    console.log(window.a); // 37
  • 函数上下文

    函数体内this的值取决于函数如何调用。

  1. 简单调用

     function f1() {
       return this;
     }
    
     f1() === window; // global object

    在客户端的JavaScript中,window对象是浏览器执行的代码的global object。由于不是在strict mode,this缺省是window对象。

     function f2() {
       "use strict"; // 使用 strict mode
       return this;
     }
    
     console.info(f2() === undefined); // true
     console.info(window.f2() === window); // true

    由于f2使用了strict mode, 直接调用f2,this为undefined,因为未提供调用的对象。

  2. 作为对象的方法

    当作为一个对象的方法调用时,this指向调用方法的对象。

     var o = {
       prop: 37,
       f: function() {
         return this.prop;
       }};
    
     console.log(o.f()); // logs 37

    请注意调用结果不受函数如何以及在何处定义的影响。
    例如,上述代码中f函数是作为对象o的方法定义的,我们同样可以先定义f函数然后将其赋值给对象o的属性。

     var o = {prop: 37};
    
     function independent() {
       return this.prop;
     }
    
     o.f = independent;
     console.log(o.f()); // logs 37

    This仅受其直接引用的影响。下例中g函数是o对象的b属性的一个属性,当通过o.b.g()调用时,在g函数的方法体内,this指向o.b而跟对象o无关系。

    o.b = {g: independent, prop: 42};
    console.log(o.b.g()); // logs 42

    嵌套函数(nested function)
    若嵌套函数作为对象的方法调用,如前所述,嵌套函数体内的this指向调用它的对象。

    var obj = {
     m: function() {                 // Method m of the object.
         this.f = f;
         function f() {              // A nested function f
            console.log(this === obj);
         }
     }
    };
    obj.m();
    obj.f(); // "true": nested f is invoked as method of obj

    若作为函数(function)直接调用,那么this在strict mode下为undefined,在non-strict mode下为global object,一个常见的错误是此时通过this获取outer function的执行上下文。若想获得outer function的上下文,需要在outer function内定义变量存储,这样所定义的变量在nested function可见。

    var o = {
     m: function() {                 // Method m of the object.
         var self = this;            // Save the this value in a variable.
         console.log(this === o);    // Prints "true": this is the object o.
         f();                        // Now call the helper function f().
         function f() {              // A nested function f
            console.log(this === o); // "false": this is global or undefined
            console.log(self === o); // "true": self is the outer this value.
         }
     }
    };
    o.m();
    

    在prototype chain上

    JavaScript对象原型链上继承的方法中,this指向调用该方法的对象。

     var o = {f:function(){ return this.a + this.b; }};
     var p = Object.create(o);
     p.a = 1;
     p.b = 4;
    
     console.log(p.f()); // 5

    作为 getter or setter
    Getter和setter中this指向当前访问的属性所属的对象。

     function modulus(){
       return Math.sqrt(this.re * this.re + this.im * this.im);}
    
     var o = {
       re: 1,
       im: -1,
       get phase(){
         return Math.atan2(this.im, this.re);
       }};
    
     Object.defineProperty(o, 'modulus', {get: modulus, enumerable:true, configurable:true});
    
     console.log(o.phase, o.modulus); // logs -0.78 1.4142
  3. 作为构造器
    当函数跟在new之后作为构造器时,this指向创建的function对象。
    注: 构造器通常返回新对象的引用,但也可以通过return语句返回其它的对象

     function C() {
       this.a = 37;
     }
    
     var o = new C();
     console.log(o.a); // logs 37
    
     function C2() {
       this.a = 37;
       return {a:38};
     }
    
     o = new C2();
     console.log(o.a); // logs 38

    函数C2返回了对象{a:38},this所指向的新创建的对象并未被返回,因此C2的第一条语句this.a = 37虽然执行过,但即便删除也不影响构造器函数的调用。

    call和apply
    Call和apply调用的this指向第一个参数即调用的对象。

     function add(c, d) {
       return this.a + this.b + c + d;
     }
    
     var o = {a:1, b:3};
     add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
     add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

    bind方法
    ECMAScript 5引入了Function.prototype.bind. 调用f.bind(someObject)会创建一个与f拥有相同方法体和作用域的函数,该函数成为someObject的属性。

     function f() {
       return this.a;
     }
    
     var g = f.bind({a:"azerty"});
     console.log(g()); // azerty
     var o = {a:37, f:f, g:g};
     console.log(o.f(), o.g()); // 37, azerty
  4. 作为DOM event handler

    先来看一段代码,定义了三个按钮btn1, btn2, btn3,分别指定了onclick事件setBtn1ToRed, setBtn2ToYellow, setBtn3ToBlue试图将按钮文字置为红黄蓝。

     <input type="button" id="btn1" value="btn1" onclick="setBtn1ToRed();alert('btn1 is clicked');" />
     <input type="button" id="btn2" value="btn2" />
     <input type="button" id="btn3" value="btn3" onclick="setBtn3ToBlue(this, event)" />
     <script type="text/javascript">
         function setBtn1ToRed() {
             console.info(this == window); // true
             //this.style.color = 'red';
         }
    
         function setBtn2ToYellow() {
             console.info(this.id); // btn2
             this.style.color = 'yellow';
         }
         document.getElementById("btn2").onclick = setBtn2ToYellow;
    
         function setBtn3ToBlue(target, event) {
             console.info(target.id); //btn3
             console.info(event instanceof MouseEvent); //true
             target.style.color = 'blue';
         }
    
         setBtn2ToYellow.newAttribute = "newValue";
         document.getElementById("btn2").onclick.newAttribute == "newValue"; // true
     </script>

    在F12调试工具中分别查看三个按钮的onclick属性

    可以看到通过inline event注册的第一个按钮的onclick仅仅是将οnclick="setBtn1ToRed();alert('btn1 is clicked');"中的属性值作为方法体;而通过element.onclick = setBtn2ToYellow;我们将element的onclick属性设置为setBtn2ToYellow的一个引用,点击element触发函数执行时,this指向element。

    图示如下

    为了更进一步验证btn2的onlick是setBtn2ToYellow的引用,我们通过为setBtn2ToYellow新增一个属性,然后检查btn2的onclick属性是否也拥有了这个新增属性

     setBtn2ToYellow.newAttribute = "newValue";
     document.getElementById("btn2").onclick.newAttribute == "newValue";  // true

 

若希望inline event registration获得目标DOM元素或事件,可以通过btn3的方式onclick="setBtn3ToBlue(this, event)"获取目标元素和事件。

注意onclick="setBtn3ToBlue(this, event)"中的this为input元素,查看调用栈可见


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值