Почему новый Object ("foo") возвращает "[object Object]" - PullRequest
1 голос
/ 11 марта 2011
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() {}

Почему вызов метода массива в строке действует иначе?Я полагаю, это потому, что String также имеет элементы доступа .length и [].

Может кто-нибудь объяснить, что именно происходит, когда вы вызываете нативные методы неправильного типа?

[Редактировать]

Woops Я решил это.

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

Действует то же самое для остальных.

Давайте поговорим о спецификации ES5:

15.2.1.1 Object ([значение]) Когда функция Object вызывается без аргументов или со значением одного аргумента, предпринимаются следующие шаги:

  1. Если значениеимеет значение null, не определено или не указано, создает и возвращает новый объект Object точно так же, как если бы стандартный встроенный конструктор Object был вызван с теми же аргументами (15.2.2.1).

  2. Возврат ToObject (значение)

И ToObject:

9.9 ToObject Абстрактная операция ToObject преобразует свой аргумент в значение типа Objectсогласно Таблице 14:

Таблица 14 - Тип аргумента ToObject Результат

Undefined Выдает исключение TypeError.

Null Бросить исключение TypeError.

Boolean Создать новый логический объект, внутреннее свойство которого [[PrimitiveValue]] установлено равным значению аргумента.См. 15.6 для описания булевых объектов.

Number Создайте новый объект Number, для которого внутреннее свойство [[PrimitiveValue]] установлено равным значению аргумента.См. 15.7 для описания объектов Number.

String Создайте новый объект String, для которого внутреннее свойство [[PrimitiveValue]] установлено равным значению аргумента.См. 15.5 для описания объектов String.Object Результатом является входной аргумент (без преобразования).

[Bounty]

Теперь почему [[PrimitiveValue]] из String равно "[object Object]"?

Ответы [ 4 ]

1 голос
/ 30 марта 2011

[[PrimitiveValue]] из String равно , а не [object Object], как показано ниже:

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

Проблема в вашем коде - ключевое слово new

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

Ключевое слово new вернет экземпляр Object с прототипом любого переданного вами конструктора типов.

1 голос
/ 25 марта 2011

В ответ на ваш вопрос

Теперь, почему [[PrimitiveValue]] для String равен "[object Object]"?

Вы должны обратиться к ECMAscript стандартный документ раздел 15.4.4.11

" Пусть obj будет результатом вызова ToObject с передачей значения this в качестве аргумента. "

Когда вы Array.prototype.call("abc") 'this', это строка "abc". Передача этой строки в ToObject аналогична вызову new Object("abc"), и это делается неявно.

Также стоит отметить, что Array.prototype.sort.call("foo") генерирует ошибку TypeError в FF4.

Ошибка типа: Array.prototype.sort.call ("foo") доступна только для чтения

Это похоже на требование (также в спецификации), что алгоритм сортировки не определен, если " Любое свойство индекса массива объекта obj, имя которого является неотрицательным целым числом меньше, чем len, является свойством данных чей атрибут [[Configurable]] равен false."

Строки не могут быть изменены с помощью [] аксессоров. Попробуйте сами

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

FF4, скорее всего, немного более строг в следовании спецификации

1 голос
/ 26 марта 2011

Проблема здесь в том, что конструкторы для этого типа называются (Number, String, Array, Boolean...), которые действуют немного иначе, чем их «примитивные» аналоги - они возвращают объект, который содержит примитивное значение.

Это [[PrimitiveValue]] или [[value]] в предыдущих спецификациях является внутренним свойством, к которому вы можете получить доступ через .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))

По какой-то причине инспектор webkit не выглядитосознавая примитивную ценность этих объектов.Таким образом, Object('foo') напечатает '[object Object]', но если вы вызовете Object('foo').toString() или любой метод, который неявно вызывает toString или valueOf, например alert(Object('foo')), вы получите ожидаемое значение "foo".

Это также причина этого:

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

Javascript имеет свою долю странности.Также учтите, что в движках javascript есть множество изюминок с различными уровнями соответствия спецификациям.

0 голосов
/ 11 марта 2011

Я нашел обходной путь для этого.

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

Использование:

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