Javascript - 检查方法原型是否已更改?


3

检查方法的原型是否已被更改的最佳方法是什么?

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'这不起作用,这就是为什么我没有在我的答案中建议它。 22 2月. 092009-02-22 23:16:53

  0

@olliej:这是隐含的,但我已经更新了答案。 23 2月. 092009-02-23 04:24:52


2

这取决于你的意思是“改变”如果你的意思之间改变什么,当你的代码被加载和一段时间以后,你可以存储函数的引用,一拉

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

但如果你的意思是从默认的本地实现改变,没有真正的方法来告诉。

  0

所以像Prototype这样的一些库修改了核心对象的原型,比如Array.prototype.push或pop。所以我很想知道如何检查本地对象的默认原型方法是否已更改。 22 2月. 092009-02-22 10:19:49