2009-02-22 101 views

回答

8

如果你對一個函數做了toString(),你會得到該函數的源代碼。對於本機功能,FF,IE,Opera和Chrome會返回一個帶有[本機代碼]正文的功能。但是,Chrome在javascript中實現了大多數功能,並且會返回大多數函數的源代碼(Object.constructor是Chrome中返回[本機代碼]的少數原生函數之一)

下面你會發現一個帶有正則表達式檢查[本地代碼]。 (沒有必要調用toString(),因爲當函數未被調用時它會自動完成)。它使用FF3,IE7,Opera 9.6和Chrome 1進行了測試。但正如我所說的,由於Chrome確實會返回大多數功能的真實源代碼,因此在該瀏覽器中測試它並無用處。

function isNative(func) { 
    return /^\s*function[^{]+{\s*\[native code\]\s*}\s*$/.test(func); 
} 


alert(isNative(Array.prototype.push)); 

更新

如果本機方法被替換爲其他一些本地方法,像Array.prototype.push = Math.abs上面的代碼將當然無法察覺。如果您想要檢測這種變化,或者您自己的對象的方法發生了變化,您必須將原始方法存儲在變量中,然後運行您懷疑更改的函數,然後與存儲的方法進行比較。

但是,在閱讀了關於olliejanswer的操作的評論之後,很明顯,OP想知道如何檢測本機對象上的方法是否已被更改。如果它們被更改,它們通常不會被另一個本機函數替換,而是會被一些新代碼替換,通常用於添加瀏覽器本身不具有的方法,或者將行爲更改爲與預期標準兼容。在這種情況下,上面的代碼可以在FF,IE和Opera中使用,但不能用於Crome。

如果您想檢測任何類型的方法更改,可能會使用以下代碼。以下函數使用兩種方法創建對象:保存比較保存在創建對象時提供參數時會自動調用。 保存需要兩個或多個參數,其中第一個是對象,其餘是要保存的方法名稱。您必須提供方法名稱的原因是因爲大多數內部對象的「未枚舉」 - 在方法上設置了標誌。

function Cmpobj() { 
    if (this.constructor !== arguments.callee){ 
     throw SyntaxError("Constructor called as function"); 
    } 
    var srcobj, methods=[]; 
    this.save=function(obj) { 
     var undef; //Local undefined 
     srcobj=obj; 
     for (var i=arguments.length -1; i>0; --i) { 
      var name = arguments[i]; 
      //Push an object on the array without using push 
      methods[methods.length] = { 
       name:name, 
       func:typeof obj[name] === "function" ? obj[name]:undef 
      }; 
     } 
    } 
    this.compare=function(obj) { 
     var changed=[]; 
     obj = obj || srcobj; 
     for (var i=methods.length-1; i>=0; --i) { 
      if (methods[i].func !== obj[methods[i].name]) { 
       changed[changed.length]=methods[i].name; 
      } 
     } 
     return changed; 
    } 
    if (arguments.length) this.save.apply(this,arguments); 
} 

// Creating a compare object. The first parameter is the object, 
// followed by up to 254 method names.  
var saved = new Cmpobj(Array.prototype,"pop","push","slice"); 

//Do some change 
Array.prototype.pop = Array.prototype.push; 

// Compare if something is changed  
alert(saved.compare().join(", ")); 
+0

如果你這樣做`Array.push = Math.abs`這不起作用,這就是爲什麼我沒有在我的答案中建議它。 – olliej 2009-02-22 23:16:53

2

這取決於你的意思是「改變」如果你的意思之間改變什麼,當你的代碼被加載和一段時間以後,你可以存儲函數的引用,一拉

var oldFunc = SomeType.prototype.someFunction; 
... 
if (oldFunc === someInstance.someFunction) // unchanged, note the use of strict equality 

但如果你的意思是從默認的本地實現改變,沒有真正的方法來告訴。

+0

所以像Prototype這樣的一些庫修改了核心對象的原型,比如Array.prototype.push或pop。所以我很想知道如何檢查本地對象的默認原型方法是否已更改。 – Geuis 2009-02-22 10:19:49