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指向就可以得出值了
好好思考,不懂也可以交流