天天看點

【面試題】你有沒有碰到 JavaScript 一些意想不到的問題?

【面試題】你有沒有碰到 JavaScript 一些意想不到的問題?

1. 奇怪的 try..catch

❓問題

下面代碼執行後将傳回什麼?​

​2​

​​ 還是 ​

​3​

​?

(() => {
  try {
    return 2;
  } finally {
    return 3;
  }
})();      

💡解答

答案是 ​

​3​

​​,這是為什麼呢?這是因為在 ​

​try...catch...finally​

​​ 語句中,無論是否抛出異常 ​

​finally​

​​ 子句都會執行。此外,如果抛出異常,即使沒有 ​

​catch​

​​ 子句處理異常,​

​finally​

​ 子句中的語句也會執行。

📚參考

  • MDN try...catch

2. [] 和 null 都是對象

❓問題

下面 3 行代碼傳回結果是什麼?

typeof [];
typeof null;

null instanceof Object;      

💡解答

傳回結果是這樣的:

typeof []; // -> 'object'
typeof null; // -> 'object'

null instanceof Object; // false      

​typeof​

​​ 操作符傳回一個字元串,且必須符合 Table 37: typeof 操作符 傳回值​。對于沒有實作 ​

​[[Call]]​

​​ 的 ​

​null​

​​、普通對象、标準特異對象和非标準特異對象,它傳回字元串 ​

​'object'​

​。

console.log(typeof 42);
// expected output: "number"

console.log(typeof '前端自習課');
// expected output: "string"

console.log(typeof true);
// expected output: "boolean"

console.log(typeof undeclaredVariable);
// expected output: "undefined"      

但是,你可以使用 ​

​toString​

​ 方法檢查對象的類型。

Object.prototype.toString.call([]);
// -> '[object Array]'

Object.prototype.toString.call(new Date());
// -> '[object Date]'

Object.prototype.toString.call(null);
// -> '[object Null]'      

📚參考

  • MDN typeof

3. 箭頭函數傳回 undefined

❓問題

函數 ​

​f2​

​​ 執行後為什麼傳回了 ​

​undefined​

​?

let f1 = () => '前端自習課';
f1(); // -> '前端自習課'

let f2 = () => {};
f2(); // -> undefined      

💡解答

我們第一眼感覺應該是傳回 ​

​{}​

​​,可是卻傳回了 ​

​undefined​

​​,這本質原因是因為箭頭函數傳回的 ​

​{}​

​ 是箭頭函數文法的一部分,我們寫一個測試用例就能看出來:

let f2 = () => {
    return '前端自習課'
};
f2(); // -> '前端自習課'      

是以上面 ​

​f2​

​​ 函數傳回的是 ​

​undefined​

​​,當然,如果需要傳回一個 ​

​{}​

​ 對象也是可以的,隻需要使用括号将傳回值包裹起來:

let f2 = () => ({});
f2(); // -> {}      

4. 還能使用反引号執行函數?

❓問題

調用函數除了下面的方式,還有其他方式嗎?

function f(...args) {
  return args;
}

f(1, 2, 3); // -> [ 1, 2, 3 ]      

當然還有啦,我們可以使用反引号調用:

f`Hello string ${'前端自習課'}, Hello boolean ${false}, Hello array ${[1, 2, 3]}`;
/*
[
    ["Hello string ",  ", Hello boolean ", ", Hello array ", ""],
    "前端自習課",
    false,
    [1, 2, 3]
]
*/      

💡解答

這個看着很神奇的樣子,但是實際上用的是模版字元串。這是一種進階形式的模版字元串,是帶标簽的模版字元串。

上面示例代碼中:​

​f​

​ 函數是模版字面量的标簽,标簽可以用函數解析模闆字元串。标簽函數的第一個參數包含一個字元串值的數組。其餘的參數與表達式相關。

📚參考

  • MDN 模版字元串。

5. JavaScript 中也有标簽?

❓問題

下面這種寫法會有問題嗎?

foo: {
  console.log("Hello");
  break foo;
  console.log("前端自習課");
}      

💡解答

答案是沒問題,會傳回 ​

​Hello​

​​ 的字元串。因為 ​

​foo​

​​ 被識别為一個标簽,然後執行後面 ​

​console.log("Hello")​

​​,然後執行 ​

​break foo​

​ 中斷執行。

我們經常會使用帶标簽的語句和 ​

​break​

​​/​

​continue​

​ 語句一起使用,進而實作結束或繼續循環:

let str = '';

loop1:
for (let i = 0; i < 5; i++) {
  if (i === 1) {
    continue loop1;
  }
  str = str + i;
}

console.log(str);
// expected output: "0234"      

📚參考

  • MDN label

6. {}{} 是 undefined

❓問題

我們可以在控制台測試下面代碼。類似這樣的結構會傳回最後定義的對象中的值。

{}{}; // -> undefined
{}{}{}; // -> undefined
{}{}{}{}; // -> undefined
{foo: 'bar'}{}; // -> 'bar'
{}{foo: 'bar'}; // -> 'bar'
{}{foo: 'bar'}{}; // -> 'bar'
{a: 'b'}{c:' d'}{}; // -> 'd'
{a: 'b', c: 'd'}{}; // > SyntaxError: Unexpected token ':'
({}{}); // > SyntaxError: Unexpected token '{'      

💡解答

當解析到 ​

​{}​

​​ 會傳回 ​

​undefined​

​​,而解析 ​

​{foo: 'bar'}{}​

​​ 時,表達式 ​

​{foo: 'bar'}​

​​ 傳回 ​

​'bar'​

​。

這裡的 ​

​{}​

​ 有兩重含義:表示對象,或表示代碼塊。

例如,在 ​

​() => {}​

​​ 中的 ​

​{}​

​ 表示代碼塊。是以我們必須加上括号:​

​() => ({})​

​ 才能讓它正确地傳回一個對象。

if (true) {
  foo: "bar";
} // -> 'bar'      

繼續閱讀