2

做什么({}).valueOf.call(myvar)

它将任何值转换为对象(对象保持不变,原语转换为包装类型的实例)。

我的问题是如何?有人可以给出更长的答案,这是如何在幕后完成的。因为valueOf()方法旨在返回原始值而不是 object 。

console.log{name:"sameer"}.valueOf() //returns an object but cant be displayed since toString() method will be called by js so [object Object] gets displayed which is a string ,how to display the exact return value from valueOf() method .Is there a way?
4

2 回答 2

3

回答你的第一个问题

JavaScript 有两种主要的变量类别类型,原语和对象。你会经常听到这样的话,在 JS 中一切都是对象。这并不完全准确。还有一些原始数据类型,它们除了保存值什么都不做。

它们没有方法,也不是包装器类型的实例。因此,在您可以对它们调用任何方法之前,需要将它们转换为包装器类型的对象。在 JavaScript 中,这种转换是自动的,称为自动装箱

请允许我演示一下:

var firstString = "Test";
typeof firstString == "string"; // true

var secondString = new String("Test");
typeof secondString == "string"; // false
secondString.prototype.toString.call// [object String];

注意会发生什么。上面其实有两种。一个是string,另一个是[object String]。这告诉你两件事:secondString instanceof Stringtrue。那是一个包装类型。在您看到的核心语言内部String继承自Object.

但第一个string只是内存引用,仅此而已。当你调用类似的方法时firstString.replace()firstString会自动转换为它的包装器类型。这是自动装箱

上述行为代表以下对:

号码自动装箱

var x = 5; var y = new Number(5);,

布尔自动装箱

var x = false; var y = new Boolean(false);

正则表达式自动装箱

var x = new RegExp("etc"); var y = /etc/;

Object.prototype.valueOf

valueOf方法是为任何对象定义的。为了调用它,它将所有原始类型转换为它们的包装器类型,并将现有对象保持不变。现在它将简单地返回 Object 引用中保存的值。所以它非常简单,它是FORCE AUTOBOXING的一种方式。您正在强迫我之前提到的转换。

回答你的第二个问题

显示未过滤的结果很简单。使用console.dir(). 看这里

({}).valueOf.call(myvar);

它完全等同于Object.prototype.valueOf.call(myVar);。现在你已经知道做什么了valueOf

假设您知道工作方式Function.prototype.call,您的语句将valueOf在您作为this参数传递的对象范围内调用该方法Function.prototype.call(第一个参数是this对象引用)。

var myvar = {
    "name": "name"
};
({}).valueOf.call(myVar);
// is equivalent to
myVar.valueOf();
于 2013-05-17T10:15:06.690 回答
3

再次问好!我们再一次面对强大的对手。在开始之前,让我们消除一个错误的想法:

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'})

于 2013-05-17T11:06:34.343 回答