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

Почему существуют два типа строк JavaScript?

Это просто сильно ударил меня. Я не знаю, относится ли это ко всем браузерам (у меня нет другого компетентного браузера для тестирования), но по крайней мере у Firefox есть два типа строковых объектов.

Откройте консоль Firebugs и попробуйте следующее:

>>> "a"
"a"
>>> new String("a")
String { 0="a"}

Как вы можете визуально наблюдать, Firefox рассматривает new String("a") и "a" по-разному. В противном случае, оба типа строк, похоже, ведут себя одинаково. Например, есть доказательства того, что оба используют один и тот же объект-прототип:

>>> String.prototype.log = function() { console.log("Logged string: " + this); }
function()
>>> "hello world".log()
Logged string: hello world
>>> new String("hello world").log()
Logged string: hello world

Таким образом, очевидно, что оба они одинаковы. То есть, пока вы не попросите тип.

>>> typeof("a")
"string"
>>> typeof(new String("a"))
"object"

Мы также можем заметить, что когда this является строкой, она всегда является формой объекта:

>>> var identity = function() { return this }
>>> identity.call("a")
String { 0="a"}
>>> identity.call(new String("a"))
String { 0="a"}

Идя немного дальше, мы видим, что представление объекта без объекта не поддерживает никаких дополнительных свойств, но строка объекта:

>>> var a = "a"
>>> var b = new String("b")
>>> a.bar = 4
4
>>> b.bar = 4
4
>>> a.bar
undefined
>>> b.bar
4

Кроме того, забавный факт! Вы можете превратить строковый объект в строку без объекта с помощью функции toString():

>>> new String("foo").toString()
"foo"

Никогда не думал, что было бы полезно позвонить String.toString()! В любом случае.

Итак, все эти эксперименты задают вопрос: почему существуют два типа строк в JavaScript?


Комментарии показывают, что это также относится к каждому примитивному JavaScript-типу (номера и bools включены).

4b9b3361

Ответ 1

Существует два типа строк в строках Javascript - literal и String. Они ведут себя по-другому. Основное различие между ними состоит в том, что вы можете добавлять дополнительные методы и свойства к объекту String. Например:

var strObj = new String("object mode");
strObj.string_mode = "object"
strObj.get_string_mode = function() { return this.string_mode; }

// this converts it from an Object to a primitive string:
str = strObj.toString();

Строковый литерал просто временно передается объекту String для выполнения любого из основных методов.

То же самое относится и к другим типам данных. Здесь больше о примитивных типах данных и объектах.

ИЗМЕНИТЬ

Как отмечено в комментариях, строковые литералы не являются примитивными строками, а скорее "литеральной константой, тип которой является встроенным примитивным значением [string]", цитируя этот источник.

Ответ 2

Сравнение строковых значений с строковыми объектами.

"a" - строковое значение.

"a" === "a"; // true

new String("a") - строковый объект.

new String("a") === new String("a"); // false

Там обе строки. "a" просто получает строковое значение "a", где as new String("a") создает новый строковый объект, который внутри имеет строковое значение "a"

Ответ 3

Еще одна важная вещь, которую нужно запомнить:

typeof "my-string" // "string"
typeof String('my-string') // 'string'
typeof new String("my-string") // "object". 

Поэтому, проверяя, является ли аргумент или переменная строкой, вам нужно сделать хотя бы следующее.

function isString(arg) {
  if (!arg) {
    return false;
  }
  return typeof arg == "string" || arg.constructor == String;
}

Вышеуказанная функция все равно будет терпеть неудачу, если вы передадите объект String из другого фрейма /iframe. То есть:

frames[0].myStringVar.constructor != frames[1].myStringVar.constructor

Это потому, что конструктор String отличается для каждого контекста окна. Таким образом, надежный метод isString будет

function isString(obj) {
   return Object.prototype.toString.call(obj) == "[object String]";
}