再次问好!我们再一次面对强大的对手。在开始之前,让我们消除一个错误的想法:
valueOf() 方法旨在返回原始值而不是 object 。
不准确。valueOf
如果将原始值传递给它,则返回一个对象。如果你这样做valueOf(object)
,你会得到相同的对象:valueOf(object) === object
. 您可以轻松地看到:
var obj = {};
obj.valueOf() === obj; //true
现在,对于更有趣的问题:如何valueOf
定义?让我们看看 ES5 规范以及 v8 和 spidermonkey 源代码。
valueOf
(规范,v8,蜘蛛猴):
function ObjectValueOf() {
return ToObject(this);
}
正如我们所看到的,它只是返回ToObject
,如规范中定义的那样。兔子洞出现了。
ToObject
(规范,v8,蜘蛛猴)
function ToObject(x) {
if (IS_STRING(x)) return new $String(x);
if (IS_SYMBOL(x)) return new $Symbol(x);
if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
throw %MakeTypeError('null_to_object', []);
}
return x;
}
大奖。我们可以在这里看到整个流程。如果它是一个字符串,数字,布尔值等返回一个包装器($String
和$Boolean
之类的代表实际的字符串或数字;见这里);如果是无效参数,则抛出错误;否则,返回参数。
那个蜘蛛猴的来源更深入兔子洞。它ToObject
是这样定义的:
JS_ALWAYS_INLINE JSObject *
ToObject(JSContext *cx, HandleValue vp)
{
if (vp.isObject())
return &vp.toObject();
return ToObjectSlow(cx, vp, false);
}
因此,如果它不是对象,请调用ToObjectSlow
. 系好爱丽丝,就会有 C++。我们需要看看有什么ToObejctSlow
作用:
JSObject *
js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
{
if (val.isNullOrUndefined()) {
...error throwing magic here...
return NULL;
}
return PrimitiveToObject(cx, val);
}
查看参数是否为 null 或未定义后的更多间接性。大结局在这里:
JSObject *
PrimitiveToObject(JSContext *cx, const Value &v)
{
if (v.isString()) {
Rooted<JSString*> str(cx, v.toString());
return StringObject::create(cx, str);
}
if (v.isNumber())
return NumberObject::create(cx, v.toNumber());
JS_ASSERT(v.isBoolean());
return BooleanObject::create(cx, v.toBoolean());
}
与 v8 版本几乎相同,只是分类不同。
现在,正如我之前所说,我认为您的问题更多地与表示您所看到的对象的媒介有关。Firebug 和 chrome 的 devtools 非常适合显示对象。然而,如果你尝试alert
它,你会看到 unfortunate [object Object]
,因为这就是({}).toString()
给你的(因为它再次给出了一个字符串形式[object InternalClassName]
,就像我们之前看到的那样)。
作为奖励,尝试console.dir({foo : 'bar'})