Object - 對Object類的擴(kuò)展

Prototype對Object類進(jìn)行的擴(kuò)展主要通過一個靜態(tài)函數(shù)Object.extend(destination, source)實(shí)現(xiàn)了JavaScript中的繼承。 從語義的角度, Object.extend(destination, source)方法有些不和邏輯, 因?yàn)樗聦?shí)上僅僅實(shí)現(xiàn)了從源對象到目標(biāo)對象的全息拷貝。不過你也可以這樣認(rèn)為:由于目標(biāo)對象擁有了所有源對象所擁有的特性, 所以看上去就像目標(biāo)對象繼承了源對象(并加以擴(kuò)展)一樣。另外, Prototype對Object擴(kuò)展了幾個比較有用的靜態(tài)方法, 所有其他的類可以通過調(diào)用這些靜態(tài)方法獲取支持。

Source View - 源碼解析

Object.extend = function(destination, source) {  // 一個靜態(tài)方法表示繼承, 目標(biāo)對象將擁有源對象的所有屬性和方法
for (var property in source) {
destination[property] = source[property];   // 利用動態(tài)語言的特性, 通過賦值動態(tài)添加屬性與方法
}
return destination;   // 返回?cái)U(kuò)展后的對象
}
Object.extend(Object, {
inspect: function(object) {   // 一個靜態(tài)方法, 傳入一個對象, 返回對象的字符串表示
try {
if (object == undefined) return 'undefined';  // 處理undefined情況
if (object == null) return 'null';     // 處理null情況
// 如果對象定義了inspect方法, 則調(diào)用該方法返回, 否則返回對象的toString()值
return object.inspect ? object.inspect() : object.toString();
} catch (e) {
if (e instanceof RangeError) return '...';  // 處理異常情況
throw e;
}
},
keys: function(object) {     // 一個靜態(tài)方法, 傳入一個對象, 返回該對象中所有的屬性, 構(gòu)成數(shù)組返回
var keys = [];
for (var property in object)
keys.push(property);     // 將每個屬性壓入到一個數(shù)組中
return keys;
},
values: function(object) {   // 一個靜態(tài)方法, 傳入一個對象, 返回該對象中所有屬性所對應(yīng)的值, 構(gòu)成數(shù)組返回
var values = [];
for (var property in object)
values.push(object[property]);   // 將每個屬性的值壓入到一個數(shù)組中
return values;
},
clone: function(object) {    // 一個靜態(tài)方法, 傳入一個對象, 克隆一個新對象并返回
return Object.extend({}, object);
}
});

Field & Function Reference - 屬性方法一覽

Object ( 靜態(tài) ) - 擴(kuò)展
Method / Property Kind Arguments Description
extend(destination, source) 靜態(tài)方法 任意對象  
inspect(object) 靜態(tài)方法 任意對象  
keys(object) 靜態(tài)方法 任意對象  
values(object) 靜態(tài)方法 任意對象  
clone(object) 靜態(tài)方法 任意對象  

Analysis & Usage - 分析與使用

Object.extend(destination, source)是Prototype實(shí)現(xiàn)的一個靜態(tài)方法, 在JavaScript中模擬了繼承。 事實(shí)上, 這個方法的語義更加傾向于:動態(tài)地為某個對象添加屬性或方法。這個函數(shù)貫穿了整個Prototype的框架, 雖然核心思想是一致的, 但是在使用中還是能夠看到一些不同之處, 這些不同之處很微小但是卻值得一提。

1. 擴(kuò)展現(xiàn)有對象的功能 - 為他們添加新的函數(shù)

Object.extend(Number.prototype, {
toColorPart: function() {
var digits = this.toString(16);
if (this < 16) return '0' + digits;
return digits;
},
......
});

這是非常典型的對Number類的擴(kuò)展, 為Number.prototype加入了一些額外的函數(shù), 從而每個Number對象的實(shí)例都擁有這些方法。

2. 定義并實(shí)現(xiàn)抽象類

var Enumerable = {
each: function(iterator) {
var index = 0;
try {
this._each(function(value) {
try {
iterator(value, index++);
} catch (e) {
if (e != $continue) throw e;
}
});
} catch (e) {
if (e != $break) throw e;
}
},
......
}
Object.extend(Array.prototype, Enumerable);
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0; i < this.length; i++)
iterator(this[i]);
},
......
}

這是Prototype中的代碼段, 它向我們展示了定義并實(shí)現(xiàn)抽象類的完整過程。這里首先定義了一個Enumerable類, 這是一個抽象類。這個抽象類的內(nèi)部, 有一個_each方法被調(diào)用來完成一些邏輯。但是在整個Enumerable的范圍內(nèi), 你無法找到_each方法的具體實(shí)現(xiàn)。也就是說, Enumerable是一個抽象類, 具有一個_each的抽象函數(shù)。 所以, 如果你還沒有實(shí)現(xiàn)_each這個抽象函數(shù), 你是無法直接使用Enumerable類的。之后的代碼就比較明朗了, 使用Object.extend方法, 將所有Enumerable的函數(shù)復(fù)制給Array.prototype, 然后在Array.prototype中實(shí)現(xiàn)_each方法, 這樣就使得Array對象具備了Enumerable這個抽象類的所有特性。



------君臨天下,舍我其誰------