Reputation: 76395
I thought I knew how JavaScript's this
keyword worked, but I've been caught by surprise again. Considering this snippet:
function foo()
{
return 'Foobar';
}
foo.valueOf = function()
{
return this();//this points to foo
};
foo.toString = foo;//alternatively
console.log(foo + '');//logs Foobar as you'd expect
In the valueOf
method, this
will point to the function object, because I'm defining a property of the function object. But when I try to do the same thing with the location
object:
location.origin = function()
{
return this.protocol + '//' + this.hostname;
};
location.origin.valueOf = location.origin;
location.origin.toString = function()
{
return this();
}
console.log(location.origin + '/uri');//undefined//undefined/uri ?
console.log(location.origin.toString());//undefined//undefined ?
console.log(location.origin.valueOf());//undefined//undefined ?
The only way to get this to work is changing this()
to location.origin()
. Could anybody explain what is so different about the location
object? I can just assign properties and methods at will, but I have noticed the Location
constructor and its prototype is not as "accessible" as the other prototypes. In Chrome you have to use Object.getPrototypeOf(location);
, whereas FF allows Location.prototype
.
Basically, I have 2 questions:
What's the difference between the location.origin
stuff above and:
var foo = {bar:function(){return 'Foobar';}};
foo.bar.valueOf = function(){return this();};
console.log(foo.bar + '');//logs Foobar!
And secondly
Are there any other objects that behave like this?
Upvotes: 1
Views: 198
Reputation: 147413
The value of this
is set entirely by how a function is called, or by Function.prototype.bind.
In the valueOf method, this will point to the function object, because I'm defining a property of the function object.
No, it isn't. In the function, this
references foo
because of how you called the function, not how you defined it.
> location.origin = function() {
> return this.protocol + '//' + this.hostname;
> };
>
> location.origin.valueOf = location.origin;
Note that location
is a host object. In Safari, origin
is readonly, the above does nothing:
alert(typeof location.origin); // string, not function
The result in Firefox is different, it's as noted in the OP.
A golden rule in javascript is: "don't treat host objects like native objects". That's because they don't necessarily behave like native objects. The behaviour you observe has nothing to do with how this
is set and everything to do with messing with host objects and their properties.
Upvotes: 2
Reputation: 2153
foo.valueOf does not point to 'foo' but to 'Foobar'. this is because of return this(); // parenthesis after this means that foo is executed and its result (=foobar) is finally returned
In the second example, location.origin.valueOf is a function
location.origin = function()
{
return this.protocol + '//' + this.hostname;
};
location.origin.valueOf = location.origin(); //<-- Note the parenthesis here
location.origin.toString = function()
{
return this();
}
console.log(location.origin() + '/uri'); //<-- again parenthesis here
console.log(location.origin.toString);// function
console.log(location.origin.valueOf); //<-- parenthesis removed here
Upvotes: 0
Reputation: 8158
I'm thinking that since window.location
is a host object, it does not obey "native" JS object semantics, and that's why you're having problems doing the same thing for location
as you did with foo
.
http://jibbering.com/faq/#nativeObject
Upvotes: 0