JavaScript this指向总结

JS中this的指向有些复杂,分为较多种的情况。此外,在严格模式和非严格模式之间也会有一些差别。

注:node环境中的全局变量global统一对应浏览器环境中的全局变量window。

全局环境

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true

无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。


纯粹的函数调用

严格模式

function test(){
    "use strict"; 
    // 这里是严格模式
    return this;
  }
  console.log( test() === undefined);
//   true
  console.log( window.test() === window);
//   true

可以看到严格模式下,因为没有调用test方法的对象,于是this指向undefined,当我们注明了使用window调用的时候,于是指向了window全局对象。

非严格模式

var a="123";
let b="321";
function test(){
    console.log(this.a);
    console.log(this.b);
}
test(); 
// 123
// undefined

这里我们看到this指向执行test这个方法的对象,前面是空的,同时也是非严格模式,也就是window对象,于是this.a等于window.a。
var将a变量添加到window这个对象下面。let不会将b变量添加到window下面。
ES6中建议使用let 和const 代替原来的var。


对象中的方法调用

let obj={
    a:"123",
    test:function(){
        console.log(this.a);
    }
}
obj.test();
// 123

此时this指向执行test的obj,自然顺利成章的this.a等于obj.a。


方法中内部方法的调用

var a="123";
let obj ={
    a:"321",
    test:  function(){
        return function(){
            console.log(this.a);
        }
    }
}
obj.test()();
// 123

方法内部的方法(闭包)中的this统一指向window。


构造方法中的调用

function Person(age){
    this.name="123";
    this.age=age;
}
let worker=new Person(33);
console.log(worker.name);
// 123

构造函数中的this.name最终会指向实例自己的属性。它的this被绑定到正在构造的新对象。


bind,apply,call中的调用

let obj={
    a:"123",
    test:function(){
        console.log(this.a);
    }
}
let g = obj.test.bind({a:"444"});
g();
// 444
let h = g.bind({a:'555'}); // bind只生效一次!
h();
// 444
obj.test.call({a:"222"},1,2,3);
// 222
obj.test.apply({a:"333"},[1,2,3]);
// 333

bind会创建一个与obj.test具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
上面的g已经指向绑定过了的obj.test,于是想要再次绑定g的this就失效了。
call,apply后的第一个参数决定了this的指向。
call的第23456等等参数是独立的值。
apply的第二个参数是数组。


箭头函数


var a="123";

let obj={
    a:"321",
    test:()=>{
        console.log(this.a);
    }
}

obj.test();
//123
let obj={
    a:"123",
    test:function(){
        let testyou= ()=>{
            console.log(this.a);
        }
        testyou();     
    }
}
obj.test();
//123
obj.test.apply({a:"321"});
//321

注意:如果将this传递给call、bind、或者apply,它将被忽略。不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null。
对于箭头函数的this,看了挺多的文章,我个人是这样理解的:

1.从箭头函数那一层逐渐向外看。
2.只要是对象,跳过,继续向外,如果到头了,没有遇到方法,恭喜,那么箭头函数的this指向window。
3.如果外部某一层是方法,停下,思考该方法下的this 指向,箭头函数的this继承于它。

第一个例子:test被定义为箭头函数,它的外层是个对象obj,跳过,到头了,于是指向window
第二个例子:testyou被定义为箭头函数,它的外层是test方法,于是寻找执行这个test方法时内部的this指向,指向obj,于是箭头函数的this指向obj。随后用apply改变test函数的this指向,箭头函数的this所以继承了改变。

你可能感兴趣的:(JavaScript this指向总结)