【发布时间】:2011-01-23 09:08:19
【问题描述】:
我在地址栏中尝试了这段代码:
javascript: alert({} + [])
结果是:[object Object]。
javascript: alert(typeof ({} + []))
结果是:字符串。
谁能给我解释一下这是怎么回事?
【问题讨论】:
标签: javascript types type-conversion
我在地址栏中尝试了这段代码:
javascript: alert({} + [])
结果是:[object Object]。
javascript: alert(typeof ({} + []))
结果是:字符串。
谁能给我解释一下这是怎么回事?
【问题讨论】:
标签: javascript types type-conversion
连接运算符 (+) 将两个字符串值连接在一起。如果你给它一些不是字符串值的东西,那么它首先调用它们的.toString()方法。
回应下面的评论,“是的!”
Object.prototype.toString = function () { return "a"; };
Array.prototype.toString = function () { return "b"; };
var foo = {} + [];
alert(foo); // alerts 'ab'
如果没有对原型进行上述修改,如果您有alert({} + []),那么您将采用{}.toString()(即"[Object object]")和[].toString()(即"",因为数组为空),然后连接他们(仍然是"[Object object]")。这是一个字符串,typeof 会告诉你它是一个字符串。
【讨论】:
Array.prototype.toString = function () { return this.join(','); };
看起来因为+ 运算符未定义为接受参数作为一个[] 和一个{},它基本上将两者都转换为字符串(比尝试将它们转换为数字更有意义)然后应用+ 作为连接运算符。
编辑: 针对更改后的问题,我认为它们仍然首先被转换为字符串。这是我在 spidermonkey 中尝试过的一个会话:
js> x=[]+{}
[object Object]
js> z=x[0]
[
js> x.length
15
js> x=[]+{}
[object Object]
js> x.length
15
js> x[0]
[
js> x[1]
o
js> for (var i=0;i<x.length;i++) {print(x[i]);}
[
o
b
j
e
c
t
O
b
j
e
c
t
]
js> typeof(x)
string
js> print(x)
[object Object]
发生的事情是{}+[] 的结果是一个字符串,但不是空字符串。而是字符串“[object Object]”。
【讨论】:
这有点复杂。
你会在这里找到一个很好的解释它是如何工作的:http://www.adequatelygood.com/2010/3/Object-to-Primitive-Conversions-in-JavaScript
但似乎本樱桃描述的方式确实发生了变化(也是我重新认识的)。如果您将运行他的示例:
function population(country, pop) {
return {
country: country,
pop: pop,
toString: function () {
return "[Population " +
"\"" + country + "\" " +
pop +
"]";
},
valueOf: function () {
return pop;
}
};
}
var america_pop = population("USA", 350e6);
var mexico_pop = population("Mexico", 200e6);
var canada_pop = population("Canada", 200e6);
alert(america_pop); // [Population "USA" 350000000
var north_america_pop = america_pop + mexico_pop + canada_pop;
alert(north_america_pop); // 750000000
这不再是真的,警报将是:
350000000
750000000
alert(obj) 不再调用 valueOf() 而不是 toString(),如果使用 Array.join 则执行
alert([america_pop]); // [Population "USA" 350000000
已经有一个帖子关于:valueOf() vs. toString() in Javascript
他们清楚地表明,当 [hint] 是一个数字时总是会调用 valueOf,而且情况总是如此,除非你加入一个数组。这很令人困惑,因为如果你调用 'string' + 'string' 这绝对是一个字符串上下文,但 JS 会首先查看数字上下文,如果它是原始值,则始终调用 valueOf() 方法而不是 toString() /p>
【讨论】:
恐怕比这里解释的要复杂一些。
问题的标题是:
然后问题询问{}+[] 表达式,这里的每个人都假设它的计算结果为'[object Object]' - 但它总是这样吗?
立即按 Shift+Control+J 并在 > 提示符处输入 {}+[]:
也许是浏览器的错误?让我们在 Node 中尝试同样的方法:
这里发生了一些有趣的事情。
加号 (+) - 实际上被称为 “加法运算符” 而不是 “连接运算符” 就像有人在这里写的那样 - 请参阅 ECMA-262, 6th Edition, Section 12.7.3 - The Addition operator ( + ) - 执行字符串连接或数字加法,这对于理解此类示例非常重要。
曾经有人问过我这样的问题:
如果alert({}+[]) 显示'[object Object]' 和x = {}+[] 将'[object Object]' 放入x,那么为什么在控制台或节点REPL 中写入{}+[] 会得到0?
答案是,在对象和数组上使用加号运算符时,会将它们转换为字符串 - 分别为字符串 '[object Object]' 和空字符串 - 这里我们实际上 不是 将对象添加到数组! {} 被解释为一个空块并且评估为空,因此 + 现在被评估为 unary operator 将 [] 数组强制为一个数字,对于一个空数组恰好为零 - 但它不是元素的数量,而是空数组的 0,如果可以,则第一个元素转换为数字,如果不能,则转换为 NaN 用于单元素数组,以及 NaN 用于具有多个元素的任何数组。
一些更有趣的结果,尝试{} 和[] 与+、-、* 和/ 运算符的所有组合:
$ node
> []+[]
''
> {}+{}
'[object Object][object Object]'
> []+{}
'[object Object]'
> {}+[]
0
> []-[]
0
> {}-{}
NaN
> []-{}
NaN
> {}-[]
-0
> []*[]
0
> {}*{}
NaN
> []*{}
NaN
> {}*[]
... ^C
> []/[]
NaN
> {}/{}
NaN
> []/{}
NaN
> {}/[]
SyntaxError: Invalid regular expression: missing /
at Object.exports.createScript (vm.js:24:10)
at REPLServer.defaultEval (repl.js:137:25)
at bound (domain.js:250:14)
at REPLServer.runBound [as eval] (domain.js:263:12)
at REPLServer.<anonymous> (repl.js:392:12)
at emitOne (events.js:82:20)
at REPLServer.emit (events.js:169:7)
at REPLServer.Interface._onLine (readline.js:210:10)
at REPLServer.Interface._line (readline.js:546:8)
at REPLServer.Interface._ttyWrite (readline.js:823:14)
这是从内到外学习所有语言怪癖的最佳方法之一。
【讨论】:
基本上会调用toString 方法。您实际上可以通过编写返回数字的toString 方法来覆盖默认行为。
var obj1 = {
toString: function () {
return 1;
}
},
obj2 = {
toString: function () {
return 2;
}
};
alert(typeof (obj1 + obj2));
【讨论】: