В чем разница между строковыми литералами и строковыми объектами в JavaScript?
принято от MDN
строковые литералы (обозначаются двойными или одинарными кавычками) и строки
возвращается из строковых вызовов в контексте, отличном от конструктора (т. е. без
используя ключевое слово new) являются примитивными строками. JavaScript автоматически
преобразует примитивы в строковые объекты, чтобы их можно было использовать
Строковые методы объекта для примитивных строк. В контекстах, где
метод должен быть вызван на примитивную строку или поиск свойства
происходит, JavaScript автоматически обернет строковый примитив и
вызовите метод или выполните поиск свойства.
Итак, я думал (логически) операции (вызовы методов) на строковых литералах должны быть медленнее, чем операции на строковых объектах, потому что любой строковый литерал преобразуется в строковый объект (дополнительная работа) перед method применяется к строке.
но в этом
8 ответов:
JavaScript имеет две основные категории типов, примитивы и объекты.
var s = 'test'; var ss = new String('test');шаблоны одинарных/двойных кавычек идентичны с точки зрения функциональности. Кроме того, поведение, которое вы пытаетесь назвать, называется Авто-боксом. Так что на самом деле происходит то, что примитив преобразуется в свой тип оболочки при вызове метода типа оболочки. Поставить просто:
var s = 'test';- это примитивный тип данных. У него нет методов, это не более чем указатель на ссылку на память необработанных данных, что объясняет гораздо более высокую скорость произвольного доступа.
так что же происходит, когда вы делаете
s.charAt(i)например?С
sне является экземпляромString, JavaScript будет auto-boxs, имеющегоtypeof stringк своему типу оболочки,StringСtypeof objectили точнееs.valueOf(s).prototype.toString.call = [object String].поведение авто-бокс бросает
sвзад и вперед к своему типу оболочки по мере необходимости, но стандартные операции невероятно быстро, так как вы имеете дело с более простым типом данных. Однако авто-бокс иObject.prototype.valueOfимеют различные эффекты.если вы хотите заставить авто-бокс или привести примитив к его типу оболочки, вы можете использовать
Object.prototype.valueOf, но поведение отличается. На основе широкого спектра тестовых сценариев auto-boxing применяет только "необходимые" методы, не изменяя примитивный характер переменной. Вот почему вы получаете лучшую скорость.
это скорее зависит от конкретной реализации, но я попробую. Я приведу пример с V8, но я предполагаю, что другие двигатели используют аналогичные подходы.
строковый примитив разбирается на
v8::String
в случае строкового литерала мы не можем назначить свойства
var x = "hello" ; x.y = "world"; console.log(x.y); // this will print undefined, тогда как в случае объекта String можно присвоить свойства
var x = new String("hello"); x.y = "world"; console.log(x.y); // this will print world
Если вы используете
new, вы явно заявляете, что хотите создать экземпляр объект. Таким образом,new Stringсоздает объект упаковка строка примитивный, что означает, что любое действие на него включает в себя дополнительный слой работы.typeof new String(); // "object" typeof ''; // "string"как они бывают разных типов, ваш JavaScript переводчик может также оптимизировать их по-разному, как уже упоминалось в комментариях.
Строковый Литерал:
строковые литералы неизменяемы, что означает, что после их создания их состояние не может быть изменено, что также делает их потокобезопасными.
var a = 's'; var b = 's';
a==bрезультат будет 'true' обе строки ссылаются на один и тот же объект.Строковый Объект:
здесь создаются два разных объекта, и они имеют разные ссылки:
var a = new String("s"); var b = new String("s");
a==bрезультат будет ложным, потому что они есть разные ссылки.
когда вы заявляете:
var s = '0123456789';вы создаете строковый примитив. Этот строковый примитив имеет методы, которые позволяют вызывать методы на нем без преобразования примитива в объект первого класса. Поэтому ваше предположение, что это будет медленнее, потому что строка должна быть преобразована в объект, неверно. Он не должен быть преобразован в объект. Сам примитив может вызывать эти методы.
преобразование его в полноценный объект (что позволяет добавить новые свойства к нему) является дополнительным шагом и не делает строки oeprations быстрее (на самом деле ваш тест показывает, что это делает их медленнее).
существование объекта имеет мало общего с фактическим поведением строки в движках ECMAScript/JavaScript, поскольку корневая область будет просто содержать функциональные объекты для этого. Таким образом, функция charAt(int) в случае строкового литерала будет искать и выполнять.
с реальным объектом вы добавляете еще один слой, где метод charAt (int) также ищется на самом объекте до того, как начнется стандартное поведение (так же, как и выше). Видимо есть на удивление большой объем работы проделан в этом случае.
кстати, я не думаю, что примитивы на самом деле преобразуются в объекты, но движок скрипта просто помечает эту переменную как строковый тип, и поэтому он может найти все предоставленные функции для нее, поэтому похоже, что вы вызываете объект. Не забывайте, что это среда выполнения скрипта, которая работает по другим принципам, чем среда выполнения OO.
Я вижу, что этот вопрос давно решен, есть еще одно тонкое различие между строковыми литералами и строковыми объектами, поскольку никто, похоже, не коснулся его, я думал, что просто напишу его для полноты.
в основном другое различие между ними заключается в использовании eval. eval ('1 + 1') дает 2, тогда как eval (новая строка ('1 + 1')) дает '1 + 1', поэтому, если определенный блок кода может быть выполнен как "нормально", так и с eval, это может привести к странным результаты
Comments