Javascript - проверить, был ли изменен прототип метода?


3

Каков наилучший способ проверить, был ли протоип метода изменен?

8

Если вы используете toString() для функции, вы получаете исходный код функции. Для собственных функций FF, IE, Opera и Chrome возвращают функцию с телом [native code]. Тем не менее, у 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)); 

Update

Приведенный выше код конечно не обнаружить, если нативный метод заменен каким-либо другим способом, родной, как Array.prototype.push = Math.abs. Если вы хотите обнаружить такое изменение или если методы ваших собственных объектов изменены, вы должны сохранить исходный метод в переменной, а затем запустить функцию, которая, как вы подозреваете, изменит ее, а затем сравнить с хранимыми методами.

Однако после прочтения комментария от op на olliejanswer, совершенно очевидно, что OP хотел знать, как определить, были ли изменены методы на нативных объектах. Если они меняются, они обычно не заменяются другой нативной функцией, но с некоторым новым кодом, как правило, для добавления методов, которые браузер не имеет изначально, или для изменения поведения, совместимого с ожидаемым стандартом. В этом случае код выше будет работать в FF, IE и Opera, но не в Crome.

Если вы хотите обнаружить любые изменения методов, которые могут использовать следующий код. Следующая функция создает объект с двумя способами: save и сравнить. save автоматически вызывается, если аргументы предоставляются при создании объекта. save ожидает два или более аргумента, в которых первым является объект, а остальное - имена методов, которые должны быть сохранены. Причина, по которой вы должны указывать имена методов, заключается в том, что в большинстве внутренних объектов «не перечисляет» -flag, установленный в методах.

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 фев. 092009-02-22 23:16:53

  0

@olliej: Это подразумевалось, но я все равно обновил ответ. 23 фев. 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 фев. 092009-02-22 10:19:49