Почему я не могу добавить свойства к строковому объекту в JavaScript? - PullRequest
57 голосов
/ 05 марта 2011

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

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

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

Ответы [ 2 ]

80 голосов
/ 05 марта 2011

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

  • 5 примитивных типов: String , Число , Boolean , Нуль , Не определено
  • 1 не примитивный тип: Объект

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

Когда вы пытаетесь присвоить свойство с именем 'bar' переменной foo, например:

foo.bar = 'abc';

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

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

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

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

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


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

test.test = "test inner";

вообще ничего не делает.


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

Например:

var str = '';
str.prop;

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

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

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

тогда это

str.prop;

вызовет эту функцию получения.

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

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

30 голосов
/ 16 марта 2011

Если вы используете объект 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...