美文网首页
this指向总结

this指向总结

作者: 简单tao的简单 | 来源:发表于2020-01-07 14:25 被阅读0次

    全局环境下

    在全局环境下,this 始终指向全局对象(window), 无论是否严格模式;

    console.log(this.document === document); // true
    
    // 在浏览器中,全局对象为 window 对象:
    console.log(this === window); // true
    
    this.a = 37;
    console.log(window.a); // 37
    

    函数上下文调用

    函数直接调用

    普通函数内部的this分两种情况,严格模式和非严格模式。
    非严格模式下,this 默认指向全局对象window

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

    而严格模式下, this为undefined

    function f1(){
        "use strict"; // 这里是严格模式
        console.log(this); //undefined
    }
    f1(); 
    
    对象中的this

    对象内部方法的this指向调用这些方法的对象

    1. 函数的定义位置不影响其this指向,this指向只和调用函数的对象有关。
    var o = {
      prop: 37,
      f: function() {
        return this.prop;
      }
    };
    console.log(o.f());  //37
    var a = o.f;
    console.log(a()) //undefined
    
    var o = {prop: 37};
    function independent() {
      return this.prop;
    }
    o.f = independent;
    console.log(o.f()); // 37 
    
    1. 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window)。
    function independent() {
        console.log(this) //this指向o对象里面的b对象
        return this.prop;
    }
    var o = {prop: 37};
    o.b = {
        g: independent,
        prop: 42
    };
    console.log(o.b.g()); // 42
    
    原型链中的this

    原型链中的方法的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
    

    可以看出, 在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 p 没有任何关系,只需记住谁调用指向谁。

    以上对于函数作为getter & setter 调用时同样适用。

    构造函数中this

    构造函数中的this指向被创建的新对象
    注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。

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

    当函数通过Function对象的原型中继承的方法 call() 和 apply() 方法调用时, 其函数内部的this值可绑定到 call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,JavaScript内部会尝试将其转换成对象然后指向它。

    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
    
    function tt() {
      console.log(this);
    }
    // 返回对象见下图(图1)
    tt.call(5);  // Number {[[PrimitiveValue]]: 5} 
    tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}
    
    bind 方法

    bind方法在ES5引入, 在Function的原型链上, Function.prototype.bind。通过bind方法绑定后, 函数将被永远绑定在其第一个参数对象上, 而无论其在什么情况下被调用。

    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
    

    DOM事件处理函数

    当函数被当做监听事件处理函数时, 其 this 指向触发该事件的元素 (针对于addEventListener事件)

    // 被调用时,将关联的元素变成蓝色
    function bluify(e){
        //在控制台打印出所点击元素
        console.log(this);
        //阻止事件冒泡
        e.stopPropagation();
        //阻止元素的默认事件
        e.preventDefault();      
        this.style.backgroundColor = '#A5D9F3';
    }
    
    // 获取文档中的所有元素的列表
    var elements = document.getElementsByTagName('*');
    
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for(var i=0 ; i<elements.length ; i++){
        elements[i].addEventListener('click', bluify, false);
    }
    

    内联事件

    内联事件中的this指向分两种情况:

    1. 指向当前DOM元素
    2. 当代码被包括在函数内部执行时,在非严格模式指向全局对象window, 在严格模式指向undefined
    <button onClick="console.log(this)">show me</button>
    <button onClick="(function(){console.log(this)})()">show inner this</button>
    <button onClick="(function(){'use strict';console.log(this)})()">use strict</button>
    
    image.png

    setTimeout & setInterval

    this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)

    //默认情况下代码
    function Person() {  
        this.age = 0;  
        setTimeout(function() {
            console.log(this);
        }, 3000);
    }
    var p = new Person();//3秒后返回 window 对象
    
    image.png
    //通过bind绑定
    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }).bind(this), 3000);
    }
    var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}
    
    image.png

    箭头函数中的 this

    由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值,

    1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
    2. 考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略。(可以忽略是否在严格模式下的影响)

    因为箭头函数可以捕获其所在上下文的this值 所以

    function Person() {  
        this.age = 0;  
        setTimeout(() => {
            console.log(this) //箭头函数this继承上下文this
        }, 10);
    }
    var p = new Person();
    
    image.png
    function Person() {  
        this.age = 0;  
        setTimeout(function(){
            console.log(this)  //普通函数this指向window
        }, 10);
    }
    var p = new Person();
    
    image.png
    var adder = {
      base : 1,
        
      add : function(a) {
        var f = v => v + this.base;
        return f(a);
      },
    
      addThruCall: function inFun(a) {
        var f = v => v + this.base;
        var b = {
          base : 2
        };
                
        return f.call(b, a);
      }
    };
    
    console.log(adder.add(1));         // 输出 2
    console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder
    

    严格模式示例代码

    var f = () => {'use strict'; return this};
    var p = () => { return this};
    console.log(1,f());
    console.log(2,p());
    //1 window
    //2 window
    

    如果将箭头函数当做一个方法使用会怎样呢?

    var obj = {
      i: 10,
      b: () => console.log(this.i, this),
      c: function() {
        console.log( this.i, this)
      }
    }
    obj.b();  // undefined window{...}
    obj.c();  // 10 Object {...}
    

    可以看到,作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象

    var obj = {
      i: 10,
      b: () => console.log(this)  // Window
    }
    obj.b(); 
    
    function Person(){
        this.name = 'little bear123',
        this.age = 1844,
        setTimeout(()=>{
            console.log(this); //Person
        })
    }
    let p = new Person();
    

    普通函数this & 箭头函数this 总结

    普通函数中的this:
    1. this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是obj
    2. 在默认情况(非严格模式下,未使用 'use strict'),没找到直接调用者,则this指的是 window (约定俗成)
    3. 在严格模式下,没有直接调用者的函数中的this是 undefined
    4. 使用call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象
    箭头函数中的this:
    1. 箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window; 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this
    2. 箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。

    相关文章

      网友评论

          本文标题:this指向总结

          本文链接:https://www.haomeiwen.com/subject/mqkractx.html