Сравнение производительности равенства строк строки JavaScript
У меня есть вопрос javascript noob. Скажем, у нас есть две очень большие строки (~ миллион символов или более), которые равны - они имеют одинаковую длину и один и тот же контент.
Пусть говорят, что у нас есть эти две функции, которые делают то же самое (сравнивают строки):
function equals1(a, b) {
return a === b;
}
function equals2(a, b) {
if (a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
Почему первая функция (equals1()) почти в два раза быстрее, чем вторая?
Как можно улучшить вторую, чтобы она выполнялась так же хорошо, как первая?
Ответы
Ответ 1
Первое делает то же самое. Если строки имеют разные длины, они вернут false. Затем он проверяет, совпадают ли символы с одинаковыми индексами. Однако он реализован на уровне реализации JS, поэтому он работает так же быстро, как C, С++, Java или на любом другом языке, на котором написана реализация JavaScript.
Ответ 2
Первая функция быстрее, потому что ей не нужно проверять, если i < a.length
миллион раз, и выполнить операцию увеличения в i
миллион раз.
Ответ 3
Скорее всего, Javascript выполняет интернирование строк (Выполняют ли обычные реализации JavaScript использование интернирования строк?) в соответствии с тем, кто находится в комитете ECMAScript. Я думал, что тогда === будет O (1), но на основе теста производительности исходного плаката это O (n), поскольку удвоение строки удваивает время для равенства. Это действительно печально, что интернирование строк не используется они так и должны быть.
Обновление: JSPerf
Оригинальные заявки на плакаты должны быть скопированы для сложности O (N)
Из http://jsperf.com/eqaulity-is-constant-time
Кажется, что даже если у меня есть 16-кратная большая строка, время не меняется более 1-2%
Поэтому, пожалуйста, пересмотреть те вещи, которые я пробил и ваши вниз голоса
Другими словами:
когда вы делаете
var str1 = "stringwithmillionchars"; //stored in address 51242
var str2 = "stringwithmillionchars"; //stored in address 12313
"stringwithmillionchars" будет сохранен один раз, если скажем в адресе 201012 памяти
и оба str1 и str2 будут "указывать в этом адресе 201012. Этот адрес можно определить с помощью какого-либо хэширования для сопоставления с определенными местоположениями в памяти.
Поэтому при выполнении
"stringwithmillionchars"==="stringwithmillionchars"
будет выглядеть как
getContentOfAddress(51242)===getContentOfAddress(12313)
или 201012 === 201012
который принимает O (1)/постоянное время
Цикл for в вашем примере (equals2()) имеет время O (N), где N - длина обеих строк. Это потому, что он должен выполнять N сравнений между каждой парой символов и N сравнениями между я и str.length.
Примечание: номера адресов выбраны случайным образом для иллюстрации.
Важно. На основе сопоставлений производительности с моим вопросом (Почему Javascript ===/== равенство строк иногда имеет постоянную временную сложность и несколько раз имеет линейный временная сложность) интернирование происходит только тогда, когда строки назначаются напрямую с кавычками, иначе сравнение будет принимать линейное время вместо константы, поскольку происходит сравнение char -to- char.