this指向问题
是不是经常搞不懂所谓的this指向,到底指向谁?一头雾水,越看越头大
别急 ! this指向是在面试中经常会考到知识点,也就要求我们必须掌握,但是大多数人总是会判断错误,接下来就仔细看一下这篇文章吧
this指向可以分为四种情况
我们从最容易分辨的开始
1. obj.fn() 也就是方法调用模式 this----> obj
这个其实也是比较好理解的,就是谁调用指向说,this就指向我们的obj
注意: 区分obj.fn() 和 obj.fn ,一个是调用了函数,是函数执行之后的 ,一个是赋值,把函数obj了,并没哟调用
两者在this指向上也有区别,obj.fn() this指向obj,而后者指向window
是不是觉得自己好像懂了一点点了,是不是觉得这个obj.fn()太简单了,别急,我们做几道题来巩固一下
// 练习1
function sayHi() {
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
// 这个其实也很好理解,就是典型的obj.fn() 所以this--->person
person.sayHi(); // YvetteLau
是不是自信心来了,来看下一题
//练习2
function sayHi() {
console.log('Hello,', this.name);
}
var person2 = {
name: 'Christina',
sayHi: sayHi
}
var person1 = {
name: 'YvetteLau',
friend: person2
}
// 当我们的obj.fn()多层调用的时候,我们不管调用了多少层,this都是指向离他最近的obj的,也就是this---> friend
person1.friend.sayHi(); // Christina
有新增加了一个小的知识点,当this多层调用的时候,我们的this指向就只会指向自己最近的,无论多少层,还是指向最近的obj
再来看一个让你怀疑人生的题
// 练习3
function sayHi() {
console.log('Hello,', this.name);
}
var person1 = {
name: 'YvetteLau',
sayHi: function () {
setTimeout(function () {
console.log('Hello,', this.name);
})
}
}
var person2 = {
name: 'Christina',
sayHi: sayHi
}
var name = 'Wiliam';
person1.sayHi(); // Wiliam
// 这个就是需要区分setTimeout和sayHi里面的有没有关系?
// 答案肯定是否定的,没有一点关系,就像你家的钱和隔壁家的,完全没有关系,有关系也就是都是钱而已
// 此时 person2.sayHi并没有加括号,也就是赋值,此时this---> window
setTimeout(person2.sayHi, 100); //Wiliam
setTimeout(function () {
//这个就是真的典型的obj.fn() ,所以this--> person2
person2.sayHi(); //YvetteLau
}, 200);
有的人看见obj.fn就毫不犹豫的相信this-->obj,所以就认为person1.sayHi() 中的this指向person1,就直接接的输出为YvetteLau
但是我们需要考虑一下,person1.sayHi()里面有个函数,也就意味着,虽然sayHi里面的this指向this,单数setTimeout里面的this并不指向person1 ,而是指向window,所以打印出来wiliam\
好了,可别怀疑自己,接下来就是真的容易的啦
2. 上下文调用模式 this ---> call apply bind的第一个参数
我们用的方法中,call apply bind的第一个参数就是用来改变我的this指向的,this就指向第一个参数
但是,需要注意,当把unll 和undefined当做第一个参数传递给它们的时候,this指向就是不生效了,this-->window
这个也可以简单理解为,你都把unll和undefined传给call了,this能指向谁?指向null?也不现实,所以它只能去外面找window
function sayHi() {
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
var Hi = person.sayHi;
// this --> person
Hi.call(person); // YvetteLau
3. new this---->新创建的对象
看到这个,我们首先需要明确new做了四件事情
1. 创建一个新的对象
2. 将构造函数赋值给新的对象,并将this指向新的对象
3. 执行构造函数
4. 返回这个对象
这个也就不难理解,this就指向我们新创建的对象
function sayHi(name) {
this.name = name;
}
var name = 'zs'
var Hi = new sayHi('Yevtte');
console.log('Hello,', Hi.name); // Yevtte
4. 其他 this ---> window
首先回顾一下下上面三种情况
1.obj.fn() this-->obj 2. call apply bind this-->他们的第一个参数 3. new this-->新创建的对象
有了这三个明显的特点,其他的就是咱们的第四种 this ---> window
不绝对,但是大部分都是
function sayHi(name) {
console.log('Hello,', this.name);
}
var name = 'YvetteLau';
sayHi('zs'); // YvetteLau
这个可能也会有疑惑,但是仔细判断一下, sayHI('zs') ,不符合obj.fn()也没有call和new,所以就是第三种情况,this-->window
有没有觉得自己有一点稍微懂了一点点了,再给一个终极大烧脑的题
var number = 5; // 10 20
var obj = {
number: 3, //6
fn: (function () {
var number; // 3 9 27
this.number *= 2; // 10
number = number * 2; // NaN
number = 3; //3
return function () {
var num = this.number; //10 3
this.number *= 2; // 20 6
console.log(num);
number *= 3; // 9 27
console.log(number);
}
})()
}
var myFun = obj.fn; // this--> window
myFun.call(null); //this-->window 10 9
obj.fn(); //this --> obj 3 27
console.log(window.number); // 20
最后打印出来就是 10 9 3 27 20
不要怀疑自己,因为里面还运用到了一个匿名函数自调用
当var了obj的时候,就已经执行了fn里面的函数,并且返回了return后面的值,
此时obj.fn就已经等于了return后面的这个函数
所以在下面执行的时候,就不会再执行return前面的,直接从return后面的开始,然后判断每个引用的this指向就可以得出值了
好好思考,不懂也可以交流