注:翻譯之中有什麼不恰當的地方,歡迎大家指正,祝大家雙節快樂!
如果不是有特殊需要而去擴展原生對象和原型(prototype)的做法是不好的
復制代碼 代碼如下:
//不要這樣做
Array.prototype.map = function() {
// 一些代碼
};
除非這樣做是值得的,例如,向一些舊的浏覽器中添加一些ECMAScript5中的方法。
在這種情況下,我們一般這樣做:
復制代碼 代碼如下:
if (!Array.prototype.map) {
Array.prototype.map = function() {
//一些代碼
};
}
如果我們比較偏執,為了防止別人將map定義為其它意想不到的值,像true或其他,我們可以 將檢測代碼改為下面這樣:
復制代碼 代碼如下:
if (typeof Array.prototype.map !== "function") {
Array.prototype.map = function() {
// 一些代碼
};
}
(盡管這將破壞其它開發者的map定義,並影響他們功能的實現)
但是,在一個充滿敵意和殘酷競爭的環境下(換句話說,但你提供或者使用一個js庫時),你不應該相信任何人。如果其他人的js代碼先於你的js代碼加載,並且以某種方式定義了一個不完全兼容ES5的map()方法,導致你的代碼不能正常運行,該怎麼辦呢?
不過,你可以相信浏覽器,如果Webkit內核實現了map()方法,你可以放心,這個方法肯定會正常運行。否則的話,你就要用你的代碼進行檢測了。
幸運的是,這在JavaScript當中很容易實現,當你調用原生函數的toString方法的時候,會返回一個函數的字符串,該函數的函數體是[native code]。
例如在Chrome的控制台下:
復制代碼 代碼如下:
> Array.prototype.map.toString();
"function map() { [native code] }"
一個適當的代碼檢查向來就是一個稍微令人不快的事,因為不同浏覽器對空格和換行處理的太過輕率。測試如下:
復制代碼 代碼如下:
Array.prototype.map.toString().replace(/\s/g, '*');
// "*function*map()*{*****[native*code]*}*" // IE
// "function*map()*{*****[native*code]*}" // FF
// "function*map()*{*[native*code]*}" // Chrome
只簡單的去掉\s會得到更實用的字符串:
復制代碼 代碼如下:
Array.prototype.map.toString().replace(/\s/g, '');
// "functionmap(){[nativecode]}"
你可以將它封裝成一個可以重用的shim()函數,這樣以來你就沒有必要去重復所有的類似!
Array.prototype...這樣的操作了。這個函數會接受一個對象作為參數(例如,Array.prototype),一個將要添加的屬性(例如 'map')和一個要添加的函數。
復制代碼 代碼如下:
function shim(o, prop, fn) {
var nbody = "function" + prop + "(){[nativecode]}";
if (o.hasOwnProperty(prop) &&
o[prop].toString().replace(/\s/g, '') === nbody) {
//表名是原生的!
return true;
}
//新添加的
o[prop] = fn;
}
測試:
復制代碼 代碼如下:
//這是原生的方法
shim(
Array.prototype, 'map',
function(){/*...*/}
); // true
//這是新添加的方法
shim(
Array.prototype, 'mapzer',
function(){alert(this)}
);
[1,2,3].mapzer(); // alerts 1,2,3
(完)^_^