JavaScript中的this

作者: Viaphlyn | 来源:发表于2017-11-19 17:00 被阅读11次

    MDN|JavaScript this

    一、this的指向

    1.this是Javascript语言的一个关键字。
    它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。

          function test(){
            this.x = 1;
          }
    

    2.理解这句话:

    this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。

    • 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(严格模式下,this指向不是window,是undefined)
    function a(){
        var user = "via";
        console.log(this.user); //undefined
        console.log(this); //Window
    }
    a();
    
    • 情况2:函数有被上一级的对象所调用, 则this指向的就是上一级的对象。
    var o = {
        user:"via",
        fn:function(){
            console.log(this.user); //via
        }
    }
    window.o.fn();
    
    var o = {
        a:10,
        b:{
            a:12,
            fn:function(){
                console.log(this.a); //12
            }
        }
    }
    o.b.fn();
    
    • 情况3:函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象。
    var o = {
        a:10,
        b:{
            // a:12,
            fn:function(){
                console.log(this.a); //undefined
            }
        }
    }
    o.b.fn();
    
    • 特殊:
    var o = {
        a:10,
        b:{
            a:12,
            fn:function(){
                console.log(this.a); //undefined
                console.log(this); //window
            }
        }
    }
    var j = o.b.fn;
    j();
    //函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行
    //所以最终指向的是window
    
    • 当this碰到return
      如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
    function fn()  
    {  
        this.user = 'via';  
        return {};  
    }
    var a = new fn;  
    console.log(a.user); //undefined
    
    function fn()  
    {  
        this.user = 'via';  
        return 1;
    }
    var a = new fn;  
    console.log(a.user); //via
    

    特殊:虽然null也是对象,但是在这里this还是指向那个函数的实例

    function fn()  
    {  
        this.user = 'via';  
        return null;
    }
    var a = new fn;  
    console.log(a.user); //via
    

    二、call、apply、bind改变this指向

    • 直接看代码
    var a = {
        user:"via",
        fn:function(){
            console.log(this.user);
        }
    }
    var b = a.fn;
    b(); //undefined
    a.fn(); //via
    b.call(a);//通过在call方法,给第一个参数添加要把b添加到哪个环境中,this就会指向那个对象。
              //call还可以添加多个参数
    b.apply(a);//apply也可以有多个参数,不同的是第二个参数必须是一个数组
    
    • 如果call和apply的第一个参数写的是null,那么this指向的是window对象
    var a = {
       user:"via",
       fn:function(){
           console.log(this); //Window
       }
    }
    var b = a.fn;
    b.call(null);//window
    b.apply(null);//window
    
    • bind方法返回的是一个修改过后的函数。
    var a = {
        user:"via",
        fn:function(){
            console.log(this.user);
        }
    }
    var b = a.fn;
    b.bind(a);
    //firefox:bound fn()
     length: 0
     name: "bound fn"
     __proto__: function ()
    //chrome:ƒ (){
            console.log(this.user);
        }
    
    var a = {
        user:"via",
        fn:function(){
            console.log(this.user); //via
        }
    }
    var b = a.fn;
    var c = b.bind(a);
    c();//执行函数
    
    • 同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的
    var a = {
        user:"via",
        fn:function(e,d,f){
            console.log(this.user); //via
            console.log(e,d,f); //10 1 2
        }
    }
    var b = a.fn;
    var c = b.bind(a,10);
    c(1,2);
    

    二、其他指向

    • 构造函数
      通过这个函数生成一个新对象(object)。这时,this就指这个新对象。
    function Fn(){
        this.num = 1;
    }
    var a = new Fn();
    console.log(a.num); //1
    
    //a创建了一个Fn的实例并没有执行
    //调用这个函数Fn的是对象a,那么this指向的自然是对象a
    
    • 存在于一个对象的原型链上,那么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
    
    • 作为一个内联事件处理函数
      this指向监听器所在的DOM元素:
    <button onclick="alert(this.tagName.toLowerCase());">
      Show this
    </button>
    
    • 作为一个DOM事件处理函数
      this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。
    // 被调用时,将关联的元素变成蓝色
    function bluify(e){
      console.log(this === e.currentTarget); // 总是 true
    
      // 当 currentTarget 和 target 是同一个对象是为 true
      console.log(this === e.target);        
      this.style.backgroundColor = '#A5D9F3';
    }
    
    • getter或setter的函数都会把 this 绑定到正在设置或获取属性的对象。
    function sum() {
      return this.a + this.b + this.c;
    }
    
    var o = {
      a: 1,
      b: 2,
      c: 3,
      get average() {
        return (this.a + this.b + this.c) / 3;
      }
    };
    
    Object.defineProperty(o, 'sum', {
        get: sum, enumerable: true, configurable: true});
    
    console.log(o.average, o.sum); //  2, 6
    

    三、在匿名函数,定时器中的函数setTimeout/setInterval中

    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }), 1000);
    }
    
    var p = new Person();//window
    
    • 匿名函数,定时器中的函数,由于没有默认的宿主对象,所以默认this指向window
    • 用一个 变量提前把正确的 this引用保存 起来, that = this 或者 ** _this = this** 来保存我们需要的this指针
    function Person() {
        var that=this ; 
        that.age = 0;  
        setTimeout((function() {
            console.log(that);
        }).bind(this), 3000);
    }
    
    var p = new Person();//1秒后返回构造函数新生成的对象 Person{...}
    
    • 或用func.bind(this)给回调函数直接绑定宿主对象, bind绑定宿主对象后依然返回这个函数
    function Person() {  
        this.age = 0;  
        setTimeout((function() {
            console.log(this);
        }).bind(this), 1000);
    }
    
    var p = new Person();//1秒后返回构造函数新生成的对象 Person{...}
    

    四、箭头函数

    • 不绑定this
      箭头功能不会创建自己的this;它使用封闭执行上下文的this值。
    • 在箭头函数中,this是根据当前的词法作用域来决定的,就是说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。在全局作用域中,它会绑定到全局对象上。
      (默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window)
    var globalObject = this;
    var foo = (() => this);
    console.log(foo() === globalObject); // true
    

    注意:如果将thisArg传递给call、bind、或者apply,它将被忽略(thisArg即传入三个函数中的第一个参数)。仍可以为调用添加参数,不过第一个参数应该设置为null。

    • 与普通函数对比
        var obj={  
            num:3,  
            fn:function(){  
                setTimeout(function(){  
                    console.log(this.num);  
                  //this出现在全局函数setTImeout()中的匿名函数里
                 //并没有某个对象进行显示调用,所以this指向window对象 
                });  
            }  
        }  
        obj.fn();//undefined 
    
        var obj1={  
            num:4,  
            fn:function(){  
                setTimeout(() => {  
                    console.log(this.num);  //this指向函数的宿主对象了 
                });  
            }  
        }  
        obj1.fn();//4  
    
    • 多层嵌套的箭头函数
        var obj1={  
            num:4,  
            fn:function(){  
                var f=() => {    //object,也就是指obj1  
                    console.log(this);  
                    setTimeout(() => {  
                        console.log(this);//object,也就是指obj1  
                    });  
                }  
                f();  
            }  
        }  
        obj1.fn();  
    

    改动一处箭头函数

        var obj1={  
            num:4,  
            fn:function(){  
                var f=function(){      
                    console.log(this); 
                  //函数f定义后并没有对象调用,this直接绑定到最外层的window对象  
                    setTimeout(() => {  
                        console.log(this);
                    //外层this绑定到了window,内层也相当于定义在window层(全局环境)  
                    });  
                }  
                f();  
            }  
        }  
        obj1.fn();  
    
        var obj1={  
            num:4,  
            fn:function(){  
                var f=() => {      
                    console.log(this); 
                   //object,f()定义在obj1对象中,this就指向obj1,这是箭头函数this指向的关键  
                    setTimeout(function() {  
                        console.log(this);
                         //window,非箭头函数的情况下还是要看宿主对象是谁
                         //如果没有被对象调用,函数体中的this就绑定的window上  
                    });  
                }  
                f();  
            }  
        }  
        obj1.fn();  
    
    • 1.箭头函数的this绑定看的是this所在的函数定义在哪个对象下,绑定到哪个对象则this就指向哪个对象
    • 2.如果有对象嵌套的情况,则this绑定到最近的一层对象上

    相关文章

      网友评论

        本文标题:JavaScript中的this

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