iT邦幫忙

2022 iThome 鐵人賽

DAY 16
1

前言

這篇要介紹的是用 instanceof 這個函式,將會沿用上一篇的範例進行解說。


語法

instanceof 這個運算子用於檢測某個建構函式的 prototype 是否出現在某個實體物件的原型鏈上。

語法如下:

object instanceof constructor

  • object 為帶入的實體物件
  • constructor 為建構函式

從範例認識 instanceof

讀者可以先閱讀以下程式碼,這個範例跟上一篇比起來,差異在最後面增加了幾行的程式碼,其中使用到了 instanceof。

function Shape(x, y) {
  this.x = x;
  this.y = y;
}

Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
};

function Rectangle(...args) {
  Shape.apply(this, args);
}

const properties = {
  name: {
    value: "長方形",
    enumerable: true,
    writable: true,
  },
  getPos: {
    value: function () {
      console.log(`Current Position: ${this.x}, ${this.y}.`);
    },
  },
};

Rectangle.prototype = Object.create(Shape.prototype, properties);
Rectangle.prototype.constructor = Rectangle;

const rect = new Rectangle(0, 0);

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true

前面說到 instanceof 這個運算子用于檢測某個建構函式的 prototype 是否出現在某個實體物件的原型鏈上,所以觀察程式碼後,會發現 rect instanceof Rectangle 或是 rect instanceof Shape 都是 true。

對照圖來看,的確 Rectangle 和 Shape 的 prototype 都在原型鏈上。


使用 instanceof 判定型別

因為使用 typeof 去判斷物件型別時蠻多情況都會印出 object,所以改成用 instanceof,可以更加細分例如是陣列、物件、Date 物件...等。

console.log(typeof 123); // 'number'
console.log(typeof Infinity); // 'number'
console.log(typeof NaN); // 'number'

console.log(typeof '123'); // 'string'

console.log(typeof true); // 'boolean'
console.log(typeof false); // 'boolean'

console.log(typeof Symbol()); // 'symbol'

console.log(typeof Object); // 'function',因為實際上這個 Object 是 Object() constructor
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/Object

console.log(typeof Object.prototype); // 'object'

console.log(typeof null); // 'object',null 因為 JS 早期設計的問題,所以也被判定為 null
console.log(typeof [1, 2, 3]); // 'object'
console.log(typeof { name: 'harry' }); // 'object'
console.log(typeof new Date); // 'object'
console.log(typeof function() {}); // 'function'

console.log([1, 2, 3] instanceof Array); // true
console.log({ name: 'harry' } instanceof Object); // true
console.log(new Date() instanceof Date); // true
console.log(new String() instanceof String); // true
console.log(function() {} instanceof Function); // true

// 這裡需要注意的是陣列、函式、Date 物件等用 `instanceof Object` 判定也會是 true,可以去思考原型鏈就能理解
console.log([1, 2, 3] instanceof Object); // true
console.log(new Date() instanceof Object); // true
console.log(function() {} instanceof Object); // true

其他判斷型別的方式-2023/07/31 補充

  1. Array.isArray() 可以判斷是否一個變數值是一個陣列
  2. Object.prototype.toString() 也能判斷物件型別是哪陣列、函式還是物件
const arr = [1, 2, 3];
const fn = () => {
  return 123;
};
const obj = { foo: 123 };

console.log(Object.prototype.toString.call(arr)); // [object Array]
console.log(Object.prototype.toString.call(fn)); // [object Function]
console.log(Object.prototype.toString.call(obj)); // [object Object]

實作 instanceof

最後,我們來嘗試著自己實作一個 instanceof。

實作的觀念就是根據原型鏈一直去找指定物件(第一個參數)的 __proto__,如果有找到,就回傳 true,原型鏈都找完還是沒找到則回傳 false。

function myInstanceof(obj, target) {
  while (true) {
    if (obj === null) return false;
    
    if (obj === target.prototype) return true;
    
    obj = obj.__proto__;
  }
}

我們可以將前面範例的 rect 物件和 Rectangle、Shape 函式拿來驗證:

console.log(myInstanceof(rect, Rectangle) );
// true,因為 rect.__proto__ === Rectangle.prototype
console.log(myInstanceof(rect, Shape) );
// true,因為 rect.__proto__.__proto__ === Rectangle.prototype
console.log(myInstanceof(rect, String) );
// false,原型鏈找不到 String.prototype

原型繼承的系列文就到這邊結束了,明天將會進入重要的非同步處理的系列。


參考資料 & 推薦閱讀

MDN instanceof

自己实现一个instanceof


上一篇
Day15-Object.create() 介紹
下一篇
Day17-JavaScript Promise 系列-認識 Promise
系列文
強化 JavaScript 之 - 程式語感是可以磨練成就的30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言