开发者

Why does new Object("foo") return "[object Object]"

开发者 https://www.devze.com 2023-02-16 20:02 出处:网络
Array.prototype.sort.call(\"foo\"); // \"[object Object]\" Array.prototype.sort.call(true); // true Array.prototype.sort.call(1); // 1
Array.prototype.sort.call("foo"); // "[object Object]"
Array.prototype.sort.call(true); // true
Array.prototype.sort.call(1); // 1
Array.prototype.sort.call([1]); // [1]
Array.prototype.sort.call({}); // {}
Array.prototype.sort.call(function() {}); // function() {}

Why does the calling an array method on a string act differently? I presume it's because String also has .length and [] element accessors.

Can anyone explain what exactly happens when you call native methods on the wrong type?

[Edit]

Woops I solved it.

new Object("foo"); // "[object Object]"

It acts the same for the rest.

Let's speak to the ES5 spec:

15.2.1.1 Object ( [ value ] ) When the Object function is called with no arguments or with one argument value, the following steps are taken:

  1. If value is null, undefined or not supplied, create and return a new Object object exactly as if the standard built-in Object constructor had been called with the same arguments (15.2.2.1).

  2. Return ToObject(value)

And ToObject is :

9.9 ToObject The abstract operation ToObject converts its argument to a value of type Object according to Table 14:

Table 14 — ToObject Argument Type Result

Undefined Throw a TypeError exception.

Null Throw a TypeError exception.

Boolean Create a new Boolean object whose [[PrimitiveValue]] internal property is set to the value of the argument. See 15.6 for a description of Boolean objects.

Number Create a new Number object whose [[PrimitiveValue]] internal property is set to the value of the argument. See 15.7 for a description of Number objects.

String Create a new String object whose [[PrimitiveValue]] internal property is set to the value of the argument. See 15.5 for a description of String objects. Object The result is the input argument (no conversion).

[Bounty]

Now why is [[PrimitiveVa开发者_高级运维lue]] of String equal to "[object Object]" ?


The 'problem' here is that the constructors for that type are called (Number, String, Array, Boolean...), which act a little different than their "primitive" counterparts - they return an object that contains a primitive value.

This [[PrimitiveValue]], or [[value]] in previous specifications, is an internal property which you can access via .valueOf().

'foo' // is a string
String('foo') // is a string
new String('foo') // is a String object with [[value]] set to 'foo'

1 // is a number
Number(1) // is a number
new Number(1) // is a Number object with [[value]] set to 1

Object('foo') == (new String('foo'))
Object(1) == (new Number(1))

For some reason the webkit inspector doesn't seem aware of these object's primitive value. So, Object('foo') will print '[object Object]', but if you call Object('foo').toString() or any method that implicitly calls toString or valueOf, like alert(Object('foo')), you get the expected value "foo".

That's also the cause of this:

var x = new Boolean(false);
// any object evaluates to true...
!!x // == true
Boolean(x) // == true

Javascript has it's fair share of weirdness. Also consider that there are plenty of quirks in javascript engines, with varying levels of compliance with the specs.


In answer to your question

Now why is [[PrimitiveValue]] of String equal to "[object Object]" ?

You must turn to the ECMAscript standard doc section 15.4.4.11

"Let obj be the result of calling ToObject passing the this value as the argument."

When you Array.prototype.call("abc") 'this' is the string "abc". Passing that string into ToObject is the same as calling new Object("abc"), and this is done implicitly.

Also, it is worthwhile noting that Array.prototype.sort.call("foo") generates a TypeError in FF4.

TypeError: Array.prototype.sort.call("foo") is read-only

This is likey due the requirement (also in the spec) that the sort algorithm is not defined if "Any array index property of obj whose name is a nonnegative integer less than len is a data property whose [[Configurable]] attribute is false."

Strings can not be altered with [] accessors. Try it for yourself

var test = "abc";
test[1] = 'x';
console.log(test) //'abc'

FF4 is most likely being a bit more strict in following the spec


[[PrimitiveValue]] of String is not [object Object] as demonstrated below:

console.log(String('foo'));

The issue in your code is the keyword new

console.log(new String('foo'));

The new keyword will return an instance of Object with the prototype of whatever type-constructor you passed.


I've found a workaround for this.

function callArrayMethod(method, arg1, arg2) {
    if (arg2) {
        return Array.prototype[method].call(arg1.split(''), arg2).join('');
    }
    return Array.prototype[method].call(arg1.split(''), arg2).join('');
}

Usage:

> callArrayMethod('sort', 'cba');
"abc"
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号