I think what happens is that we have the interaction of a strict mode code and a non-strict mode. And in fact, when I dug up a copy of Firefox 3.6.15 (which does not support strict mode), I donβt get the error using the link I sent to your question (it warns βtrueβ twice).
The code you provided is obviously a non-strict mode code. But what about the implementation of the hasOwnProperty browser? I suspect that this is strict, in browsers where strict mode is supported.
When you speak
func();
... what the browser does looks func using standard identifier resolution, and then calls it as if you did this:
func.call(undefined);
If func is a free function, then in a call to func , this is a global object. But , if func is a strict mode function, this inside the call is undefined .
In contrast to this:
this.func();
... he looks up func again (this time by resolving the property using the prototype chain), and then effectively does this:
this.func.call(this);
In strict or free mode, this means that this inside the function will be this . (And of course, globally, this is a global object.)
Here is an example of this interaction using code that we can see, not hasOwnProperty :
(function() { "use strict"; window.strictFunction = function() { display("strictFunction: this === window? " + (this === window)); display("strictFunction: typeof this: " + typeof this); }; })(); strictFunction(); strictFunction.call(undefined);
As you can see, this free code, with the exception of a bit, defines the strictFunction function on window . Then we call this function twice from the empty code. The result is the following:
strictFunction: this === window? false
strictFunction: typeof this: undefined
strictFunction: this === window? false
strictFunction: typeof this: undefined
In contrast, if we do this with a free function, the result is:
looseFunction: this === window? true
looseFunction: typeof this: object
looseFunction: this === window? true
looseFunction: typeof this: object
Full example: Live Copy | Live source
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Fun With Strict Interactions</title> <style> body { font-family: sans-serif; } p { margin: 0; } </style> </head> <body> <script> (function() { "use strict"; window.strictFunction = function() { display("strictFunction: this === window? " + (this === window)); display("strictFunction: typeof this: " + typeof this); }; })(); (function() { window.looseFunction = function() { display("looseFunction: this === window? " + (this === window)); display("looseFunction: typeof this: " + typeof this); }; })(); display("Direct call:"); strictFunction(); looseFunction(); display("<hr>Call with <code>.call(undefined)</code>:"); strictFunction.call(undefined); looseFunction.call(undefined); display("<hr>Call with <code>.call(window)</code>:"); strictFunction.call(window); looseFunction.call(window); function display(msg) { var p = document.createElement('p'); p.innerHTML = String(msg); document.body.appendChild(p); } </script> </body> </html>
Exit (using JavaScript engine that supports strict mode):
Direct call:
strictFunction: this === window? false
strictFunction: typeof this: undefined
looseFunction: this === window? true
looseFunction: typeof this: object
-
Call with .call (undefined):
strictFunction: this === window? false
strictFunction: typeof this: undefined
looseFunction: this === window? true
looseFunction: typeof this: object
-
Call with .call (window):
strictFunction: this === window? true
strictFunction: typeof this: object
looseFunction: this === window? true
looseFunction: typeof this: object