Строковый объект против буквального - изменение прототипа?
Мне интересно, почему кажется, что добавление метода к прототипу строкового литерала, похоже, работает, но добавление свойства не происходит? Я играл с идеями относительно этого вопроса и имел следующий код:
String.prototype._str_index1 = 0;
String.prototype._str_reset = function() {
this._str_index1 = 0;
};
String.prototype._str_substr = function(len) {
var ret = this.substr(this._str_index1, len);
this._str_index1 = this._str_index1 + len;
return ret;
};
var testString = new String('Loremipsumdolorsitamet,consectetur');
log(testString._str_substr(5));
log(testString._str_substr(4));
Это прекрасно работает. Если, однако, я изменяю третью последнюю строку на:
var testString = 'Loremipsumdolorsitamet,consectetur';
... кажется, что хотя метод _str_substr
существует и может быть вызван в строковом литерале, значение свойства _str_index1
всегда равно 0.
Что?
Ответы
Ответ 1
Строковый примитив преобразуется в объект переходного String
каждый раз при попытке вызвать метод объекта String
(механизм JavaScript внутренне преобразует примитив строки в объект String
, когда это необходимо). После возвращения этой функции объект String
(ненавязчиво) преобразуется обратно в примитив строки (под капотом), и этот новый примитив возвращается (и большую часть времени назначается переменной); при каждом вызове метода String
.
Итак, после каждого вызова testString._str_substr
, _str_index1
выбрасывается вместе с объектом, а новый объект (с reset _str_index1
) создается, когда _str_substr
вызывается снова.
См. также MDC:
Поскольку JavaScript автоматически преобразует примитивы строк и объекты String, вы можете вызвать любой из методов объекта String в примитиве строк. JavaScript автоматически преобразует примитив строки во временный объект String, вызывает метод, а затем отбрасывает временный объект String.
Ответ 2
Это происходит потому, что объект создается и сразу же отбрасывается, когда выполняется назначение, потому что это строковый литерал.
Итак, с первой версией объект создается и сохраняется, поэтому testString - это объект, а не строковый литерал. Во втором случае объект создается и удаляется, поэтому все свойства теряются...
Теперь попробуйте заменить эту строку следующим:
var testString = 'Loremipsumdolorsitamet,consectetur'._str_substr();
Интересно, верно? Он по-прежнему возвращает примитив строки, но это может быть исправлено...
String.prototype._str_substr = function(len) {
var ret = this.substr(this._str_index1, len);
this._str_index1 = this._str_index1 + len;
return new String(ret);
};
Конечно, это просто предложения, призванные помочь объяснить, почему литералы действуют иначе, чем объекты, а не реальные рекомендации...