Редактировать: для справки вот по спецификации объяснение д-ра Акселя Раушмайера
http://www.2ality.com/2011/06/javascript-equality.html
Действительно здорово написать.
===
(Строгое равенство): учитываются только равные значения одного типа.
- undefined === undefined, null === null,
- NaN === ничего, включая себя,
- Примитив [Number | String | Boolean] === значение примитива равно,
- к себе (+0 === -0)
- Два объекта [Массив | Объект | Функция] === Только сам (та же самая сущность)
==
(Меньшее равенство)
- Если оба значения имеют одинаковый тип: сравните с ===.
- undefined == null
- число и строка: строка => число и сравнение
- булево и не булево => не булево число и сравнить
- строка или число => объект: преобразовать объект в примитив и сравнение.
Во всех современных средах Javascript они реализованы совершенно по-разному. Проще говоря, ==
проверяет сходство путем преобразования заданных переменных в примитивы (строка, число, логическое значение). ===
проверяет на строгость одинаковости, что означает точно такой же объект или примитивное значение без преобразования.
Если вы делаете
objOne == objTwo
что на самом деле происходит
[[EQUALS]].call(objOne.valueOf(), objTwo.valueOf())
Разрешение valueOf может в некоторой степени влиять на функции, представленные в JS, и на внутренние компоненты движка. Достаточно сказать, что сравнение всегда будет заканчиваться двумя значениями, приведенными к примитиву, иначе будет выдано сообщение об ошибке.
Редактировать: EQUALS
сначала пытается STRICT_EQUALS
, что прерывает остальную часть процесса.
Интересным здесь является то, что valueOf (и его партнер toString) могут быть переопределены. Запустите этот кусок кода в Chrome (я думаю, что любой webkit, не уверен, что JSC и V8 разделяют этот лакомый кусочек). Это взорвет ваш разум:
var actions = [];
var overload = {
valueOf: function(){
var caller = arguments.callee.caller;
actions.push({
operation: caller.name,
left: caller.arguments[0] === this ? "unknown" : this,
right: caller.arguments[0]
});
return Object.prototype.toString.call(this);
}
};
overload.toString = overload.valueOf;
overload == 10;
overload === 10;
overload * 10;
10 / overload;
overload in window;
-overload;
+overload;
overload < 5;
overload > 5;
[][overload];
overload == overload;
console.log(actions);
Выход:
[ { operation: 'EQUALS',
left: overload,
right: 10 },
{ operation: 'MUL',
left: overload,
right: 10 },
{ operation: 'DIV',
left: 'unknown',
right: overload },
{ operation: 'IN',
left: overload,
right: DOMWindow },
{ operation: 'UNARY_MINUS',
left: overload,
right: undefined },
{ operation: 'TO_NUMBER',
left: overload,
right: undefined },
{ operation: 'COMPARE',
left: overload,
right: 5 },
{ operation: 'COMPARE',
left: 'unknown',
right: overload },
{ operation: 'ToString',
left: 'unknown',
right: overload } ]
Суть различия между ==
и ===
иллюстрируется тем, что ===
не отображается в этом списке. Он полностью пропускает путешествие в JavascriptLand. Это приключение стоит дорого при сравнении производительности.
Однако вам необходимо учитывать оптимизацию движка. Для большинства объектов движок сможет вырезать большинство шагов и остаться в NativeLand и получить почти такую же производительность. Но это не гарантия, и если что-то мешает движку использовать оптимизацию, некоторую фантазию в вашем коде или переопределение встроенных функций или множество проблем, то вы сразу же увидите результат в производительности. ===
заставляет его.
===
- это почти единственная неизменная вещь в Javascript.