Ответ 1
Прежде всего, я предполагаю, что вы говорите об автоматическом преобразовании примитивных значений в объекты. Это происходит в двух случаях в JavaScript:
- Когда вы передаете примитивное значение как значение
this
в.call
или.apply
(но не в строгом режиме). - Когда вы пытаетесь получить доступ к "свойству" примитивного значения, например.
"foo bar".split()
.
В первом случае преобразование является постоянным, т.е. this
действительно будет ссылаться на объект, во втором преобразование происходит только внутри организации на время оценки
Если вас не интересуют детали преобразования, вы можете игнорировать остальную часть ответа.
1. Примитивное значение this
Когда функция вызывается и ее значение this
не является объектом, оно преобразуется в один, по крайней мере, в нестрогий режим. Это описано в §10.4.3 Ввод кода функции [spec] в документации ECMAScript 5.1:
Следующие шаги выполняются, когда элемент управления вводит контекст выполнения для кода функции, содержащегося в объекте функции
F
, вызывающего пользователяthisArg
и вызывающего пользователяargumentsList
:
- Если код функции является строгим кодом, установите
ThisBinding
вthisArg
.- Если значение
thisArg
равноnull
илиundefined
, установитеThisBinding
для глобального объекта.- Еще если
Type(thisArg)
неObject
, установитеThisBinding
вToObject(thisArg
).
[...]
Как вы можете видеть на шаге три, значение преобразуется в объект, вызывая ToObject
[spec].
2. Доступ к свойствам
Что-то подобное происходит, когда вы пытаетесь получить доступ к свойствам (§11.2.1 Аксессоры свойств [spec]), В приведенной здесь части объясняется, как оценивается выражение foo[bar]
, то есть как оценивается доступ к свойствам с нотной скобкой. Часть, которую мы заинтересованы, также относится к точечной нотации.
Произведение
MemberExpression : MemberExpression [ Expression ]
оценивается следующим образом:
- Пусть
baseReference
является результатом оценкиMemberExpression
.- Пусть
baseValue
beGetValue(baseReference)
.
[...]8. Верните значение типа
Reference
, значениеbase
которогоbaseValue
и имя ссылки которогоpropertyNameString
, а флаг режимаstrict
strict
.
Важным шагом является последний: независимо от того, что оценивает MemberExpression
, он преобразуется в значение типа Reference
[ спецификация]. Это тип данных, используемый только в спецификации, и содержит дополнительную информацию о том, как фактическое значение должно быть извлечено из ссылки (не путать с ссылками на объекты в реальном коде JavaScript!).
Чтобы получить "реальное" значение/результат от такой ссылки, внутренняя функция GetValue(V)
(§8.7.1) [spec] (как и на этапе 2 в вышеприведенном алгоритме), где говорится:
Следующий
[[Get]]
внутренний метод используетсяGetValue
, когдаV
является ссылкой свойства с базовым значением примитива. Он вызывается с использованиемbase
в качестве значенияthis
и свойстваP
в качестве аргумента. Сделаны следующие шаги:
- Пусть
O
beToObject(base)
.
[...]
Пример:
Предположим, что мы имеем выражение
var foo = "BAR".toLowerCase();
Это выражение присваивания, которое оценивается следующим образом:
Произведение
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
оценивается следующим образом:
- Пусть
lref
будет результатом оценкиLeftHandSideExpression
.- Пусть
rref
будет результатом оценкиAssignmentExpression
.- Пусть
rval
beGetValue(rref)
.
[...]
Шаг 1: оценивается левая сторона, которая является идентификатором foo
. Как именно идентификаторы разрешены, для этого не важно.
Шаг 2: Правая часть оценивается, т.е. "BAR".toLowerCase()
. Результат внутреннего этой оценки будет опорным значением, аналогичным:
REFERENCE = {
base: "BAR",
propertyNameString: "toLowerCase",
strict: false
}
и сохранен в rref
.
Вызывается этап 3: GetValue(rref)
. Значением base
является значение "BAR"
. Поскольку это примитивное значение, будет вызван ToObject
, чтобы преобразовать его во временный объект String
. Кроме того, ссылка на самом деле является доступом к свойствам, поэтому GetValue
в конечном итоге вызовет метод toLowerCase
в объекте String
и вернет результат метода.