为什么布尔原始值不调用原型toString()方法?

10

假设我有这段代码:

Boolean.prototype.toString = function toString() {
  return this.valueOf() ? '1' : '0';
};

var object = {
  true: 'true',
  false: 'false',
  1: '1',
  0: '0'
};

// "true" - this doesn't work
console.log('primitive', object[true]);
// "1" - but these do
console.log('primitive.toString()', object[true.toString()]);
console.log('instance', object[new Boolean(true)]);

原始类型为什么不使用类的toString定义?对象键要么是字符串,要么是符号,它们不能只是原始布尔值。这就是我感到困惑的原因。


2
因为原始类型没有 toString 方法,它只是一个值。 - Nina Scholz
@NinaScholz 但是我认为当一个值被用作对象的键时,它必须被强制转换为字符串。此外,在重新定义 Boolean.prototype.toString() 后,调用 true.toString() 返回 "1"。这样就证明了你所说的 true 没有 toString() 方法是错误的。 - Patrick Roberts
它打印primitive true, instance 1。这不是你期望的吗? - Mohit Bhardwaj
@Mike 不行,因为对象键是字符串,如果你在重新定义 Boolean.prototype.toString() 后运行 true.toString(),它会返回 "1" 而不是 "true" - Patrick Roberts
1
object[true.toString()] != object[true] 对象[true.toString()]!= 对象[true] - Vladu Ionut
显示剩余2条评论
2个回答

8
因为规范是这样规定的。 http://www.ecma-international.org/ecma-262/6.0/index.html#sec-tostring 在这个表中,原始类型的字符串值被定义。只有对于对象才使用ToPrimitive
该表告诉我们,一个对象oToStringToString( ToPrimitive(o, "string"))
规范告诉我们,如果一个对象调用了ToPrimitive,我们必须按照以下步骤执行:
1. If PreferredType was not passed, let hint be "default".
2. Else if PreferredType is hint String, let hint be "string".
3. Else PreferredType is hint Number, let hint be "number".
4. Let exoticToPrim be GetMethod(input, @@toPrimitive).
5. ReturnIfAbrupt(exoticToPrim).
6. If exoticToPrim is not undefined, then
  a. Let result be Call(exoticToPrim, input, «hint»).
  b. ReturnIfAbrupt(result).
  c. If Type(result) is not Object, return result.
  d. Throw a TypeError exception.
7. If hint is "default", let hint be "number".
8. Return OrdinaryToPrimitive(input,hint).

@@toPrimitive 被设置是一个特殊情况,因此我们现在需要查看 OrdinaryToPrimitive

1. Assert: Type(O) is Object
2. Assert: Type(hint) is String and its value is either "string" or "number".
3. If hint is "string", then
  a. Let methodNames be «"toString", "valueOf"».
4. Else,
  a. Let methodNames be «"valueOf", "toString"».
5. For each name in methodNames in List order, do
  a. Let method be Get(O, name).
  b. ReturnIfAbrupt(method).
  c. If IsCallable(method) is true, then
    i. Let result be Call(method, O).
    ii. ReturnIfAbrupt(result).
    iii. If Type(result) is not Object, return result.
6. Throw a TypeError exception.

因此,ToPrimitive(o, "string") 的返回值是 o.toString(),而 toString(o.toString())o.toString() 相同。


1
很棒的编辑!我认为那回答了所有问题,感谢你详尽的回答! - Patrick Roberts
@DavidDiez 没有人会读手册。如果你认为这不是真的,那只是在自欺欺人 ;) - Patrick Roberts
@Patrik,我知道呵呵。我只是开玩笑,所以用了“引号” ;) - David Diez

3
  • "true"是一个布尔值。
  • "Boolean"实例是一个对象,而不是布尔值。
  • 因此,该实例不必使用原型。
  • "Boolean"对象只是js中用于使用布尔类型的抽象。

Boolean.prototype.toString=function toString(){
  return this?'1':'0';
};

var object = {
  'true':'true',
  'false':'false',
  '1':'1',
  '0':'0'
};

console.log('primitive', object[true]);
console.log('instance', object[new Boolean(true)]);
console.log('bool type:', typeof(true));
console.log('Boolean type:', typeof(new Boolean(true)));


感谢解释,我认为@TillArnold更详细地解释了"primitives are not obliged to use the prototype"的原因。 - Patrick Roberts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接