How to verify that the properties of the window object are native?

Asked

Viewed 1,082 times

8

I’m using Shim that modifies several of the properties in the window object of browsers.

At this point I need to validate whether one of the specified properties is native or a Shim. Because Shim can modify the native property.

For example:

(function () {
  var native = window.alert;
  window.alert = function (): {
    /* faz alguma coisa */
    console.log(arguments);
    return native.apply(this, arguments);
  };
})();

In the example we can see that it does not change the functionality of alert applying the original at the end, but this alert is no longer the original in another code snippet I would like to know if this method is the original or a modified.

The alert was used only as example purposes of the problem.

Without modifying the "Shim" that no longer exposes the alert native, how to access the alert native to compare with the modified and know that the function in the window is not the native?

  • If not implemented, it returns false when using in an if().

  • @2madera that’s not what I asked, alert will return true if it is modified or native. I want to know if it is native or not. If it exists in the object window is another very simple thing to solve.

4 answers

7

I don’t know how much this would be compatible with all browsers, but if you convert the function to string, you’ll see the source code in the case of non-native functions, and a string containing [native code] the native ones. For example, in the case of your variable native (tested on the Chrome console):

native.toString(); // function alert() { [native code] } 

Based on this, one can create a function to verify this:

function nativa(fn) {
    return typeof fn == 'function' && fn.toString().indexOf('[native code]') > -1;
}
  • +1 Dude I can use this solution in my case very exclusively because of a failure of implementation of Shim that I’m trying to detect, but in IE will not work and if you solve the dependency correctly in a future version will end up breaking. The ideal was to be able to access the same original method.

  • 1

    I focused on the question of the title and missed the most important, the last sentence. The solution is what Gustavo Rodrigues posted.

6


A native function will return function () { [native code] } when converted to string.

var nativa = typeof funcao === 'function ' && funcao.toString().indexOf('[native code]') !== -1

On the other hand this does not work if the function Function.prototype.toString has been modified.

You can access native javascript functions using another window (an iframe or popup) and compare them:

function retrieveNative(native) {
  var iframe = document.createElement('iframe');
  document.head.appendChild(iframe);
  var retrieved = iframe.contentWindow[native];
  document.head.removeChild(iframe);
  return retrieved;
}
var alertNativo = retrieveNative('alert');

Remark: The right thing to do is to body the iframe, but if it has not been loaded yet, it will generate an exception, putting in the head will not carry the iframe but it will provide access to window which is the objective in this case.

Credits to @bfavaretto for the change in comments.

  • +1, this iframe hack is the only solution in certain cases.

  • +1 i used this hack iframe also, but now... I’m having trouble because I need to do this validation before he loads from DOM, so you can’t do appendChild in the body.

  • 1

    @Gabriel You can try an appendchild at head. It would be invalid html, but if it works...

  • An important observation about this method: everything that comes from the other frame is completely independent of what is in the parent frame. So if you take a builder, as in var obj = retrieveNative('Object'), and compare with the native, you will see that they are different (obj.prototype != Object.prototype)

  • @bfavaretto very good face worked and solved dude!!! I want to give Accept to both, because it was effort in common, but how to do it? Hehe Has to give Accept in this issue and still gratify you man?

  • 1

    Don’t worry, @Gabrielgartz. It accepts Gustavo’s solution, it is more complete (Gustavo: if you want to add my suggestion in the body of the answer, feel free).

  • It expresses my gratitude for your idea of using the head because it worked and solved the case for all browsers now, since I can compare by string if it is native and in iframe if it exists in window pattern.

  • This function I took from my favorites, which had taken a question from SOEN. They can edit the question, even more if they find the source of the function.

  • 1

    I found the source, I didn’t think it would be so easy: http://stackoverflow.com/a/3108140/1850091

  • You already have many comments, let’s leave it as it is: if we are going to worry a lot about it we will have to do the same as Google Analytics, because the document.head may not work if it is <=IE8.

Show 5 more comments

4

To restore a native function, we can use the delete. Example:

delete window.alert;

So, by applying this to a function that deletes and restores the initial value, we can verify that the function is native without the hack iframe:

function isNative(object, name) {
    var aux = object[name]; //salva o valor
    delete object[name]; //apaga a função
    var result = object[name] == aux; //se continuar a mesma é porque é nativa
    object[name] = aux; //restaura a anterior, caso não seja a nativa
    return result;
}

Testing:

console.log(window.alert, isNative(window, 'alert'));
window.alert = function() { }
console.log(window.alert, isNative(window, 'alert'));
delete window.alert;
console.log(window.alert, isNative(window, 'alert'));

Exit:

True

False

True

Jsfiddle

Note: is technical does not work in some browsers if the function has been set with the function Object.defineProperty and the parameter writable : false. See the fiddle test. In Chrome there were no problems, but in Firefox the function returned true when it should be false.

Note 2: also does not work if the function definition is done directly in the global scope, for example:

function alert() { ... }
  • Dude, way this idea, I’ll test it, but I think so far it’s actually the best of all.

  • 3

    Really good. It should only fail if Shim has been FDP enough to overwrite the function with [[Configurable]] false. That happens if he declares function alert(){} instead of window.alert = ..., or using Object.defineProperty to explicitly set the attribute.

  • @Gabrielgartz Certo, take the test. I don’t know if it can have any side effects or some case where it doesn’t work. If someone knows me let me know!

  • @bfavaretto No Chrome worked, because he must have ignored the writable. In firefox no. :(

  • You need to define the configurable to prevent the delete.

  • @bfavaretto I just saw!

  • Kind of my case Polymer Beads don’t use defineProperty so it worked, in Webkit, Mozilla and Opera, it’s definitely uses a lighter solution than the previous ones, but the @Gustavorodrigues solution is not to be fooled I believe...

  • @Gabrielgartz It’s not just defineProperty, function alert(){} already prevents a delete (property is created as not configurable).

  • Is that the @utluiz function does not predict but I test 2 things, if after delete they are equal and if after delete it still exists in window. In the case of alert are different but exists native in the case of HTMLTemplateElement there is no native after delete in Opera.

Show 4 more comments

1

One possibility is to "backup" the window before running your Scan. After that you can compare the values of the functions with the old value of the backup to see if there was a change.

//Coloque esse código em uma tag <script> anterior à tag <script> com o shim.
var window_backup = {}
for(var k in window){
    window_backup[k] = window[k];
}

function is_native(key){
   return window[key] === window_backup[key];
}

The main advantage of this approach is that you do not depend on implementation details as the result of the toString function and do not need to mess with the window object after you run the Shim.

  • +1 This is also legal, but requires that it be instantiated before the Shim, which greatly limits the possibility of use. Thank you for the contribution.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.