美文网首页
一篇就够-this指向

一篇就够-this指向

作者: johe_jianshu | 来源:发表于2020-03-24 19:15 被阅读0次

    this的指向

    用一句话概括:this永远指向最后调用函数的对象
    this可以理解为JS的动态作用域,而JS默认的静态作用域是在函数创建的时候就决定了。

        var name = "windowsName";
        function a() {
            var name = "Cherry";
    
            console.log(this.name);          // windowsName
    
            console.log("inner:" + this);    // inner: Window
        }
        a();
        console.log("outer:" + this)         // outer: Window复制代
    
    
    

    最后调用a的地方a(),前面没有调用的对象那么就是全局对象 window,这就相当于是 window.a()。如果使用严格模式的话,全局对象就是 undefined,那么就会报错 Uncaught TypeError: Cannot read property 'name' of undefined。

        var name = "windowsName";
        var a = {
            name: "Cherry",
            fn : function () {
                console.log(this.name);      // Cherry
            }
        }
        a.fn();//Cherry
        window.a.fn();//Cherry,最后调用的对象为a
    

    a.fn()与window.a.fn()最后调用对象为a,所以this指向a

       
       var name = "windowsName";
       var a = {
           // name: "Cherry",
           fn : function () {
               console.log(this.name);      // undefined
           }
       }
       window.a.fn();
    

    最后调用对象为a,只会在a中查找,不会往上继续查找

        var name = "windowsName";
        var a = {
            name : null,
            // name: "Cherry",
            fn : function () {
                console.log(this.name);      // windowsName
            }
        }
        var f = a.fn;
        f();
    

    最后调用对象为window

        var name = "windowsName";
        function fn() {
            var name = 'Cherry';
            innerFunction();
            function innerFunction() {
                console.log(this.name);      // windowsName
            }
        }
        fn()
    

    this优先级

    • 第一层:世界尽头(全局)
      优先级最低,在默认情况下是全局,浏览器里就是window,在严格模式下就是undefined
    function showThis(){
        console.log(this); 
    }
    
    function showThisWithStrict(){
        'use strict';
        console.log(this);
    }
    showThis();//window
    showThisWithStrict();//undefined
    
    • 第二层:点石成金(.操作符)

    说白了就是找函数前面的.操作符,如果用到this的函数属于某个上下文对象,那么这个上下文对象绑定到this。
    遵循上文所说的"this指向最后调用它的对象"

    var boss = {
      name: 'boss',
      returnThis () {
        return this
      }
    }
    
    boss.returnThis() === boss // true
    
    

    遵循this指向最后调用它的对象:

    var boss1 = {
      name: 'boss1',
      returnThis () {
        return this
      }
    }
    
    var boss2 = {
      name: 'boss2',
      returnThis () {
        return boss1.returnThis()
      }
    }
    
    var boss3 = {
      name: 'boss3',
      returnThis () {
        var returnThis = boss1.returnThis
        return returnThis()
      }
    }
    
    // boss1
    boss1.returnThis()
    // boss1,实际上是调用boss1.returnThis()指向boss1
    boss2.returnThis() 
    // undefined或window,实际上是window.returnThis()
    boss3.returnThis()
    
    

    把this绑定到boss2:

    var boss1 = {
        name:'boss1',
        returnThis(){
            return this
        }
    }
    
    var boss2 = {
        name:'boss2',
        returnThis: boss1.returnThis
    }
    
    boss2.returnThis()//boss2
    
    • 第三层:指腹为婚(call和apply)
      Object.prototype.call和Object.prototype.apply,它们可以通过参数指定this。

    由于函数的构造函数是function Function(),而Function.prototype是对象,即Function.prototype.proto === Object.prototype,所以函数(函数也是对象)拥有call和apply方法

    function returnThis(){
        return this;
    }
    
    var boss1 = { name: "boss1" };
    
    returnThis();//window
    returnThis.call(boss1);//boss1
    returnThis.apply(boss1);//boss1
    
    
    • 第四层:海誓山盟(bind)
      Object.prototype.bind,会提供一个新函数来进行永久的this绑定,call和apply不能修改。
    function returnThis(){
        console.log(this.name);
    }
    
    var boss1 = { name:'boss1' };
    
    //绑定this为boss1,并返回这个绑定后的函数
    var bindBoss1ReturnThis = returnThis.bind(boss1);
    
    bindBoss1ReturnThis();//boss1
    
    var boss2 = { name:'boss2' };
    bindBoss1ReturnThis.call(boss2);//boss1
    bindBoss1ReturnThis.apply(boss2);//boss1
    bindBoss1ReturnThis.bind(boss2)();//boss1
    
    • 第五层:内有乾坤(new)
      当我们使用new constructor实例化一个对象时,就会自动绑定this到对象上。会覆盖掉bind绑定的this。
    function showThis(){
        console.log(this);
    }
    
    new showThis(); //showThis实例
    showThis(); //window
    
    var boss1 = { name:'boss1' }
    var boss1ShowThis = showThis.bind(boss1);
    boss1ShowThis();//boss1
    
    new boss1ShowThis(); //showThis实例
    
    
    • 第六层:军令如山(箭头函数)
      箭头函数里的this,被封印到当前词法作用域之中,称作Lexical This,在代码运行前就可以确定。

    箭头函数的作用就相当于把this这个原本为动态作用域的,改成静态作用域,在函数创建时就能够通过箭头函数把this确定下来。

    箭头函数中没有this绑定,必须通过查找作用域链(静态作用域的特性)来决定其值,如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则,this为undefined

    其余五层的this都是动态作用域,不会根据作用域链向上找,只会根据当前上下文对象的this查找,箭头函数的this,在函数创建的时候就已经确定,为最近的不为箭头函数的this

    
        var name = "windowsName";
    
        var a = {
            name : "Cherry",
    
            func1: function () {
                console.log(this.name)     
            },
    
            func2: function () {
                setTimeout( () => {
                    this.func1()
                },100);
            }
    
        };
    
        a.func2()     // Cherry
    
    var returnThis = () => this
    
    returnThis() // window
    new returnThis() // TypeError
    
    var boss1 = {
      name: 'boss1',
      returnThis () {
        var func = () => this
        return func()
      }
    }
    
    returnThis.call(boss1) // still window
    
    var boss1returnThis = returnThis.bind(boss1)
    boss1returnThis() // still window
    
    boss1.returnThis() // boss1
    
    var boss2 = {
      name: 'boss2',
      returnThis: boss1.returnThis
    }
    
    boss2.returnThis() // boss2
    
    

    最近的不为箭头函数的this,依旧遵循上述规则,是动态作用域:
    boss1.returnThis.call(window),修改了returnThis的this指向,在执行returnThis的时候,创造箭头函数func,此时this绑定为returnThis的this,当前returnThis的this为window,所以func中的this也指向window.

    this的特殊情况

    在"," "=" "||"操作符的情况下,this指向为全局

    var value = 1;
    
    var foo = {
      value: 2,
      bar: function () {
        return this.value;
      }
    }
    
    //示例1
    console.log(foo.bar()); // 2
    //示例2
    console.log((foo.bar)()); // 2
    //示例3
    console.log((foo.bar = foo.bar)()); // 1
    //示例4
    console.log((false || foo.bar)()); // 1
    //示例5
    console.log((foo.bar, foo.bar)()); // 1
    

    相关文章

      网友评论

          本文标题:一篇就够-this指向

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