7個關於"this"面試題,你知道幾個?

前端小智發表於2021-11-02
作者:Shadeed
譯者:前端小智
來源:dmitripavlutin

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

在JavaScript中,this 表示函式呼叫上下文。this難點在於它有一個複雜的行為,這也是面試中經常被考的點。

本文列舉7個關於this有趣的面試問題:

  • 問題1:變數 vs 屬性
  • 問題2:Cat 的名字
  • 問題3:延遲打招呼
  • 問題4:人工方法
  • 問題5:問候和告別
  • 問題6:棘手的 length
  • 問題7:呼叫引數

問題1:變數 vs 屬性

下面的列印結果是啥:

const object = {
  message: 'Hello, World!',

  getMessage() {
    const message = 'Hello, Earth!';
    return this.message;
  }
};

console.log(object.getMessage()); // ??

答案:'Hello, World!'

object.getmessage()是一個方法呼叫,此時的 this 表示 object

方法還有一個變數宣告const message = 'Hello, Earth!'。這個變數都不會影響this.message的值。

問題2:Cat 的名字

下面程式碼列印什麼:

function Pet(name) {
  this.name = name;

  this.getName = () => this.name;
}

const cat = new Pet('Fluffy');

console.log(cat.getName()); // What is logged?

const { getName } = cat;
console.log(getName());     // What is logged?

答案:'Fluffy''Fluffy'

當函式作為建構函式new Pet('Fluffy')呼叫時,建構函式內部的this等於構造的物件

Pet建構函式中的this.name = name表示式在構造的物件上建立name屬性。

this.getName = () => this.name在構造的物件上建立方法getName。 而且由於使用了箭頭函式,箭頭函式內部的this值等於外部作用域的this值, 即 Pet

呼叫cat.getName()以及getName()會返回表示式this.name,其計算結果為'Fluffy'

問題3:延遲打招呼

下面程式碼列印什麼:

const object = {
  message: 'Hello, World!',

  logMessage() {
    console.log(this.message); // What is logged?
  }
};

setTimeout(object.logMessage, 1000);

答案:1秒後,列印 undefined

儘管setTimeout()函式使用object.logMessage作為回撥,但仍將object.logMessage用作常規函式,而不是方法。

在常規函式呼叫期間,this等於全域性物件,即瀏覽器環境中的 window。

這就是為什麼logMessage方法中的 this.message等於 window.message,即undefined

問題4:人工方法

如何呼叫logMessage函式,讓它列印 "Hello, World!" ?

 message: 'Hello, World!'
};

function logMessage() {
  console.log(this.message); // "Hello, World!"
}

答案:

至少有 3 種方式,可以做到:

 message: 'Hello, World!'
};

function logMessage() {
  console.log(this.message); // logs 'Hello, World!'
}

// Using func.call() method
logMessage.call(object);

// Using func.apply() method
logMessage.apply(object);

// Creating a bound function
const boundLogMessage = logMessage.bind(object);
boundLogMessage();

問題5:問候和告別

下面程式碼列印什麼:

const object = {
  who: 'World',

  greet() {
    return `Hello, ${this.who}!`;
  },

  farewell: () => {
    return `Goodbye, ${this.who}!`;
  }
};

console.log(object.greet());    // What is logged?
console.log(object.farewell()); // What is logged?

答案: 'Hello, World!''Goodbye, undefined!'

當呼叫object.greet()時,在greet()方法內部,this值等於 object,因為greet是一個常規函式。因此object.greet()返回'Hello, World!'

但是farewell()是一個箭頭函式,箭頭函式中的this值總是等於外部作用域中的this值。

farewell()的外部作用域是全域性作用域,它是全域性物件。因此object.farewell()實際上返回'Goodbye, ${window.who}!',它的結果為'Goodbye, undefined!'

問題6:棘手的 length

下面程式碼列印什麼:

var length = 4;
function callback() {
  console.log(this.length); // What is logged?
}

const object = {
  length: 5,
  method(callback) {
    callback();
  }
};

object.method(callback, 1, 2);

答案: 4

callback()是在method()內部使用常規函式呼叫來呼叫的。由於在常規函式呼叫期間的this值等於全域性物件,所以this.length結果為window.length。。

第一個語句var length = 4,處於最外層的作用域,在全域性物件 window 上建立一個屬性length

問題7:呼叫引數

下面程式碼列印什麼:

var length = 4;
function callback() {
  console.log(this.length); // What is logged?
}

const object = {
  length: 5,
  method() {
    arguments[0]();
  }
};

object.method(callback, 1, 2);

答案: 3

obj.method(callback, 1, 2)被呼叫時有3個引數:callback, 12。結果,method()內部的引數特殊變數是如下結構的陣列類物件:

{
  0: callback,
  1: 1, 
  2: 2, 
  length: 3 
}

因為arguments[0]()是arguments物件上的回撥的方法呼叫,所以回撥內部的引數等於arguments。 所以 callback()中的this.lengtharguments.length相同,即3

~ 完,我是小智,我要去刷碗了,我們下期見!


程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:https://dmitripavlutin.com/ja...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章