天天看點

如何快速的判斷this指向this指向問題

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指向就可以得出值了

好好思考,不懂也可以交流