JavaScript这个关键字令人惊讶

时间:2012-09-21 13:55:11

标签: javascript this prototype

我以为我知道JavaScript的this关键字是如何工作的,但我又一次感到惊讶。考虑这个片段:

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

valueOf方法中,this将指向函数对象,因为我正在定义函数对象的属性。但是当我尝试用location对象做同样的事情时:

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 ?

实现这一目标的唯一方法是将this()更改为location.origin()。任何人都可以解释location对象的不同之处吗?我可以随意分配属性和方法,但我注意到Location构造函数及其原型不像其他原型一样“accessible”。在Chrome中,您必须使用Object.getPrototypeOf(location);,而FF则允许Location.prototype

基本上,我有两个问题:
上面的location.origin内容之间有什么区别:

var foo = {bar:function(){return 'Foobar';}};
foo.bar.valueOf = function(){return this();};
console.log(foo.bar + '');//logs Foobar!

其次是 还有其他任何行为都是这样的吗?

3 个答案:

答案 0 :(得分:2)

this的值完全取决于函数的调用方式或Function.prototype.bind

  

在valueOf方法中,这将指向函数对象,因为我正在定义函数对象的属性。

不,不是。在函数中,this引用foo,因为你调用函数的方式,而不是你如何定义它。

> location.origin = function() {
>     return this.protocol + '//' + this.hostname;
> };
>
> location.origin.valueOf = location.origin;

请注意location是一个宿主对象。在Safari中,origin只读,上面什么都不做:

alert(typeof location.origin); // string, not function

Firefox中的结果不同,正如OP中所述。

javascript中的一条黄金法则是:“不要将主机对象视为本机对象”。那是因为它们不一定像本机对象一样。您观察到的行为与设置this的方式无关,而与处理宿主对象及其属性有关。

答案 1 :(得分:0)

foo.valueOf不指向'foo'而是指向'Foobar'。这是因为 return this(); //后面的括号表示执行foo并最终返回其结果(= foobar)

在第二个例子中, location.origin.valueOf是一个函数

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

答案 2 :(得分:0)

我在想,因为window.location是一个宿主对象,它不遵守“原生”JS对象语义,这就是为什么你在为location做同样事情时遇到问题的原因做了foo

http://jibbering.com/faq/#nativeObject