Javascript复杂的valueOf方法

时间:2013-05-17 10:11:22

标签: javascript

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

  

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

我的问题是如何?有人可以给出更长的答案如何在场景后完成。因为valueOf()方法意味着返回原始值而不是对象。

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?

2 个答案:

答案 0 :(得分: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);

RegExp autoboxing

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

<强> Object.prototype.valueOf

为任何对象定义valueOf方法。为了调用它,它会将所有原始类型转换为它们的包装类型,并保持现有对象不变。现在它只是返回Object引用中保存的值。所以它很简单,它是强制自动运行的一种方式。你正在强迫我之前提到的转换。

回答您的第二个问题

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

({}).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();

答案 1 :(得分:3)

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

  

valueOf()方法用于返回原始值而非对象。

不准确。如果传递了原始值,valueOf将返回一个对象。如果您执行valueOf(object),则会获得相同的对象:valueOf(object) === object。你可以轻而易举地看到:

var obj = {};
obj.valueOf() === obj; //true

现在,对于更有趣的问题:如何定义valueOf?让我们看看ES5规范以及v8和spidermonkey源。

valueOfspecv8spidermonkey):

function ObjectValueOf() {
  return ToObject(this);
}

正如我们所看到的,它只返回ToObject,如规范中所定义。兔子洞出现了。

ToObjectspecv8spidermonkey

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,而like表示实际的字符串或数字;请参阅here);如果它是一个无效的参数,则抛出一个错误;否则,返回论点。

那个的蜘蛛侠来源深入兔子洞。它定义了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还是未定义后的更多间接。结局是here

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它,你会看到不幸的[object Object],因为这是({}).toString()给你的东西(因为它会给出[object InternalClassName]形式的字符串再次,正如我们之前看到的那样。)

作为奖励,请尝试console.dir({foo : 'bar'})