一篇就够-this指向

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指向)