Reputation: 76413
Update
For clarity: @FelixKing: Yes, I expected this
to still be undefined when calling window.foo()
, and here's why: since, in JavaScript:
function foo()
{
console.log('I am a function');
}
Is (almost) the same thing as:
var foo = function()
{
console.log('I am a function');
}
and foo === window.foo
evaluates to true, I'd expect them both to behave alike. If functions are variables, and JS falls back to the global object (inside function x, a variable isn't declared but you use it, JS bubbles up through all scopes, up to the global object, until it finds the variable in question, or it creates it on a global level), it shouldn't matter if specify the window
object up front or not. Yet, when you do, the behaviour changes, which I didn't expect.
I have a gut feeling as to why this is the case (I'm defining methods, rather then variables) but then again, for global objects there is very little difference between them. var c = 'Variable'; console.log(window.c === c);
logs true etc... but I'd like to know what the difference actually is, and how it works (on all levels).
I'm prepared to go as far as to accept that foo.apply(this,[]);
or foo.apply(window,[]);
allows you to force this
to point to the global object, but not window.foo();
. If strict is there to shield the global object, I'd say this is leaving the back door wide open. I occasionally find myself calling functions, depending on the value of a variable, for example. For that I use window[myVar]();
, strict or not, that means this
will point to the global object, whereas it doesn't if I call the function directly. That is, to my mind, an inconsistency.
I've encountered some weird behaviour with the this
keyword in strict mode. Don't get me wrong I know this
is undefined in strict functions. What I find confusing, is that this
can be forced to point to the global object (or any other object, for that matter), effectively undermining the safety-net, provided by strict mode. This has other implications, too. Consider this code:
'use strict';//using strict everywhere
(function(Global)
{
var closureObject = {};
Global.foo = function()
{
closureObject.setIn = closureObject.setIn || 'Set in foo';
console.log(this);
console.log(this === Global);
bar();
bar.apply(this);
return (this !== Global ? this : undefined);
};
Global.bar = function()
{
closureObject.setIn = closureObject.setIn || 'set in bar';
console.log(this);
return (this !== Global ? this : undefined);
};
})(this);
var undef = (Math.ceil(Math.random()*10)%2 ? foo() : bar());
foo();//undefined --- false --- undefined --- undefined
window.foo();//Window --- true --- undefined --- window
foo.apply(this,[]);//same as window.foo
Same applies for custom objects:
function Foo(n)
{
this.name = n;
}
Foo.prototype.func = foo;//or window.foo
//other objects:
var d = new Date();
foo.apply(d,[]);//Date --- false --- undefined --- date
This, In my opinion, is a possible source of hacks and pitfalls. What's more: it makes it rather hard to determine where the call is coming from: if foo()
was called from the global object (window.foo();
), that context is of course not passed on to bar
, unless bar
is called using bar.apply(this,[]);
The reason why I might want to have a cut & dry, safe and reliable way to determine the caller context is simple: I'm using a closure to avoid those pesky globals, but at the same time I'm setting up a couple of functions that do serve as event handlers.
I know not using strict mode, or setting a global are easy fixes, but strict mode is here to stay, and I like what it brings to the party (well, most of it). I firmly believe that this is the way JS is going to evolve, and I'd hate to find myself weeping of my own broken code because of not wanting to bother with strict
. That might not happen too soon, but I just want to keep my knowledge up-to-date.
I've read the MDN pages on strict
, as well as John Resig's blog post, I've watched quite a few of DC's video's and read a lot of his articles and I haven't found a definitive explanation for the behaviour I described above. I haven't read through the entire ECMAScript standard (Boy, that stuff is so dry, it could drain the Sahara desert), but perhaps someone here could point me in the right direction to help me understand this better.
Upvotes: 3
Views: 949
Reputation: 28278
I'm not sure if I'm reading your question right, but it seems as if you are having trouble with the fact that func.apply(context, arguments)
can take context
as a parameter which will be then be reffered by this
inside the function.
I would argue that passing the context is necessary and JavaScript couldn't work properly without it.
Off the top of my head, since there is no super
the only way to use inheritance properly is to use something like BaseClass.prototype.baseFunction.apply(this, arguments)
.
Removing that functionality would create a language that is very different from JavaScript today and that is not what strict
mode is about.
Upvotes: 2