JavaScript - производительность операторов === vs ==

Несколько недель назад я прочитал эту ветку ‹быстрее, чем‹ =? об операторах сравнения в C . Было сказано, что нет никакой разницы в производительности между < и <=, поскольку они интерпретируются как одинаковые / похожие машинные команды.

В то же время в «лучших практиках» нашей компании было сказано, что мы всегда должны использовать «===» для сравнения вместо «==». Итак, я начал задаваться вопросом, всегда ли это уместно, поскольку я привык использовать «==» и «typeof ... ==» и не хочу менять свой способ написания: -]

Обратите внимание, что это в контексте JavaScript.

Итак, у меня есть небольшое исследование, и здесь Который оператор равенства (== vs ===) следует использовать при сравнении JavaScript? сказано, что:

Это связано с тем, что оператор равенства == выполняет приведение типа ..., что означает, что интерпретатор неявно пытается преобразовать значения, а затем выполняет сравнение.

С другой стороны, оператор идентичности === не выполняет приведение типов и, следовательно, не преобразует значения значений при сравнении

И я начал задаваться вопросом, означает ли это, что, когда я использую оператор «===», я получу хорошую производительность, так как никакие ресурсы не будут тратиться на преобразование операндов. И после того, как весь код превращается в машинные команды, означает ли это, что так же, как нет разницы в C, когда вы используете < и <=, это то же самое в JavaScript и других языках?


person gotqn    schedule 11.09.2012    source источник
comment
Путь в ад вымощен микрооптимизациями.   -  person asawyer    schedule 11.09.2012
comment
В конце концов, кодирование превращается в машинные команды. Но не все инструкции на разных языках обязательно превращаются в один и тот же машинный код.   -  person BoltClock    schedule 11.09.2012
comment
Попробуйте взглянуть на этот пост: stackoverflow.com/questions/8044750/   -  person Chase    schedule 11.09.2012
comment
Вы хотите, чтобы ваш оператор сравнения выполнял приведение типов? Нет? Затем используйте ===. Я не вижу здесь выбора.   -  person Šime Vidas    schedule 11.09.2012
comment
В 2017 году стоит упомянуть, что === быстрее, чем == в V8, когда компилятор может доказать, что типы совпадают, выполнив анализ - последующие запуски кода могут сократить в ===, чего не могут в ==. Это деталь реализации, которая может измениться - используйте любой правильный оператор.   -  person Benjamin Gruenbaum    schedule 01.09.2017
comment
@BenjaminGruenbaum у вас есть ссылка (документы, веб-страница ...) на это заявление?   -  person darkylmnx    schedule 09.04.2018
comment
@darkylmnx Помогла бы ссылка на v8 / v8 / compiler? Вы также можете просто запустить этот код и выгрузить сборку, чтобы увидеть, что требуется дополнительная проверка, если компилятор не может доказать, что операнды относятся к одному типу.   -  person Benjamin Gruenbaum    schedule 09.04.2018
comment
проверю спасибо! как насчет этого, какой из них будет быстрее a === false OR if (! a) N @BenjaminGruenbaum   -  person darkylmnx    schedule 11.04.2018
comment
@darkylmnx, который зависит от многих вещей, например, может ли компилятор подтвердить тип a или нет - обычно === false быстрее, но важно избегать преждевременных оптимизаций - они также проверяют принципиально разные вещи.   -  person Benjamin Gruenbaum    schedule 11.04.2018


Ответы (6)


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

Из стандарта ECMA:

11.9.6 Алгоритм сравнения строгого равенства Сравнение x === y, где x и y являются значениями, дает истинное или ложное значение. Такое сравнение выполняется следующим образом:

  1. Если Тип (x) отличается от Типа (y), вернуть false.
  2. Если Type (x) - Undefined, вернуть true.
  3. Если Type (x) равен Null, вернуть true.
  4. Если Type (x) - Number, то файл. Если x равен NaN, вернуть false. б. Если y равно NaN, вернуть false. c. Если x имеет то же числовое значение, что и y, вернуть true. d. Если x равно +0, а y равно -0, вернуть истину. е. Если x равен -0, а y равен +0, вернуть истину. f. Вернуть false.
  5. Если Type (x) равен String, то верните true, если x и y являются одной и той же последовательностью символов (одинаковой длины и одинаковых символов в соответствующих позициях); в противном случае верните false.
  6. Если Type (x) имеет значение Boolean, вернуть true, если x и y оба истинны или оба ложны;
person gbjbaanb    schedule 11.09.2012
comment
Это содержит некоторую неверную информацию (и небольшое редактирование слишком поздно). Нет требования, чтобы str === str было истинным только для одного и того же объекта. "a" + "b" === "ab" верно, но не требуется, чтобы "a" + "b" был привязан к тому же объекту, что и "ab". Хотя оба == и === могут остановиться раньше, если реализация решит, что оба являются одним и тем же значением объекта (это будет оптимизация для конкретной реализации, которая будет работать в некоторых случаях), в противном случае строковые значения должны сравниваться посимвольно с ===. - person ; 11.09.2012
comment
Итак, в конце концов, за этим образцом знаков равенства скрывается много логики: -] ... Спасибо за ответ и ссылку на книгу ESMA - мне это очень интересно. - person gotqn; 11.09.2012
comment
Первый абзац в значительной степени неверен. Я могу дать подробное объяснение, если вам интересно. (Вы писали, имея в виду другой язык?) - person Šime Vidas; 11.09.2012
comment
@ ŠimeVidas будет полезно и интересно посмотреть. Я тоже использую другие языки - C / C ++ / Java / ruby ​​on rails - person gotqn; 11.09.2012
comment
@ ŠimeVidas: да, поэтому я пошел проверять стандарт! Если разные языки интерпретируют === по-разному, то это большая потенциальная ловушка для программистов. - person gbjbaanb; 12.09.2012
comment
@Joro Операторы === и == различаются только в том случае, если операнды имеют разные типы (например, String vs Number). Если сравниваются два значения Object, они ведут себя одинаково - obj1 == obj2 эквивалентно obj1 === obj2. То же самое и с другими типами - str1 == str2 эквивалентно str1 === str2 и т. Д. Это то, что было неправильно в первом абзаце (по крайней мере, в контексте JavaScript). - person Šime Vidas; 12.09.2012

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

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

  • == 1648 верно
  • === 1629 верно
  • контрольный тест 1575 верно

Если вычесть контрольный тест, похоже, что разница в их скоростях в моем браузере составляет ~ 30%. Если вы сделаете это несколько раз, вы можете получить разные ответы, но === обычно появляется быстрее всего, что, я думаю, является просто свидетельством того, насколько незначительна разница.

Я думаю, это в значительной степени доказывает то, что говорили другие, что разница в производительности - пустая трата времени, но это также показывает, что === на самом деле быстрее. Надеюсь, этот ответ может сэкономить время другим людям, тем, кто просто должен увидеть доказательства.

Обновления 2019 г.

2019-04-09 Firefox с улучшенным тестом:

  • == 1383 верно
  • === 1167 верно
  • контрольный тест 429 верно

2019-04-09 Chrome с улучшенным тестом:

  • == 249 верно
  • === 248 верно
  • контрольный тест 248 верно

2019-04-09 Edge с улучшенным тестом:

  • == 22510 верно
  • === 20315 верно
  • контрольный тест 4968 верно

С годами браузеры стали умнее, и, похоже, мой первоначальный тест столкнулся с классными оптимизациями в Chrome и Firefox, что сделало его бесполезным. Я усложнил оптимизацию теста и увеличил количество запусков, чтобы снова получить значимые результаты. Похоже, что === по-прежнему работает быстрее. Вероятно, это все еще бесполезная трата времени.

var testString = "42";
var testString2 = "43";
var testString3 = "42";
var testNumber = 42;
var testNumber2 = 43;
var testNumber3 = 42;

var testObject = {};
var testObject2 = {};
var testObject3 = testObject;


var start = Date.now();
var result = null;
for(var i = 0; i < 200000000; i++){
	result = 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString2 || testNumber == testNumber2 || testObject == testObject2 || 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3 && 
	testString == testString3 && testNumber == testNumber3 && testObject == testObject3
}

console.log("==", Date.now() - start, result);

var start = Date.now();
var result = null;
for(var i = 0; i < 200000000; i++){
	result =
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString2 || testNumber === testNumber2 || testObject === testObject2 || 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3 && 
	testString === testString3 && testNumber === testNumber3 && testObject === testObject3
}
console.log("===", Date.now() - start, result);
var start = Date.now();
var alwaysTrue = true;
var alwaysFalse = false;
for(var i = 0; i < 200000000; i++){
	result = 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysFalse || alwaysFalse || alwaysFalse || 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue && 
	alwaysTrue && alwaysTrue && alwaysTrue
}
console.log("control test", Date.now() - start, result);

person Rick Velde    schedule 22.08.2016
comment
При запуске в моем браузере (Firefox) значения равны == 1062 и _2 _..., но контрольный тест 283 также равен 283 (!) ... Что ж, === выполняется очень быстрее, интерпретируя тест. Проблема: при тестировании с Chrome результат обратный (!). == 387 === 352, контрольный тест 350 ... или NodeJS (node ​​v11.9.0) и с использованием современных console.time() console.timeEnd(), что-то вроде === 300ms, == 200ms и Nop 195ms (или запуск 10000000000 циклов === 29800 мс, == 20040 и nop 20045 мс), с == около нуля. ... Ну, я изменил код, чтобы избежать оптимизации компилятора, но проблема не устранена ... - person Peter Krauss; 29.03.2019
comment
Привет, @TimDown и Рик, вы можете подтвердить, что === быстрее в Firefox здесь, в этом другом вопросе ... Но вот это это не обычная проверка производительности, это мера реальности, способ проверить, что компиляторы делают (в среднем) для реализации предписаний ECMA 262. - person Peter Krauss; 31.03.2019

Во-первых, производительность просто не вызывает беспокойства. Для любого реального сценария любое увеличение производительности при использовании одного оператора по сравнению с другим будет бесконечно малым по сравнению с другими узкими местами в коде (обычно манипуляции с DOM будут целью номер один).

Во-вторых, во многих случаях == и === будут выполнять точно такие же действия. Когда типы двух операндов одинаковы (например, две строки или два числа), в спецификации ECMAScript есть точно такие же шаги для двух операторов. Поэтому, если вы наблюдаете разницу в производительности между двумя операторами для операндов одного и того же типа в одном браузере или в другой среде, нет ни гарантии, ни даже вероятности того, что вы увидите аналогичную разницу в другом браузере.

В случае typeof, как упоминалось в вашем вопросе, два операнда гарантированно будут одного типа (строки), и оба оператора будут делать одно и то же, поэтому единственные причины отдать предпочтение одному оператору над другим стилистические.

Сообщество JS в целом заняло довольно жесткую позицию в этом вопросе: похоже, что консенсус состоит в том, что «никогда не используйте == и !=, если вам не нужно принуждение типов», что, на мой взгляд, слишком догматично.

person Tim Down    schedule 25.09.2012
comment
Много раз мне давали большие массивы данных с сервера. Представьте себе тысячу строк, и каждое значение в этой строке нужно сравнить с чем-то другим. Если информация возвращается в виде строки, и я сравниваю ее с ==, потому что это все-таки число, это означает 1000 скрытых операций. Вот почему я думаю, что производительность имеет значение. - person gotqn; 25.09.2012
comment
@Joro: Я не уверен, что понимаю вашу точку зрения. Если ваши операнды относятся к разным типам, тогда === и == будут вести себя по-разному, поэтому выбора нет: вы должны использовать тот, который выполняет нужное вам сравнение. - person Tim Down; 25.09.2012
comment
Я понимаю вашу точку зрения. Я хотел сказать, что нужно быть готовым к любой ситуации. Записи возврата могут быть в строковом формате, но через некоторое время функции сервера обновятся, а затем будут возвращены как числа. Итак, на мой взгляд, лучшим решением будет использование ==, потому что я не буду зависеть от формата возвращаемых данных. - person gotqn; 25.09.2012
comment
Это плохой ответ: не говорите, что быстрее, не приводите никаких доказательств (без эталонного теста), только формальную спецификацию, которая не является реальной реализацией языка. . - person Peter Krauss; 29.03.2019
comment
@PeterKrauss: Я категорически не согласен. Спецификация языка определяет, как должны работать реализации. Тест, показывающий, как несколько реализаций работают сегодня, практически ничего не говорит вам о том, как будут работать завтрашние реализации: реализация, которая имеет значительную разницу между == и === при сравнении операндов одного и того же типа, ошиблась и, вероятно, будет исправлена ​​в будущие версии. Я также думаю, как упоминалось в ответе, что почти во всех сценариях бессмысленно беспокоиться о какой-либо разнице потенциалов. - person Tim Down; 29.03.2019
comment
Привет, я согласен с тем, что спецификация стабильна и должна быть процитирована ... Но посмотрите сравнение BigInt (что привело меня сюда), это новый тип данных, который требует много времени по отношению к Number. Мне не нужно ждать 1 год до стабилизации языковой реализации, мне нужна только подсказка, чтобы убедиться, что я сделал все возможное, эта подсказка является эталоном. Мой комментарий также касается хорошего ответа, а ваш - нет; потому что наиболее важно сказать, что === является лучшим, а затем дополнить эту информацию очень незначительными отличиями. У вашего ансера есть только хорошее дополнение, но полное примечание. - person Peter Krauss; 29.03.2019
comment
@PeterKrauss: Я не думаю, что == или === лучше другого. При сравнении операндов одного типа они одинаковы, поэтому выбор из них является чисто стилистическим; при сравнении операндов разных типов (таких как BigInt и Number) они имеют разное поведение, поэтому выбора нет. - person Tim Down; 29.03.2019
comment
@TimDown, вы не можете сказать, что вещь то же самое, когда это не так, это ложное утверждение: бесконечно малая разница - это разница (и у нас есть измерить его!). Мера Истина, если она очень-очень маленькая или не очень маленькая, это мнение (нужно только разделить его) ... вы путаете две вещи: 1. описание реального мира с давность нормы; 2. ваше мнение с правдой. - person Peter Krauss; 29.03.2019
comment
@PeterKrauss: Я могу лишь повторить то же самое. Я согласен с тем, что один оператор может быть немного быстрее другого для операндов того же типа в конкретном браузере (хотя ответ, на который вы указали ссылку, ничего не доказывает). Это особенность браузера, и маловероятно, что она будет воспроизведена во всех средах, поскольку указанное поведение идентично. Крайне необычно писать код для одного неизменного браузера, поэтому результаты в одном конкретном браузере не важны. Это последний комментарий, который я сделаю здесь, потому что ответы SO - плохое место для аргументов. - person Tim Down; 31.03.2019
comment
@PeterKrauss: Я думаю, что частично ошибался в этом, в частности, реализация, которая имеет значительную разницу между == и === при сравнении операндов одного и того же типа, ошиблась: возможно, современные компиляторы JS могут оптимизировать === в способ, которым они не могут с ==. - person Tim Down; 22.12.2020

Неважно, какую производительность вы получите, === явно лучший выбор в этом случае. Все остальное, например повышение производительности, - это лишь вишенка на торте. К тому же разница в любом случае минимальна.

person Elliot Bonneville    schedule 11.09.2012

Это язык сценариев. Производительность этих операторов не должна иметь настолько большого значения, что вам следует об этом беспокоиться, потому что есть множество других вещей, которые потребляют гораздо больше энергии, например, тот факт, что он работает на виртуальной машине, - это слабая типизация, работает с HTML DOM внутри браузера ...

Кроме того, оба оператора делают разные вещи, поэтому в любом случае нельзя будет взаимозаменять один с другим.

Тем не менее, я думаю (но не тестировал), что === быстрее. Причина в том, что ему нужно только сравнить тип, и если он совпадает, сравнить необработанные данные. Оператор == попытается преобразовать один тип в другой, если они не совпадают. В большинстве случаев это будет более дорогостоящая операция.

И это к счастью, потому что в большинстве случаев === - лучший вариант. :)

Но в любом случае вы можете легко протестировать его (убедитесь, что вы тестируете несколько случаев, как одного типа, так и пары разных типов), но если вы не знаете, как это проверить, я бы вообще перестал об этом беспокоиться. Разница, если она есть, вас не убьет.

person GolezTrol    schedule 11.09.2012
comment
Несмотря на общий характер, как и большинство этих ответов относительно производительности == и ===, я подозреваю, что на фактическую скорость == и === влияют предоставленные значения. Хотя правила == кажутся длиннее или требуют большего количества операций, следует учитывать, что == является суперсоответствием ===, так что всегда можно попробовать === правила и остановиться, если есть совпадение до == правил. Конечно, это в конечном итоге будет зависеть от многих других факторов, не последним из которых является реализация. - person ; 11.09.2012
comment
@pst, это правильно, но если скорость настолько важна, что вам приходится использовать такие двойные проверки, вы можете подумать о другом языке, чем Javascript. Кроме того, если вы строго относитесь к своим типам (переменная, скажем, целочисленная или неназначенная, но никогда не является строкой), вы можете безопасно использовать оператор строгого сравнения. Даже в тех случаях, когда вам понадобится ==, вы можете в качестве альтернативы сначала выполнить приведение типов. Думаю, это делает ваш код более читабельным и «безопасным», что для меня важнее скорости. - person GolezTrol; 11.09.2012

Разница в производительности незначительна, а это значит, что не стоит тратить драгоценные мозговые циклы на размышления об этом. Если вы действительно хотите знать, вам следует протестировать.

Используйте ===, если у вас нет веских причин не делать этого (вероятно, нет).

person Triptych    schedule 11.09.2012