Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript complicated valueOf method [duplicate]

Tags:

javascript

What does ({}).valueOf.call(myvar) do?

it converts any value to an object (an object remains unchanged, a primitive is converted to an instance of a wrapper type).

My question is how?Can someone give The longer answer how this is done behind the scene.Since valueOf() method is meant to return primitive values not 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?
like image 282
Maizere Pathak.Nepal Avatar asked Feb 05 '26 08:02

Maizere Pathak.Nepal


1 Answers

Hello again! Once more, we face the mighty opponent. Before we begin, let's dispel one false thought:

valueOf() method is meant to return primitive values not object .

Not accurate. valueOf returns an object if a primitive value was passed to it. If you do valueOf(object), you'd get the same object: valueOf(object) === object. You can trivially see that:

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

Now, for the more interesting question: How is valueOf defined? Let's look at the ES5 specification along with the v8 and spidermonkey sources.

valueOf (spec, v8, spidermonkey):

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

As we can see, it simply returns ToObject, as defined in the spec. The rabbit hole emerges.

ToObject (spec, v8, spidermonkey)

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;
}

Jackpot. We can see the entire flow here. If it's a string, number, boolean, etc return a wrapper ($String and $Boolean and the likes represent the actual String or Number; see here); if it's an invalid argument, throw an error; otherwise, return the argument.

The spidermonkey source for that one goes deeper down the rabbit hole. It defines ToObject as such:

JS_ALWAYS_INLINE JSObject *
ToObject(JSContext *cx, HandleValue vp)
{
    if (vp.isObject())
        return &vp.toObject();
    return ToObjectSlow(cx, vp, false);
}

So if it's not an Object, call ToObjectSlow. Buckle up Alice, there'll be C++. We need to take a look at what ToObejctSlow does:

JSObject *
js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
{    
    if (val.isNullOrUndefined()) {
        ...error throwing magic here...
        return NULL;
    }

    return PrimitiveToObject(cx, val);
}

More indirection after looking whether the argument was null or undefined. The finale is 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());
}

Pretty much the same as the v8 version, only with different taxonomy.


Now, as I said before, I think your question has more to do with the medium of representing the object you see. Firebug and chrome's devtools are more than apt at displaying an object. However, if you try to alert it, you'll see the unfortunate [object Object], because that's what ({}).toString() gives you (since it gives out a string of the form [object InternalClassName], again, as we've seen before).

As a bonus, try console.dir({foo : 'bar'})

like image 167
Zirak Avatar answered Feb 07 '26 23:02

Zirak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!