JavaScript Object Oriented Programming: Extending Natives

JavaScript

Native JavaScript 物件將 method 存在 prototype 中。例如:當一個新的物件被建立,內容為空,但為何可以使用 toString 這個 method?(參考下面的程式碼)

var obj = {};
console.log(obj.toString());

這是因為 var obj = {} (即 var obj = new Object())。而 Object 是 Native JavaScript 的建構式,obj 由 Object 所產生,因此 obj.__proto__ == Object.prototype。所以,所有在 Object.prototype 中的屬性,obj 皆可使用(包含Object.prototype.toString)。這就是為什麼 obj 可以使用 toString 這個 method 了。對於 Array、Function 和其他物件也是相同的道理,而它們的 method 即在 Array.prototype、Function.prototype 等。

當物件的屬性被存取時,interpreter 會依照下列的順序找尋屬性的值

interpreter 會尋找這個值直到找到或下一個 __proto__ 的值為 null。Object.prototype 是唯一一個物件的 __proto__ 值為 null,因此一定會終止在 Object.prototype。換句話說,所有的物件皆繼承自 Object。

當基礎型別使用 method 會隱性的轉為物件,而其結果也會是基礎型別。例如:宣告一個變數 i 等於數字 5,並使用 toString 這個 method(參考下面的程式碼)。

var i = 5;
console.log(i.toString()); // 5

修改原生的 Prototypes

Native Prototypes 可以被修改,也可以新增新的 method 到 prototype 中。例如,我們可以新增一個新的 method「each」,將物件的屬性列印出來。

Object.prototype.each = function(f) {
  for (var prop in this) {
    if (Object.prototype.hasOwnProperty(prop)) continue;
    // 跳過後面的指令,進行下一次迴圈的執行。在此用於過濾 protoytpe 的屬性
    var value = this[prop];
    f.call(value, prop, value);
  }
};

var obj = { name: 'John', age: 25 };
obj.each(function(prop, val) {
  console.log(prop); // name -> age
});

修改內建的 prototype 是不好的,但如果是要將 ECMA-262 5th 的 method 實作進舊瀏覽器是可以的。例如,假設舊瀏覽器沒有 Object.create這個 method,那我們就新增它。

if (!Object.create) {
  Object.create = function(proto) {
    function F() {}
    F.prototype = proto;
    return new F();
  };
}

繼承原生物件

原生物件(Native Objects)是可以被繼承的。例如:Array.prototype保留了所有的 method 給新的 Array 的實例(instance)。假設我們希望能在 myArray 當中使用 Array.prototype 的 method,那麼就將 Array.prototype 的值設定給myArray.__proto__即可。

function MyArray() {
  // 將陣列中的每個元素用逗點合併,使其成為一字串
  this.stringify = function() {
    return this.join(', ');
  };
}

MyArray.prototype = Array.prototype;

var myArr = new MyArray();
myArr.push('hello');
myArr.push('jack');
console.log(myArr.stringify()); // "hello, jack"
console.log(myArr); // ["hello", "jack"]
console.log(myArr.length); // 2

借用 Method

如果只是想要使用 Array 的部份功能,其實不需要繼承它 - 借用它的 method 即可。

var join = Array.prototype.join,
  join = [].join;

var obj = {
  0: 'first',
  1: 'second',
  length: 2,
};

console.log([].join.call(obj, ', ')); // first, second

Array 的 method 常被借用來處理類似 Array 的物件。

Summary

References


這篇文章的原始位置在這裡-JavaScript Object Oriented Programming - Extending Natives

由於部落格搬遷至此,因此在這裡放了一份,以便閱讀;部份文章片段也做了些許修改,以期提供更好的內容。

javascript prototype javascript