Symbol.toPrimitive是自有属性,不走原型链查找,仅当对象自身定义该方法时才调用;触发时传入hint("number"/"string"/"default"),据此决定后续转换逻辑;valueOf和toString才遵循原型链查找规则。

当 JavaScript 对一个对象执行隐式类型转换(比如 +、==、String()、Number() 等)时,引擎会尝试调用该对象的 Symbol.toPrimitive 方法。如果该方法存在且是函数,就直接用它;否则,才会按规则沿着原型链查找并调用 toString() 和 valueOf() ——但注意:Symbol.toPrimitive 本身不会在原型链上“逐层查找”,它的查找机制和普通方法不同。
Symbol.toPrimitive 不走原型链查找
Symbol.toPrimitive 是一个“自有属性(own property)”,引擎只检查对象自身是否拥有该 symbol 键对应的可调用方法,不会向上遍历原型链去寻找。这是关键前提。
- 即使
obj.__proto__[Symbol.toPrimitive]存在,只要obj[Symbol.toPrimitive]是undefined或非函数,就不会调用它; - 只有显式在对象自身设置(如
obj[Symbol.toPrimitive] = function(hint) {...}),才会被触发; - 继承而来的
Symbol.toPrimitive属性会被忽略。
触发 Symbol.toPrimitive 后的 hint 参数决定后续行为
如果对象自身定义了 [Symbol.toPrimitive](hint),引擎会传入一个字符串 hint:可能是 "number"、"string" 或 "default",取决于上下文:
-
+"123"→ hint ="number"; -
String(obj)或obj + ""→ hint ="string"; -
obj == 123或obj + 1(无法明确倾向)→ hint ="default"(此时多数引擎会优先尝试"number",失败再试"string")。
你可以在该方法中根据 hint 主动调用 this.valueOf() 或 this.toString() —— 这些方法才遵循原型链查找规则。
立即学习“Java免费学习笔记(深入)”;
valueOf/toString 才真正走原型链
当没有自有的 Symbol.toPrimitive 时,JS 引擎会退回到老式转换逻辑,此时才开始沿原型链查找 valueOf() 和 toString():
- 对 hint =
"number"或"default":先查valueOf()(自身 → 原型 → 原型的原型…),若返回原始值就用它;否则查toString(); - 对 hint =
"string":先查toString(),再查valueOf(); - 两者都返回非原始值(比如仍是个对象),则抛出
TypeError。
实际例子对比
假设:
```jsconst parent = {
[Symbol.toPrimitive](hint) { return `parent-${hint}`; }
};
const child = Object.create(parent);
child.valueOf = () => 42;
```
-
child[Symbol.toPrimitive]是undefined→ 不调用 parent 的; -
child + ""触发默认流程:hint ="default"→ 查child.valueOf()(存在,返回 42)→ 转换成功; - 若删掉
child.valueOf,则继续找child.toString()→ 找不到再找parent.toString()(若存在)→ 直到Object.prototype.toString。
想让 child 复用 parent[Symbol.toPrimitive]?必须手动赋值:child[Symbol.toPrimitive] = parent[Symbol.toPrimitive];


















