JAVASCRIPT中{} + {}的结果是什么?
转自:http://www.heyria.com/index.php/2014/01/js-object-plus-object/
当对象或者数组相加的时候,会产生有点意外的结果。
这篇文章主要是解释为什么会产生这种结果。
在JavaScript中加号操作的规则比较简单:只能对Number
或者String
相加,其他的值都会被转化成这两种类型中的一种。为了理解这种转化是怎么工作的,我们首先弄清一些事情,参考ECMA-262v5版本 9.1章节
快速复习下,在JavaScript中有两种值:primitives 跟objects.原始类型的值有: undefined
null
Boolean
Number
String
.其他的所有值都是Object
包括array跟function
1. 值的转换
加号运算符能执行三种转换:把值转化成primitive,数字跟字符串
1.1 通过ToPrimitive() 将值转换成原始类型
ToPrimitive(input, PreferredType?)
可选参数PreferredType是Number
或者是String
。返回值为任何原始值.如果PreferredType是Number,执行顺序如下:(参考:http://es5.github.io/#x9.1)
- 如果
input
为primitive
,返回 - 否则,
input
为Object
。调用obj.valueOf()
。如果结果是primitive
,返回。 - 否则,调用obj.toString(). 如果结果是
primitive
,返回 - 否则,抛出
TypeError
如果 PreferredType
是String,步骤2跟3互换,如果PreferredType
没有,Date
实例被设置成String
,其他都是Number
1.2通过ToNumber()把值转换成Number
直接看ECMA 9.3的表格http://es5.github.io/#x9.3
- undefined NaN
- null +0
- boolean value true is converted to 1, false is converted to +0
- number value no conversion necessary
- string value parse the number in the string. For example, “324″ is converted to 324 要注意的是
Object
的转换,首先调用ToPrimitive(obj, Number)
方法,然后调用ToNumber
作为结果。
1.3通过ToString()
把值转化成字符串
直接看ECMA 9.8的表格http://es5.github.io/#x9.8
- undefined “undefined”
- null “null”
- boolean value either “true” or “false”
- number value the number as a string, e.g. “1.765″
- string value no conversion necessary
1.4 试试看
下边的代码可以看到转换过程
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // not a primitive
},
toString: function () {
console.log("toString");
return {}; // not a primitive
}
}
Number(obj)//把obj转换成Number
//输出如下:
//valueOf 返回的不是原始类型,继续往下走
//toString 返回的不是原始类型,继续往下走
//TypeError: Cannot convert object to primitive value 抛出错误
2. 相加
value1 + value2
对此表达式求值时,遵循一下步骤(http://es5.github.io/#x11.6.1):
1.转换操作符两边的值为原始值
`prim1 := ToPrimitive(value1)`
`prim2 := ToPrimitive(value2)`
第二个参数PreferredType
被忽略,所以对非Date类型都是Number,Date为String
2.如果prim1或者prim2有一个是String
,把这俩值都转化成String
,返回相连的结果。 3.否则,把prim1跟prim2都转化成Number
返回相加后的结果
2.1 期望的结果
当你对两个数组相加的时候,结果跟预期的一样: [] + [] // ''
转化[]到primitive的时候,首先尝试valueOf()
,返回数组本身(this):
var arr = [];
arr.valueOf() === arr
//true
因为结果不是primitive
,继续调用toString()
,返回空字符串(这个是primitive类型)。因此[] + []
的结果是两个空字符串相连接,还是空字符串
数组跟对象相加,也能得到期望的结果:
[] + {}
//'[object Object]'
解释:将一个空对象转化为String,有以下结果
String({})
//'[object Object]'
所以是空字符串”"跟”[object Object]“的结合
更多例子:
5 + new Number(7)
12
6 + { valueOf: function () { return 2 } }
8
"abc" + { toString: function () { return "def" } }
'abcdef'
2.2 意料之外的结果
当空对象跟空对象相加的时候,事情变的有点怪了。。。
{} + {}
NaN
这里肿么了?问题在于JavaScript把第一个{},解析成空的代码块并且忽略它了。NaN
实际上是后边这个+{}
产生的。你在这里看到的加号,并不是二元元素符的那个加号,而是一元运算符,作用是,把值转换为Number
,跟Number()
方法一样,例如:
+"3.65"
3.65
下边的表达式是等价的:
+{}
Number({})
Number({}.toString()) // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN
为什么第一个{}会被解析成代码块呢?因为这段代码被解析成statement
并且{}在这个statement的起始,所以被当成block statement了。 然后,怎么修复呢–强制解析器把它认为是表达式:
({} + {})
'[object Object][object Object]'
function的参数,总是被当成表达式处理:
console.log({} + {})
[object Object][object Object]
经过这么一系列的解释,产生如下结果,你应该不会吃惊了:
{} + []
0
还是因为{}被解析成空代码块了,+[]
返回0,下边这些表达式是等价的:
+[]
Number([])
Number([].toString()) // [].valueOf() isn’t primitive
Number("")
0
有趣的是,Node.js是用的REPL解释器,跟Firefox或者Chrome都不同(即使Node.js用的是跟Chroe一样的V8引擎)。Nodejs中会产生正常的结果:
{} + {}
'[object Object][object Object]'
{} + []
'[object Object]'
3. 总结下
在绝大多数情况下,理解 +在JavaScript中是怎么工作的,并不难:只能对数字或者字符串相加。对象会被转换成字符串(如果一方是String)或者数字(木有String).如果你想连接数组,你需要使用一个方法:
[1, 2].concat([3, 4])
[ 1, 2, 3, 4 ]
在JavaScript中没有内置的方法可以连接对象。你需要使用一个类似Underscore一样的库:
var o1 = {eeny:1, meeny:2};
var o2 = {miny:3, moe: 4};
_.extend(o1, o2)
{ eeny: 1,
meeny: 2,
miny: 3,
moe: 4 }
注意:跟Array.prototype.concat()
相反,extand()
会修改它的第一个参数:
o1
{ eeny: 1,
meeny: 2,
miny: 3,
moe: 4 }
o2
{ miny: 3, moe: 4 }
翻译自http://www.2ality.com/2012/01/object-plus-object.html
JAVASCRIPT中{} + {}的结果是什么?的更多相关文章
- javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈
Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...
- javascript中的this与函数讲解
前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大家可以认为全局作用域其实就是Window函数的函数作用域,我们编写的js代码, ...
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
- javascript中的操作符详解1
好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...
- 掌握javascript中的最基础数据结构-----数组
这是一篇<数据结构与算法javascript描述>的读书笔记.主要梳理了关于数组的知识.部分内容及源码来自原作. 书中第一章介绍了如何配置javascript运行环境:javascript ...
- javascript中变量提升的理解
网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...
- 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型
前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...
- 简单分析JavaScript中的面向对象
初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...
- Javascript中的valueOf与toString
基本上,javascript中所有数据类型都拥有valueOf和toString这两个方法,null除外.它们俩解决javascript值运算与显示的问题,本文将详细介绍,有需要的朋友可以参考下. t ...
- 关于javascript中的this关键字
this是非常强大的一个关键字,但是如果你不了解它,可能很难正确的使用它. 下面我解释一下如果在事件处理中使用this. 首先我们讨论一下下面这个函数中的this关联到什么. function doS ...
随机推荐
- sshkey改变后出错的解决
错误态 ssh 192.168.111.200 出现如下错误 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING ...
- UVA 1514 Piece it together (二分图匹配)
[题目链接] Link [题目大意] 给你一些由一块黑块和两块白块组成的L形拼图,问你是否能够拼成给出的图 [题解] 我们将所有的黑块拆点,拆分为纵向和横向,和周围的白块连边, 如果能够得到完美匹配, ...
- 【主席树】bzoj2588 Spoj 10628. Count on a tree
每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using ...
- delphi模态窗口跑到后面的解决办法
Delphi(68) procedure TForm1.ShowForm2;begin Self.Enabled := False; try with TForm2.Create(ni ...
- js splice()方法
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目. 注释:该方法会改变原始数组. 实例 例子 1 在本例中,我们将创建一个新数组,并向其添加一个元素: <script ty ...
- sqlmap批量扫描burpsuite拦截的日志记录
1.功能上,sqlmap具备对burpsuite拦截的request日志进行批量扫描的能力 python sqlmap.py -l hermes.log --batch -v 3 --batch:会自 ...
- javascript快速入门17--事件
事件(上) JavaScript事件列表 事件 解说 一般事件 onclick 鼠标点击时触发此事件 ondblclick 鼠标双击时触发此事件 onmousedown 按下鼠标时触发此事件 onmo ...
- Shell--命令执行的判断依据:;,&&,||
:在命令与命令中间利用分号来隔开,这样一来,分号前得命令执行完后就会立刻接着执行后面的命令了 &&若第一个命令执行完毕并且正确执行也就是$?=0,则开始执行后一个命令,否则不执行 || ...
- Socket网络通讯开发总结之:Java 与 C进行Socket通讯(转)
先交待一下业务应用背景:服务端:移动交费系统:基于C语言的Unix系统客户端:增值服务系统:基于Java的软件系统通迅协议:采用TCP/IP协议,使用TCP以异步方式接入数据传输:基于Socket流的 ...
- IIS支持伪静态(windows 2003)
IIS配置支持伪静态 ISAPI Rewrite 第一:首先我们需要下载一个ISAPI_Rewrite,有精简版和完全版,一般精简版只能对服务器全局进行配置,而完整版可以对服务器上的各个网站进行伪静态 ...