Подтвердить что ты не робот

Почему я не могу добавить свойства к строковому объекту в javascript?

Я унаследовал код javascript, написанный другим разработчиком. Ему не понравился элемент сетки, который мы использовали во всем проекте, поэтому он решил написать свое. Сетка, которую он написал, не может сортировать даты, потому что она может привязываться только к строкам/цифрам. Он конвертирует все даты в строки перед их использованием. Я посмотрел на строковое форматирование функции даты, которую он написал, и решил, что могу просто добавить свойство даты в строку с исходным значением, а затем при сортировке посмотреть, имеет ли строка свойство даты и сортировка на основе этого. Однако, похоже, вы не можете добавлять свойства к строкам в javascript. Я не знал, что есть определенные типы, к которым нельзя добавить свойства. Например:

<html>
<script>
var test = "test";
test.test = "test inner";
console.log(test);
console.log(test.test);
</script>

test.test будет undefined. Weird. Мой вопрос в том, почему этот код не работает? А также, если вы можете придумать какие-либо обходные пути для сортировки дат на этой сетке (помимо фактической привязки к объектам даты вместо строк, что было бы болью для исправления), это было бы действительно полезно.

4b9b3361

Ответ 1

В JavaScript существует 6 языковых типов:

  • 5 примитивных типов: String, Number, Boolean, Null, Undefined
  • 1 непримитивный тип: Object

Значения примитивных типов называются примитивными значениями, и они не могут иметь свойств.
Значения не примитивного типа Object называются объектами, и они могут иметь свойства.

При попытке присвоить свойство с именем 'bar' переменной foo, например:

foo.bar = 'abc';

то результат будет зависеть от типа значения foo:

(a), если значение foo имеет тип Undefined или Null, тогда будет выброшена ошибка,

(b), если значение foo имеет тип Object, тогда на объекте foo (при необходимости) будет определено именованное свойство 'bar', а его значение будет установлен на 'abc',

(c), если значение foo имеет тип Number, String или Boolean, тогда переменная foo не будет изменена. В этом случае вышеуказанная операция присваивания будет noop.

Итак, как вы видите, присвоение свойств переменным имеет смысл только в том случае, если эти переменные являются объектами. Если это не так, то присваивание вообще ничего не сделает или даже выбросит ошибку.


В вашем случае переменная test содержит значение типа String, поэтому это:

test.test = "test inner";

ничего не делает.


Однако, поскольку ES5 представил свойства доступа, существует исключение из того, что я сказал выше. Свойства Accessor позволяют нам определять функции, которые вызывается всякий раз, когда свойство либо извлекается, либо задается.

Например:

var str = '';
str.prop;

Здесь str - переменная, содержащая значение String. Поэтому доступ к свойству этой переменной должен быть no-op (str.prop просто возвращает undefined). Это верно с одним исключением: если String.prototype содержит свойство accessor 'prop' с определенным получателем, то этот getter будет вызван.

Итак, если это определено:

Object.defineProperty( String.prototype, 'prop', {
    get: function () {
        // this function is the getter
    }
}); 

то это

str.prop;

будет ссылаться на эту функцию getter.

Живая демонстрация: http://jsfiddle.net/fmNgu/

Однако я не думаю, что добавление свойств доступа к встроенным прототипам было бы хорошей практикой.

Ответ 2

Если вы используете объект String, вы можете добавить свойства:

var test = new String("test");
test.test = "test inner";
console.log(test.toString()); // prints out "test"
console.log(test.test); // prints out "test inner"