JavaScript中識別native方法

@2014-04-21javascript

原文地址:http://yanni4night.com/blog/detecting-native-function-in-javascript.htmlhtml

Js中一些本地(native/built-in)對象和方法是能夠重寫的,好比在針對低版本瀏覽器的編程中,咱們使用:java

Array.prototype.forEach = function(item,index,arr){
    ...
};

來對ES5中才定義的方法增長polyfill。這樣可能會帶來的一些潛在的隱患問題暫且不表,但咱們能夠像在現代瀏覽器中同樣安全地使用forEach方法了(只要你實現地足夠穩健)。node

當在陌生的或不可控的環境中運行JavaScript代碼時,你可能不相信可能被 'polyfill' 過的方法,好比Array.prototype.everyArray.prototype.mapwindow.Promise。這個時候,你須要識別你要使用的方法是一個 JavaScript 宿主環境的本地方法仍是一個已經由別人 'polyfill' 過的方法。正則表達式

不過彷佛沒有任何標準或草案規定自定義方法和 native 方法應該在行爲上表現出任何不一樣。但能夠想象,JavaScript 引擎通常由C++語言編寫,彷佛 native 方法沒法打印出其源代碼。編程

默認情形下,將一個函數對象轉成String類型便可輸出其源代碼,一樣將方法名做爲參數傳入RegExp.prototype.test也會先轉成String,John Resig 寫的js簡單繼承實現中即便用這種方式來識別_super單詞的。所以對於自定義方法,會輸出源碼,那麼對於 native 方法,目前主流瀏覽器很一致性地輸出相似function func_name() { [native code] }的字符串,甚至nodejs也一樣,具體回車換行各類環境實現有略微差別,Javascript 實現的 DOM 選擇器sizzle總結了一個通用的正則表達式:瀏覽器

/^[^{]+\{\s*\[native \w/

。經過對方法源碼進行正則匹配來識別是本地方法與否。安全

這種經過源碼進行識別的方式有一個問題,能夠查看Ecma 262對於Funtion.prototype.toString的定義:函數

An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.ui

也就是說並未針對native方法作了特殊規定,甚至沒有規定方法默認應該輸出爲其源碼。在未來的實現中,對於native方法的默認字符串表示可能出現變化,特別是Google的V8引擎中愈來愈多地直接使用JavaScript語言自己來編寫。

另外一方面,這種方式強依賴於toString方法的默認行爲,所以重寫toString能夠達到欺騙的效果,如:

var s = Array.prototype.every = function(){
    return !!'this is a fake forEach!';
    };

s.toString = function(){
    return 'function every(){[native code]}';
};

//true,but it shouldn't
/^[^{]+\{\s*\[native \w/.test(s);

一個自定義方法經過了檢測。雖然這是一個極端的例子,但對於未有明確標準定義的,特別是未來有可能發生行爲改變的內容,最好的使用方式就是不依賴於這種非標準的,不穩定的特性。

這裏有一篇比較老的文章,其內容揭示了確實有老版本的Safari瀏覽器沒法經過上面的正則表達式檢測。

相關文章
相關標籤/搜索