javascript Производительность примитивной строки vs string object [duplicate]

У меня была аналогичная проблема, но в моем случае решение было другим. мой файл, который содержал php-код, назывался «somename.html», изменил его на «somename.php», работал отлично

85
задан Daniel A. White 25 October 2014 в 13:24
поделиться

8 ответов

JavaScript имеет две основные категории типов: примитивы и объекты.

var s = 'test';
var ss = new String('test');

Шаблоны с одиночной кавычкой / двойной цитатой идентичны по функциональности. В стороне, поведение, которое вы пытаетесь назвать, называется авто-бокс. Итак, что на самом деле происходит, так это то, что примитив преобразуется в его тип-оболочку при вызове метода типа-оболочки. Положите simple:

var s = 'test';

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

Итак, что происходит, когда вы делаете s.charAt(i) например?

Поскольку s не является экземпляром String, JavaScript будет автоматически помещать s, который имеет typeof string к его типу обертки, String, с typeof object или точнее s.valueOf(s).prototype.toString.call = [object String] ,

Поведение автоматического бокса приводит к тому, что s возвращается туда и обратно в свой тип оболочки, но стандартные операции невероятно быстры, так как вы имеете дело с более простым типом данных. Однако авто-бокс и Object.prototype.valueOf имеют разные эффекты.

Если вы хотите принудительно включить автоматический бокс или придать примитиву своему типу-оболочке, вы можете использовать Object.prototype.valueOf, но поведение отличается , На основе широкого спектра тестовых сценариев автоматическое боксирование применяет только «необходимые» методы, не изменяя примитивный характер переменной. Вот почему вы получаете лучшую скорость.

106
ответ дан flavian 21 August 2018 в 23:26
поделиться

Существование объекта имеет мало общего с фактическим поведением String в механизмах ECMAScript / JavaScript, поскольку корневая область будет просто содержать объекты функции для этого. Таким образом, функция charAt (int) в случае строкового литерала будет обыскана и исполнена.

С реальным объектом вы добавляете еще один слой, где метод charAt (int) также выполняется поиск по самому объекту до стандартное поведение срабатывает (так же, как указано выше). По-видимому, в этом случае наблюдается удивительно большая работа.

BTW Я не думаю, что примитивы фактически преобразуются в объекты, но механизм сценария просто помечает эту переменную как тип строки, и поэтому она может найти все предоставленные функции, чтобы он выглядел так, как будто вы вызываете объект. Не забывайте, что это время выполнения скрипта, которое работает на разных принципах, чем время выполнения OO.

3
ответ дан clearwater 21 August 2018 в 23:26
поделиться

Если вы используете new, вы явно заявляете, что хотите создать экземпляр объекта . Поэтому new String создает объект Object , обертывающий примитив String , что означает, что любое действие на нем связано с дополнительным уровнем работы.

typeof new String(); // "object"
typeof '';           // "string"

Поскольку они имеют разные типы, ваш интерпретатор JavaScript также может оптимизировать их по-разному , как указано в комментариях .

9
ответ дан Community 21 August 2018 в 23:26
поделиться

Это скорее зависит от реализации, но я сделаю снимок. Я приведу пример с V8, но я предполагаю, что другие двигатели используют аналогичные подходы.

Строковый примитив анализируется на объект v8::String . Следовательно, методы могут быть вызваны непосредственно на него, как указано в jfriend00 .

Объект String, с другой стороны, анализируется на v8::StringObject , который расширяется Object и, кроме того, что он является полноценным объектом, служит в качестве обертки для v8::String.

Теперь это логично, вызов new String('').method() должен удалить это v8::StringObject ] v8::String перед выполнением метода, следовательно, он медленнее.


Во многих других языках примитивные значения не имеют методов.

Способ MDN кажется, является самым простым способом объяснить, как работает авто-бокс примитивов (как также упоминается в ответе flav ), то есть как значения JavaScript primitive-y могут invoke methods.

Однако интеллектуальный движок не будет преобразовывать строку primitive-y в объект String каждый раз, когда вам нужно вызвать метод. Это также информативно упоминается в спецификации Annotated ES5 в отношении разрешения свойств (и «методов» №) примитивных значений:

ПРИМЕЧАНИЕ. Объект, который может быть созданный на шаге 1, недоступен вне указанного выше метода. Реализация может решить избежать фактического создания объекта. [...]

На очень низком уровне строки чаще всего реализуются как неизменные скалярные значения. Пример структуры обертки:

StringObject > String (> ...) > char[]

Чем глубже вы из примитива, тем дольше это потребуется, чтобы добраться до него. На практике примитивы String намного чаще, чем StringObject s, поэтому для двигателей не удивительно добавлять методы к классу соответствующих (интерпретируемых) объектов примитивов String вместо преобразования между String и StringObject, как поясняет объяснение MDN.


¹ В JavaScript «метод» - это просто соглашение об именах для свойства, которое разрешает значение функции типа.

26
ответ дан Fabrício Matté 21 August 2018 в 23:26
поделиться
  • 1
    Пожалуйста. =] Теперь мне интересно, объясняется ли объяснение MDN только потому, что это самый простой способ понять авто-бокс или есть ли какая-либо ссылка на него в спецификации ES. Чтение по всей спецификации на данный момент, чтобы проверить, не забудьте обновить ответ, если я когда-нибудь найду ссылку. – Fabrício Matté 23 June 2013 в 00:59
  • 2
    Отличное понимание реализации V8. Я добавлю, что бокс здесь не просто для решения этой функции. Он также должен передать эту ссылку в метод. Теперь я не уверен, что V8 пропускает это для встроенных методов, но если вы добавите собственное расширение, чтобы сказать String.prototype, вы получите коробчатую версию строкового объекта каждый раз, когда он вызывается. – Ben 7 June 2016 в 02:12

Когда вы объявляете:

var s = '0123456789';

, вы создаете примитив строки. Этот примитив строки имеет методы, которые позволяют вам называть методы на нем, не преобразовывая примитив в объект первого класса. Поэтому ваше предположение, что это будет медленнее, потому что строка должна быть преобразована в объект, неверна. Он не должен быть преобразован в объект. Сам примитив может вызывать методы.

Преобразование его в полномасштабный объект (который позволяет вам добавлять к нему новые свойства) является дополнительным шагом и не делает ускорения строк быстрее (на самом деле ваш тест показывает, что он делает их медленнее).

5
ответ дан jfriend00 21 August 2018 в 23:26
поделиться
  • 1
    Как получилось, что примитив строки наследует все свойства прототипа, включая пользовательские String.prototype? – Yuriy Galanter 23 June 2013 в 00:17
  • 2
    var s = '0123456789'; является примитивным значением, как это значение может иметь методы, я в замешательстве! – The Alpha 23 June 2013 в 00:20
  • 3
    @SheikhHeera - примитивы встроены в реализацию языка, поэтому переводчик может дать им особые полномочия. – jfriend00 23 June 2013 в 00:21
  • 4
    @SheikhHeera - Я не понимаю ваш последний комментарий / вопрос. Строковый примитив сам по себе не поддерживает добавление к нему ваших собственных свойств. Чтобы это разрешить, javascript также имеет объект String, который имеет все те же методы, что и примитив строки, но является полномасштабным объектом, который можно рассматривать как объект всеми способами. Эта двойная форма кажется немного беспорядочной, но я подозреваю, что это было сделано как компромисс производительности, поскольку 99% -й случай - это использование примитивов, и они, вероятно, могут быть быстрее и эффективнее памяти, чем строковые. – jfriend00 23 June 2013 в 00:24
  • 5
    @SheikhHeera ", преобразованный в строковый объект & quot; как MDN выражает это, чтобы объяснить, как примитивы могут вызывать методы. Они не буквально преобразуются в строковые объекты. – Fabrício Matté 23 June 2013 в 00:30

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

В принципе, другое различие между ними заключается в использовании eval. eval ('1 + 1') дает 2, тогда как eval (new String ('1 + 1')) дает '1 + 1', поэтому, если некоторый блок кода может быть выполнен как «нормально», так и с eval, он может приводят к странным результатам

2
ответ дан luanped 21 August 2018 в 23:26
поделиться

В случае строкового литерала мы не можем назначать свойства

var x = "hello" ;
x.y = "world";
console.log(x.y); // this will print undefined

. Если в случае String Object мы можем назначить свойства

var x = new String("hello");
x.y = "world";
console.log(x.y); // this will print world
10
ответ дан refactor 21 August 2018 в 23:26
поделиться
  • 1
    Наконец, кто-то мотивирует, почему нам нужны String объекты. Спасибо! – Ciprian Tomoiagă 29 November 2016 в 17:18

Строковый литерал:

Строковые литералы неизменяемы, а значит, после их создания их состояние не может быть изменено, что также делает их потокобезопасными.

var a = 's';
var b = 's';

a==b result будет «истинным» и тем же объектом, что и тот, и другой.

String Object:

Здесь создаются два разных объекта: у них разные ссылки:

var a = new String("s");
var b = new String("s");

a==b результат будет ложным, потому что у них разные ссылки.

9
ответ дан Tot Zam 21 August 2018 в 23:26
поделиться
  • 1
    Является ли объект строкой неизменным? – Yang Wang 9 July 2017 в 06:31
  • 2
    @YangWang - это глупый язык, как для a, так и для amp; b попытайтесь присвоить a[0] = 'X', что выполнит , но не будет работать так, как вы могли бы ожидать – ruX 5 January 2018 в 13:47
Другие вопросы по тегам:

Похожие вопросы: