學習軌道
/
JavaScript
JavaScript
/
練習
/
回收機器人
回收機器人

回收機器人

學習練習

簡介

了解一份資料的型別是什麼,往往對程式碼能否順暢執行、不發生錯誤非常重要。

JavaScript 有幾種方法可以檢查一個值或物件的型別。

Note

JavaScript 的型別檢查機制有時可能不太可靠。

若想獲得更完善的型別安全與更嚴謹的型別,你或許應該改用 TypeScript。這門語言建構在 JavaScript 之上,但採用靜態型別語言的型別語法。

typeof運算子

typeof運算子會回傳其運算元的型別。 輸出結果是一個字串,會與其中一種原始資料型態的名稱相符,但"null"例外。 它也可能是"function"或"object"。

typeof undefined;
// => "undefined"

typeof true;
// => "boolean"

typeof 42;
// => "number"

typeof 'Hello, World!';
// => "string"

typeof function () {
  return 'Hello, World';
};
// => "function"

typeof [1, 2, 3, 4];
// => "object"

typeof { city: 'Stockholm', country: 'Sweden' };
// => "object"

這是[出於歷史因素][typeof null is "object"]。

instanceof運算子

若要檢查物件的型別,可以使用instanceof運算子。 它會評估為一個boolean,取決於第二個運算元是否包含在第一個運算元的原型鏈中。 更明確地說,instanceof會回傳第一個運算元是否為第二個運算元或其子類別的實例。 instanceof只適用於物件。

class Beverage {
  // ...
}

// The Coffee class is a child of the Beverage class.
class Coffee extends Beverage {
  // ...
}

const java = new Coffee();

java instanceof Coffee;
// => true

java instanceof Beverage;
// => true
Advanced

Array類別有一個名為Array.isArray()的方法,用來檢查它的引數是否為陣列。

對於在不同 realm 中建立的陣列(例如網頁中的iframe),instanceof Array不會起作用,但Array.isArray()會。

這是因為 Array 類別在每個 realm 中都有不同的建構子,而每個iframe都有自己的 realm,這表示原型鏈中的函式會不同,導致instanceof Array失敗。 Array.isArray()能夠忽略這點,因此應盡可能使用它。

它同樣能避開偽陽性的情況,也就是某個物件實際上並不是Array,只是在它的原型鏈中有Array。

({ __proto__: Array.prototype }) instanceof Array
// => true

Array.isArray({ __proto__: Array.prototype })
// => false

in運算子

in運算子會回傳第一個運算元是否為第二個運算元的屬性。 它不會檢查該屬性是否已定義值。 即使屬性的值被設為undefined,in仍然能偵測到它。

class Coffee {
  constructor() {
    this.temperature = 'hot';
    this.isDarkMatter = undefined;
  }

  coolDown() {
    this.temperature = 'warm';
  }
}

const espresso = new Coffee();

'temperature' in espresso;
// => true

'color' in espresso;
// => false

'isDarkMatter' in espresso;
// => true
Note

對於繼承而來的屬性和方法,in會回傳true。

"coolDown" in espresso
// => true

"constructor" in espresso
// => true

若要避免這種情況,請改用Object.hasOwn()

Object.hasOwn()函式

Object.hasOwn()方法會回傳指定的物件是否_擁有給定的屬性_(該屬性並非繼承而來,也不是方法)。

class Coffee {
  constructor() {
    this.temperature = 'hot';
  }

  coolDown() {
    this.temperature = 'warm';
  }
}
const cappuccino = new Coffee();

Object.hasOwn(cappucino, 'temperature');
// => true

Object.hasOwn(cappucino, 'constructor');
// => false

Object.hasOwn(cappucino, 'coolDown');
// => false

說明

說明

你受僱於一間回收中心。 由於空間不足,所有產品都被放上同一條輸送帶,但這導致不同材質混在一起,變得無法使用。 為了解決這個問題,你的任務是撰寫一些函式來辨識產品的類型。

1. 檢查一個值是否為布林值

實作isBoolean函式,檢查某個值是否為布林值。

isBoolean(true);
// => true

isBoolean(null);
// => false

2. 檢查一個值是否為數字

實作isNumber函式,檢查某個值是否為有限的number或bigint,也就是不是NaN或Infinity。

有時讀取 ID 的裝置會故障,把非數值的值讀成NaN(Not a Number,不是數字)或Infinity。 你的函式也應該能正確處理這種情況。

isNumber(42);
// => true

isNumber('Hello, World!');
// => false

isNumber(42n);
// => true

isNumber(NaN);
// => false

3. 檢查一個值是否為物件

實作isObject函式,檢查某個值是否為物件。 在輸送帶上,null代表什麼都沒有,不算是一個物件。

isObject({ greeting: 'Hello' });
// => true

isObject(25n);
// => false

4. 檢查一個字串是否為數字字串

實作isNumericString函式,檢查某個值是否為只由數字,或是由一個減號後面接著數字(代表負數)所組成的字串。 這裡只考慮整數;對回收機器人的這項檢查來說,小數不算數值。

isNumericString(42);
// => false

isNumericString('42');
// => true

isNumericString('Hi!');
// => false

5. 檢查一個物件是否為電子裝置

實作isElectronic函式,檢查某個物件是否為提供的ElectronicDevice類別的實例,或是它的子類別之一。

class Duck {
  //...
}

class WashingMachine extends ElectronicDevice {
  //...
}

isElectronic(new Duck());
// => false

isElectronic(new WashingMachine());
// => true

6. 檢查一個值是否為非空陣列

實作isNonEmptyArray函式,檢查某個值是否為非空陣列。

isNonEmptyArray([1, 2, 3]);
// => true

isNonEmptyArray([]);
// => false

7. 檢查一個值是否為空陣列

實作isEmptyArray函式,檢查某個值是否為空陣列。

isEmptyArray([1, 2, 3]);
// => false

isEmptyArray([]);
// => true

8. 檢查一個物件是否有type屬性或是方法

實作hasType函式,檢查某個物件是否有type屬性或是方法。

class Keyboard(){
  type(){
    // ...
  }
}
hasType({ type:"car", color:"red" })
// => true

hasType({ color:"green" })
// => false

hasType(new Keyboard())
// => true

9. 若物件缺少id屬性或是方法,就拋出錯誤

實作assertHasId函式,當物件缺少id屬性時,會拋出Error。

如果物件確實有id屬性,就不應該回傳任何東西。

assertHasId({ id: 42, color: 'red' });
// => undefined

assertHasId({ color: 'green' });
// Error: "Object is missing the 'id' property"

10. 檢查一個物件是否有id屬性

實作hasIdProperty函式,檢查某個物件是否有id屬性。

class SimpleData {
  constructor() {
    this.number = '42';
    this.id = 'BC269327FE1D9B95';
  }
}

class StealingData extends SimpleData {}

class MethodData {
  constructor() {
    this.number = '42';
    this._id = 'BC269327FE1D9B95';
  }

  get id() {
    return this._id;
  }
}

hasIdProperty(new SimpleData());
// => true

hasIdProperty(new MethodData());
// => false

hasIdProperty(new StealingData());
// => false

11. 檢查一個物件是否有已定義的type屬性

實作hasDefinedType函式,檢查某個物件是否有不是undefined的type屬性。

hasDefinedType({ type: undefined, color: 'red' });
// => false

hasDefinedType({ type: 'car', color: 'green' });
// => true
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
JavaScript Exercism

準備好開始 回收機器人 了嗎?

註冊 Exercism,透過 37 個概念159 個練習 和真人引導來學習並精通 JavaScript,全部免費。