JavaScript中的基元和对象包装器等价

时间:2013-01-02 21:00:13

标签: javascript object primitive equivalence type-equivalence

编辑:根据每个人的反馈,此问题的原始版本更多地与设计相关,而不是与标准相关。使SO更加友好。


原件:

根据ECMA标准,JS原语是否应被视为与该原语的对象包装版本“等效”?


修订问题

是否有关于如何在当前JavaScript中比较原始包装对象的普遍协议?

var n = new Number(1),
    p = 1;
n === p;     // false
typeof n;    // "object"
typeof p;    // "number"
+n === p;    // true, but you need coercion.

修改

正如@Pointy评论的那样,ECMA规范(262,S15.1.2.4)描述了一种行为如下的Number.isNaN()方法:

Number.isNaN(NaN);                // true
Number.isNaN(new Number(NaN));    // false
Number.isNaN(+(new Number(NaN))); // true, but you need coercion.

显然,这种行为的理由是isNaN将返回true如果该论点强制转换为NaNnew Number(NaN)不会根据原生isNaN的运作方式直接强制执行。

直接使用本机Object Wrappers而不是原语的类型转换等性能损失和技巧似乎超过了现在的语义优势。

See this JSPerf.

1 个答案:

答案 0 :(得分:2)

对你的问题的简短回答是否定的,对于如何比较JS中的值没有达成共识,因为这个问题过于情绪化;这在很大程度上取决于你的具体情况。

但是,提供一些建议/提供更长的答案......原语的对象版本是邪恶的(在“它们会导致你很多错误的感觉”,而不是在道德意义上),应该避免如果可能。因此,除非你有令人信服的理由同时处理它们,否则我建议你不要考虑对象包装的原语,只需坚持代码中未包装的原语。

另外,如果你不考虑包裹的原语,它应该首先消除你甚至需要一个等于方法的需要。

*编辑 *

刚看到您的最新评论,如果您需要比较数组,那么内置的=====将不会删除它。即便如此,我建议使用arrayEquals方法而不仅仅是equals方法,因为您可以通过尽可能集中您的功能并使用内置的JS比较器来避免大量的戏剧性尽可能多。

如果你将它包装在某种通用功能中,为方便起见:

function equals(left, right) {
    if (left.slice && right.slice) { // lame array check
        return arrayEquals(left, right);
    }
    return left == right;
}

我仍然建议不要处理原始包装的对象,除非通过“句柄”使你的函数抛出错误,如果它传递了一个原始包装的对象。同样,因为这些对象只会给你带来麻烦,你应该尽可能地避免它们,并且不要让自己留下引入错误代码的空白。