您可能知道,在JavaScript '' + null = "null"
和'' + undefined = "undefined"
(在大多数浏览器中我可以测试:Firefox,Chrome和IE).我想知道这种奇怪的起源(Brendan Eich头脑中究竟是什么?!)以及是否有任何改变ECMA未来版本的目标.确实非常令人沮丧的是,必须要将'sthg' + (var || '')
Strings与变量连接起来并使用像Underscore或其他的第三方框架那样使用锤子进行果冻钉敲击.
编辑:
为了满足StackOverflow所要求的标准并澄清我的问题,它有三个:
在串联中使JS转换null
或其undefined
字符串值的奇怪背后的历史是什么String
?
在将来的ECMAScript版本中是否有机会改变这种行为?
什么是连接最漂亮的方式String
与潜在null
或undefined
对象不落入这个问题(得到一些"undefined"
的"null"
在字符串的中间)?根据主观标准最漂亮,我的意思是:简短,干净,有效.没必要说那'' + (obj ? obj : '')
不是很漂亮......
Oriol.. 73
您可以使用Array.prototype.join
忽略undefined
和null
:
['a', 'b', void 0, null, 6].join(''); // 'ab6'
根据规格:
如果element是
undefined
或null
,则接下来是空字符串; 否则,让接下来是ToString(元素).
鉴于,
在串联中使JS转换null
或其undefined
字符串值的奇怪背后的历史是什么String
?
事实上,在某些情况下,当前的行为是有道理的.
function showSum(a,b) { alert(a + ' + ' + b + ' = ' + (+a + +b)); }
例如,如果上面的函数是在没有参数的情况下调用的,那么undefined + undefined = NaN
可能比 + = NaN
.
一般来说,我认为如果你想在字符串中插入一些变量,显示undefined
或null
有意义.可能,Eich也这么认为.
当然,有些情况下忽略那些会更好,例如将字符串连接在一起时.但对于那些你可以使用的情况Array.prototype.join
.
在将来的ECMAScript版本中是否有机会改变这种行为?
很可能不是.
既然已经存在Array.prototype.join
,修改字符串连接的行为只会导致缺点,但没有优势.而且,它会破坏旧代码,因此它不会向后兼容.
连接字符串与潜在null
或最有效的方法是什么undefined
?
Array.prototype.join
似乎是最简单的一个.它是否最漂亮可能是基于意见的.
*"你可以使用Array.prototype.join忽略undefined和null"* - 值得注意的是,如果你使用空字符串作为你的`join` arg,这只能按照你的需要工作. (11认同)
Ingo Bürk.. 30
什么是将String与潜在的null或未定义的对象连接起来的最漂亮的方法,而不会陷入这个问题[...]?
有几种方法,你自己部分提到它们.简而言之,我能想到的唯一干净的方法是功能:
const Strings = {}; Strings.orEmpty = function( entity ) { return entity || ""; }; // usage const message = "This is a " + Strings.orEmpty( test );
当然,您可以(并且应该)更改实际实施以满足您的需求.这就是我认为这种方法优越的原因:它引入了封装.
真的,如果你没有封装,你只需要询问"最漂亮"的方式.你问自己这个问题,因为你已经知道自己会进入一个你无法改变实现的地方,所以你希望它能够立刻完美.但事情就是这样:需求,观点甚至环境都会发生变化.他们进化了.那么为什么不让自己改变实现只需要调整一行,也许一两次测试?
你可以称之为作弊,因为它并没有真正回答如何实现实际的逻辑.但这是我的观点:没关系.好吧,也许一点点.但实际上,没有必要担心,因为改变是多么简单.而且由于它没有内联,它看起来也更漂亮 - 无论你是以这种方式还是以更复杂的方式实现它.
如果在整个代码中,您不断重复||
内联,则会遇到两个问题:
你重复代码.
而且由于您复制了代码,因此将来很难进行维护和更改.
在高质量的软件开发方面,这些通常被认为是反模式的两点.
有人会说这太开销了; 他们会谈论表现.这是无意义的.首先,这几乎不会增加开销.如果这是你担心的,你选择了错误的语言.甚至jQuery也使用函数.人们需要克服微观优化.
另一件事是:你可以使用代码"compiler"= minifier.此区域中的好工具将尝试在编译步骤中检测要内联的语句.这样,您可以保持代码的清洁和可维护性,如果您仍然相信它或者确实有一个重要的环境,那么仍然可以获得最后一滴性能.
最后,对浏览器有一定的信心.他们将优化代码,这些天他们做得非常好.
您可以使用Array.prototype.join
忽略undefined
和null
:
['a', 'b', void 0, null, 6].join(''); // 'ab6'
根据规格:
如果element是
undefined
或null
,则接下来是空字符串; 否则,让接下来是ToString(元素).
鉴于,
在串联中使JS转换null
或其undefined
字符串值的奇怪背后的历史是什么String
?
事实上,在某些情况下,当前的行为是有道理的.
function showSum(a,b) { alert(a + ' + ' + b + ' = ' + (+a + +b)); }
例如,如果上面的函数是在没有参数的情况下调用的,那么undefined + undefined = NaN
可能比 + = NaN
.
一般来说,我认为如果你想在字符串中插入一些变量,显示undefined
或null
有意义.可能,Eich也这么认为.
当然,有些情况下忽略那些会更好,例如将字符串连接在一起时.但对于那些你可以使用的情况Array.prototype.join
.
在将来的ECMAScript版本中是否有机会改变这种行为?
很可能不是.
既然已经存在Array.prototype.join
,修改字符串连接的行为只会导致缺点,但没有优势.而且,它会破坏旧代码,因此它不会向后兼容.
连接字符串与潜在null
或最有效的方法是什么undefined
?
Array.prototype.join
似乎是最简单的一个.它是否最漂亮可能是基于意见的.
什么是将String与潜在的null或未定义的对象连接起来的最漂亮的方法,而不会陷入这个问题[...]?
有几种方法,你自己部分提到它们.简而言之,我能想到的唯一干净的方法是功能:
const Strings = {}; Strings.orEmpty = function( entity ) { return entity || ""; }; // usage const message = "This is a " + Strings.orEmpty( test );
当然,您可以(并且应该)更改实际实施以满足您的需求.这就是我认为这种方法优越的原因:它引入了封装.
真的,如果你没有封装,你只需要询问"最漂亮"的方式.你问自己这个问题,因为你已经知道自己会进入一个你无法改变实现的地方,所以你希望它能够立刻完美.但事情就是这样:需求,观点甚至环境都会发生变化.他们进化了.那么为什么不让自己改变实现只需要调整一行,也许一两次测试?
你可以称之为作弊,因为它并没有真正回答如何实现实际的逻辑.但这是我的观点:没关系.好吧,也许一点点.但实际上,没有必要担心,因为改变是多么简单.而且由于它没有内联,它看起来也更漂亮 - 无论你是以这种方式还是以更复杂的方式实现它.
如果在整个代码中,您不断重复||
内联,则会遇到两个问题:
你重复代码.
而且由于您复制了代码,因此将来很难进行维护和更改.
在高质量的软件开发方面,这些通常被认为是反模式的两点.
有人会说这太开销了; 他们会谈论表现.这是无意义的.首先,这几乎不会增加开销.如果这是你担心的,你选择了错误的语言.甚至jQuery也使用函数.人们需要克服微观优化.
另一件事是:你可以使用代码"compiler"= minifier.此区域中的好工具将尝试在编译步骤中检测要内联的语句.这样,您可以保持代码的清洁和可维护性,如果您仍然相信它或者确实有一个重要的环境,那么仍然可以获得最后一滴性能.
最后,对浏览器有一定的信心.他们将优化代码,这些天他们做得非常好.
只是为了充实它在规范方面表现如此的原因,这种行为自第一版开始就存在.那里和5.1中的定义在语义上是等价的,我将展示5.1定义.
第11.6.1节:加法运算符(+)
加法运算符执行字符串连接或数字加法.
生产AdditiveExpression:AdditiveExpression + MultiplicativeExpression的计算方法如下:
让lref成为评估AdditiveExpression的结果.
设lval为GetValue(lref).
设rref是评估MultiplicativeExpression的结果.
设rval为GetValue(rref).
设lprim为ToPrimitive(lval).
设rprim为ToPrimitive(rval).
如果Type(lprim)是String或Type(rprim)是String,那么
a.返回串联ToString(lprim)后跟ToString(rprim)的结果的字符串将添加操作的结果返回到ToNumber(lprim)和ToNumber(rprim).见11.6.3下面的注释.
因此,如果任一值最终为a String
,则ToString
在两个参数(第7行)上使用,并将它们连接起来(第7a行). ToPrimitive
返回所有非对象值不变,因此null
并且undefined
不受影响:
第9.1节ToPrimitive
抽象操作ToPrimitive接受输入参数和可选参数PreferredType.抽象操作ToPrimitive将其输入参数转换为非Object类型...根据表10进行转换:
对于所有非Object
类型,包括两者Null
和Undefined
,[t]he result equals the input argument (no conversion).
所以ToPrimitive
在这里什么都不做.
最后,第9.8节ToString
抽象操作ToString根据表13将其参数转换为String类型的值:
表13给出了"undefined"
对Undefined
类型和"null"
为Null
类型.
正如其他人所指出的那样,这种情况不太可能发生变化,因为它会破坏向后兼容性(并没有带来真正的好处),甚至更多,因为这种行为与规范的1997版本相同.我也不会认为这很奇怪.
如果你要改变这种行为,你会改变的定义ToString
为null
,并undefined
或将你的特殊情况下这些值的加法运算符? ToString
在整个规范中使用了很多很多地方,
"null"
似乎是一个无可争议的代表选择null
.举几个例子,在Java中"" + null
是字符串"null"
,在Python中str(None)
是字符串"None"
.
其他人都给予很好的解决方法,但我想补充一点,我怀疑你想使用entity || ""
作为自己的战略,因为它解析true
到"true"
,但false
到""
.该阵列加入这个答案有更多的预期的行为,或者你可以改变的执行这个答案检查entity == null
(包括null == null
和undefined == null
为真).