博客 / 詳情

返回

再也不怕面試中this的指向問題

參考

【第1318期】深入淺出 JavaScript 關鍵詞 -- this
https://juejin.cn/post/684490...

寫這篇文章原因

因為總結面經中遇到了this的指向問題,這也是面試官常問的基礎問題。所以單獨列出來供參考學習

this指向幾點判斷規則

js的函數除了聲明定義的形參之外,每個函數還接受兩個附加參數:this和arguments。this 的值並不是由函數定義放在哪個對象裏面決定,而是函數執行時由誰來喚起決定。

  1. 函數調用模式:strict情況下,指向undefined,否則指向全局變量
  2. 方法調用模式:指向方法所在的對象
  3. 構造函數模式調用,用new時,this指向新構建的對象
  4. apply,call明確綁定: 或者bind綁定,this指向被綁定的對象
  5. 箭頭函數內部的this就是外層代碼塊的this,包裹在函數中時this指向函數調用時所在的對象,若放在全局中則是指向全局對象window,且不會改變

    // Q1 規則1:如果一個函數中有this,但是它沒有被上一級的對象所調用,那麼this指向的就是window
    var a = 1;
    function print () {
     console.log(this.a)
    }            
    print()  //a=1
    
    // Q2 規則2:如果一個函數中有this,這個函數有被上一級的對象所調用,那麼this指向的就是上一級的對象。
    const obj = {
     a: 2,
     print: function () { console.log(this.a) }
    }
    obj.print();  //2
    ​
    // Q3 
    const obj = {
     a: 3,
     print: function () { console.log(this.a) }
    }
    obj.print()  //3  與下面的foo()區別在於是全局環境還是obj環境
    const foo = obj.print; 
    foo()     //undefined      全局情況下調用的,沒有全局變量a
    
    // Q3.1   如果一個函數中有this,這個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象
    const obj = {
     a: 3,
     printOut:{
         a:4,
         printIn: function(){ console.log(this.a)},
     },
    }
    obj.printOut.printIn()    //4 
    const foo = obj.printOut.printIn;  
    foo()     //undefined      全局情況下調用的,沒有全局變量a
    ​
    // Q4  Q4-Q9參見規則5
    const obj = {
     a: 4,
     print: () => { console.log(this.a) }
    }
    obj.print();                 //undefined     有箭頭函數,對象不構成單獨的作用域,導致`print`箭頭函數定義時的作用域就是全局作用域。
    ​
    // Q5
    var a = 5
    const obj = {
     a: 6,
     print: () => { console.log(this.a) }
    }
    obj.print.call({a: 7}); //5         理由同上
    ​
    // Q6 
    function Person () {
     this.a = 8
     this.print = function () {console.log(this.a)}
     return {a: 9} 
    }
    const p = new Person()  
    console.log(p.a)  //9   此時p為構造函數返回的{a:9}
    console.log(p.print())  // undefined p是沒有print函數的
    ​
    // Q7 
    'use strict';
    var a = 1;
    ​
    function print () {
     console.log(this.a)
    }
    print()    //undefined 嚴格模式下,this指向undefined
    
    // Q8 普通函數
    function foo() {
      setTimeout(function() {
     console.log('id:', this.id);
      });
    }
    var id = 21;
    foo.call({ id: 42 }); //21 setTimeout是延遲函數,在foo被調用後才執行,這時候this指向window
    
    //Q9 箭頭函數,匿名函數定義時所在的執行環境就是foo函數,所以匿名函數內部的this執向始終會和foo函數的this執向保持一致,指向call的對象。
    為什麼指向call的對象呢?參見call的用法:函數名.call(對象,arg1,arg2,...argn),功能是調用函數,並把函數內部的this指向第一個參數的對象,然後將第二個及之後的是所有的參數,作為實參傳給函數。
    function foo() {
      setTimeout(() => {
     console.log('id:', this.id);
      }, 100);
    }
    
    var id = 21;
    foo.call({ id: 42 }); //42
    
    function foo() {
      setTimeout(() => {
     console.log('id:', this.id);
      }, 100);
    }
    
    var id = 21;
    foo(); //21(沒有用call)
    
    // Q10
    var A = function( name ){ 
     this.name = name;
    };
    var B = function(){ 
     A.apply(this,arguments);
    };
    B.prototype.getName = function(){ 
     return this.name;
    };
    var b=new B('sven');
    console.log( b.getName() ); // 輸出:  'sven'
    

---更新,今天看了閉包,有了新的認識

//1
var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
var a = object.getNameFunc;
a()();//這裏的調用者一直是window,因此輸出"The Window";
object.getNameFunc()();//這裏object.getNameFunc()時調用者是object,但是將object.getNameFunc()作為一個整體,他的調用者是window,是window來調用object.getNameFunc()(),此時調用者是window,因為輸出"The Window";


//2
 var name = "The Window";
  var object1 = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  object1.getNameFunc()();//這裏類似上面object.getNameFunc()時調用者是object的,但是在object1.getNameFunc()的返回函數中,將this賦值給that,因此object1.getNameFunc()()中,this仍然是object,所以輸出"My Object",
var e = object1.getNameFunc;
e()();//這裏this一直是window,因此不管如何賦值,都輸出"The Window"


//3
var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : function(){
        return this.name;
    }
};
object.getNameFunc()
//"My Object"
(object.getNameFunc)()
//"My Object"
(object.getNameFunc = object.getNameFunc)()
//"The Window"
//最後一個object.getNameFunc的值是函數本身。function (){return this.name;}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.