js 在不同情况下的 this 指向问题也是难倒了很多萌新。今天小编详细讲解一下下列几种情况 this 的指向问题。
1. 普通函数调用
function person() {
this.name = "l";
console.log(this);
console.log(this.name);
}
person(); //输出
这种情况想必大家都知道 最后输出的是 window 和 1 。函数自执行 this 指向的是 window 。
2. 作为方法来调用
var name="1";// 此时的 name 是属于 window 下的 name,即可以通过 window.name 访问。
var person={
name:"2",
showName:function(){
console.log(this.name);//person
}
}
person.showName(); //输出
此时输出的是 2 , 这里是 person 对象调用 showName 方法,很显然 this 关键字是指向 person 对象的,所以会输出 name 。
var personA={
name:"1",
showName:function(){
console.log(this.name);
}
}
var personB={
name:"2",
sayName:personA.showName
}
personB.sayName(); //输出
此时输出的是 2 ,你可以这么理解。将 personA.showName 这个函数赋给了personB 的 sayName。
即此时的 personB 为 :
var personB={
name:"2",
sayName:function(){
console.log(this.name);
}
}
再使用 personB 对象调用 sayName 的方法,显然 this 指向的是 personB 对象了。
3. 作为构造函数来调用
function Person(name){
this.name=name;
}
var personA=Person("1");
console.log(window.name);//输出
console.log(personA.name); // 输出
此时会输出 1 以及报错 error :‘name’ of undefined。在此例中 person(“1”) 相当于函数自执行,所以 this 将会指向 window 。即 this.name=name —> window.name = name。所以 personA 中并没有定义 name 属性,所以会报错。这是在没有使用实例化的情况。使用了 new 关键字实例化情况就不同了。
function Person(name){
this.name=name;
}
var personB=new Person("1");
console.log(personB.name);// 输出
此时输出的是 1,因为 在实例化中 this 执行实例对象,本例中实例对象为 personB。
4.call/apply方法的调用
call/apply方法最大的作用就是能改变this关键字的指向(对象冒充)。
var name="1";
var Person={
name:"2",
showName:function(){
console.log(this.name);
}
}
Person.showName.call();
//这里 call 方法里面的第一个参数为空,默认指向 window 。所以这里输出的会是1.
再看一组难一点的,小伙伴们要做好准备哦。
function FnA(n1,n2){
this.n1=n1;
this.n2=n2;
this.change=function(x,y){
this.n1=x;
this.n2=y;
}
};
var fn1=new FnA("1","2");
var fn2={
n1:"3",
n2:"4"
};
fn1.change.call(fn2,"5","6");
console.log(fn2.n1); //输出
console.log(fn2.n2);// 输出
此时输出的就会是 5,6。因为 call 就是用来改变 this 指向的,即 fn1.change.call 在执行中 this 指向的是 fn2 ,即 this.n1 = x 相当于 fn2.n1 = x。x 为传过来的 5。所以最终输出的会是5。apply 方法和 call 方法是一样的,唯一不同的是传参的时候。apply 传的是数组。
fn1.change.call(fn2,"5","6");
相当于
fn1.change.apply(fn2,["5","6"]);
PS:如果能熟练使用 call 和 apply ,会为你的代码大放光彩。
5.箭头函数
es6里面this指向固定化,因为箭头函数没有this,它使用的 this 其实就是父级作用域的 this ,所以始终指向外部对象。因此它自身不能进行new实例化,同时也不能使用call, apply, bind等方法来改变this的指向。
function Timer() {
this.seconds = 0;
setInterval( () => this.seconds ++, 1000);//this继承父级作用域
}
var timer = new Timer();
setTimeout( () => console.log(timer.seconds), 3100);
在构造函数内部的setInterval()内的回调函数,this始终指向实例化的对象, 并获取实例化对象的seconds的属性,每1s这个属性的值都会增加1。所以最终会输出 3。