Какой оператор равенства (== vs ===) следует использовать в сравнениях JavaScript?
1696782 просмотра
30 ответа
Я использую JSLint, чтобы пройти через JavaScript, и он возвращает много предложений о замене ==
(два знака равенства) на ===
(три знака равенства) при выполнении таких вещей, как сравнение idSele_UNVEHtype.value.length == 0
внутри if
оператора.
Есть ли выигрыш в производительности для замены ==
на ===
?
Любое улучшение производительности будет приветствоваться, так как существует много операторов сравнения.
Если преобразование типов не происходит, будет ли выигрыш в производительности ==
?
Ответы (30)
6301 плюса
Оператор identity ( ===
) ведет себя идентично оператору равенства ( ==
), за исключением того, что преобразование типов не выполняется, и типы должны быть одинаковыми, чтобы считаться равными.
Ссылка: Учебник по Javascript: Операторы сравнения
==
Оператор сравнения равенства после выполнения любых необходимых преобразований типов . ===
Оператор не делать преобразование, так что, если два значения не имеет такой же тип ===
будет просто вернуться false
. Оба одинаково быстры.
Процитирую превосходный JavaScript Дугласа Крокфорда : Хорошие части ,
В JavaScript есть два набора операторов равенства:
===
и!==
, и их злые близнецы==
и!=
. Хорошие работают так, как вы ожидаете. Если два операнда имеют одинаковый тип и имеют одинаковое значение, то===
производитtrue
и!==
производитfalse
. Злые близнецы поступают правильно, когда операнды относятся к одному и тому же типу, но если они относятся к разным типам, они пытаются привести значения. правила, по которым они это делают, сложны и не запоминаются. Вот некоторые из интересных случаев:'' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true
Отсутствие транзитивности вызывает тревогу. Мой совет - никогда не использовать злых близнецов. Вместо этого всегда используйте
===
и!==
. Все приведенные сравнения производятсяfalse
с===
оператором.
Обновить:
Хороший момент был воспитан @Casebash в комментариях и в @Phillipe Laybaert в ответ относительно ссылочных типов. Для справочных типов ==
и ===
действуют последовательно друг с другом (кроме как в особом случае).
var a = [1,2,3];
var b = [1,2,3];
var c = { x: 1, y: 2 };
var d = { x: 1, y: 2 };
var e = "text";
var f = "te" + "xt";
a == b // false
a === b // false
c == d // false
c === d // false
e == f // true
e === f // true
Особый случай - когда вы сравниваете литерал с объектом, который оценивает один и тот же литерал из-за его метода toString
или valueOf
метода. Например, рассмотрим сравнение строкового литерала со строковым объектом, созданным String
конструктором.
"abc" == new String("abc") // true
"abc" === new String("abc") // false
Здесь ==
оператор проверяет значения двух объектов и возвращает их true
, но ===
видит, что они не одного типа, и возвращает false
. Какой из них правильный? Это действительно зависит от того, что вы пытаетесь сравнить. Мой совет - полностью обойти вопрос и не использовать String
конструктор для создания строковых объектов.
Ссылка
http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3
1102 плюса
Использование ==
оператора ( Равенство )
true == 1; //true, because 'true' is converted to 1 and then compared
"2" == 2; //true, because "2" is converted to 2 and then compared
Использование ===
оператора ( личность )
true === 1; //false
"2" === 2; //false
Это связано с тем, что оператор равенства ==
выполняет приведение типов , что означает, что интерпретатор неявно пытается преобразовать значения перед сравнением.
С другой стороны, оператор тождества ===
не выполняет приведение типов и, следовательно, не преобразует значения при сравнении и поэтому работает быстрее (как в соответствии с этим тестом JS ), поскольку пропускает один шаг.
678 плюса
Интересное наглядное представление сравнения равенства между ==
и ===
.
Источник: http://dorey.github.io/JavaScript-Equality-Table/
var1 === var2
При использовании
===
для проверки равенства JavaScript все как есть. Ничто не преобразуется перед оценкой.
var1 == var2
При использовании
==
для проверки на равенство JavaScript происходят некоторые интересные преобразования.
Автор: SNag Размещён: 05.05.2014 05:21Мораль истории:
Используйте,
===
если вы не полностью понимаете конверсии, которые происходят с==
.
603 плюса
В ответах здесь я ничего не читал о том, что значит равный . Некоторые скажут, что это ===
означает « равный» и «того же типа» , но это не совсем так. Фактически это означает, что оба операнда ссылаются на один и тот же объект или, в случае типов значений, имеют одинаковое значение .
Итак, давайте возьмем следующий код:
var a = [1,2,3];
var b = [1,2,3];
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
Тут то же самое:
var a = { x: 1, y: 2 };
var b = { x: 1, y: 2 };
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
Или даже:
var a = { };
var b = { };
var c = a;
var ab_eq = (a === b); // false (even though a and b are the same type)
var ac_eq = (a === c); // true
Такое поведение не всегда очевидно. В этой истории есть нечто большее, чем быть равными и быть однотипными.
Правило таково:
Для типов значений (чисел):
a === b
возвращает true, еслиa
иb
имеют одинаковое значение, и имеют одинаковый тип
Для ссылочных типов:
a === b
возвращает true еслиa
иb
ссылается на точно такой же объект
Для строк:
a === b
возвращает true, еслиa
иb
являются строками, и содержат одинаковые символы
Струны: особый случай ...
Строки не являются типами значений, но в Javascript они ведут себя как типы значений, поэтому они будут «равны», когда символы в строке одинаковы и имеют одинаковую длину (как объяснено в третьем правиле)
Теперь становится интересно:
var a = "12" + "3";
var b = "123";
alert(a === b); // returns true, because strings behave like value types
Но как насчет этого?
var a = new String("123");
var b = "123";
alert(a === b); // returns false !! (but they are equal and of the same type)
Я думал, что строки ведут себя как типы значений? Ну, это зависит от того, кого вы спрашиваете ... В этом случае a и b не одного типа. a
имеет тип Object
, тогда как b
имеет тип string
. Просто помните, что создание строкового объекта с помощью String
конструктора создает что-то типа, Object
который большую часть времени ведет себя как строка .
264 плюса
Позвольте мне добавить этот совет:
Если сомневаетесь, прочитайте спецификацию !
ECMA-262 - это спецификация языка сценариев, для которого JavaScript является диалектом. Конечно, на практике важнее то, как ведут себя наиболее важные браузеры, чем эзотерическое определение того, как что-то должно обрабатываться. Но полезно понять, почему новая строка («а»)! == «а» .
Пожалуйста, позвольте мне объяснить, как прочитать спецификацию, чтобы прояснить этот вопрос. Я вижу, что в этой очень старой теме ни у кого не было ответа на очень странный эффект. Так что, если вы можете прочитать спецификацию, это очень поможет вам в вашей профессии. Это приобретенный навык. Итак, продолжим.
Поиск в файле PDF для === приводит меня к странице 56 спецификации: 11.9.4. Оператор строгого равенства (===) , и после просмотра спецификации я нахожу:
11.9.6 Алгоритм
сравнения строгого равенства Сравнение x === y, где x и y - значения, дает истину или ложь . Такое сравнение выполняется следующим образом:
1. Если Type (x) отличается от Type (y), вернуть false .
2. Если Тип (x) не определен, верните true .
3. Если Тип (x) равен Null, вернуть true .
4. Если тип (x) не является числом, перейдите к шагу 11.
5. Если x равен NaN , верните false .
6. Если y равен NaN , вернуть false .
7. Если x совпадает с y, верните true .
8. Если x равен +0, а y равен −0, вернуть true .
9. Если x равен −0, а y равен +0, верните true .
10. Вернуть ложь .
11. Если Type (x) - String, тогда вернуть true, если x и y - это абсолютно одинаковая последовательность символов (одинаковая длина и одинаковые символы в соответствующих позициях); в противном случае верните false .
12. Если Type (x) - логическое значение, вернуть true, если x и y оба - true или оба false ; в противном случае верните false .
13. Верните истинуесли x и y ссылаются на один и тот же объект или если они ссылаются на объекты, соединенные друг с другом (см. 13.1.2). В противном случае верните false .
Интересным является шаг 11. Да, строки обрабатываются как типы значений. Но это не объясняет, почему новая String ("a")! == "a" . У нас есть браузер, не соответствующий ECMA-262?
Не так быстро!
Давайте проверим типы операндов. Попробуйте сами, обернув их в typeof () . Я обнаружил, что новая строка ("a") является объектом, и используется шаг 1: вернуть false, если типы отличаются.
Если вы удивляетесь, почему new String ("a") не возвращает строку, как насчет упражнения по чтению спецификации? Веселиться!
Aidiakapi написал это в комментарии ниже:
Из спецификации
11.2.2 Новый оператор :
Если Type (конструктор) не является Object, генерировать исключение TypeError.
Другими словами, если бы String не был типа Object, его нельзя было бы использовать с оператором new.
new всегда возвращает Object, даже для конструкторов String . И увы! Семантика значения для строк (см. Шаг 11) теряется.
И это, наконец, означает: новая строка («а»)! == «а» .
Автор: nalply Размещён: 28.11.2009 06:18101 плюса
В PHP и JavaScript это оператор строгого равенства. Это означает, что он будет сравнивать как тип, так и значения.
Автор: Shiki Размещён: 12.05.2010 12:5896 плюса
Я проверил это в Firefox с Firebug, используя такой код:
console.time("testEquality");
var n = 0;
while(true) {
n++;
if(n==100000)
break;
}
console.timeEnd("testEquality");
а также
console.time("testTypeEquality");
var n = 0;
while(true) {
n++;
if(n===100000)
break;
}
console.timeEnd("testTypeEquality");
Мои результаты (проверены пять раз каждый и усреднены):
==: 115.2
===: 114.4
Так что я бы сказал, что минимальная разница (это более 100000 итераций, помните) ничтожна. Производительность не повод для этого ===
. Напечатайте безопасность (ну, так же безопасно, как в JavaScript), и качество кода.
94 плюса
В JavaScript это означает то же значение и тип.
Например,
4 == "4" // will return true
но
4 === "4" // will return false
Автор: Dimitar
Размещён: 12.05.2010 12:58
84 плюса
=== Оператор называется строгим оператор сравнения, он действительно отличается от == оператора.
Давайте возьмем 2 переменные a и b.
Чтобы "a == b" было оценено как истинное, a и b должны быть одинаковыми .
В случае «a === b» a и b должны иметь одинаковое значение, а также один и тот же тип, чтобы оно имело значение true.
Возьмите следующий пример
var a = 1;
var b = "1";
if (a == b) //evaluates to true as a and b are both 1
{
alert("a == b");
}
if (a === b) //evaluates to false as a is not the same type as b
{
alert("a === b");
}
В итоге ; использование оператора == может дать значение true в ситуациях, когда вы этого не хотите, поэтому использование оператора === будет безопаснее.
В сценарии использования 90% не имеет значения, какой из них вы используете, но удобно знать разницу, когда вы однажды получите неожиданное поведение.
Автор: Reinstate Monica Размещён: 11.12.2008 02:5878 плюса
Он проверяет, равны ли одинаковые стороны по типу и значению .
Пример:
'1' === 1 // will return "false" because `string` is not a `number`
Типичный пример:
0 == '' // will be "true", but it's very common to want this check to be "false"
Еще один распространенный пример:
null == undefined // returns "true", but in most cases a distinction is necessary
Автор: vsync
Размещён: 12.05.2010 12:58
75 плюса
Почему ==
это так непредсказуемо?
Что вы получаете, когда сравниваете пустую строку ""
с нулевым числом 0
?
true
Да, это верно в соответствии с ==
пустой строкой и нулевым числом одновременно.
И это не заканчивается, вот еще один:
'0' == false // true
Вещи становятся действительно странными с массивами.
[1] == true // true
[] == false // true
[[]] == false // true
[0] == false // true
Тогда страннее со строками
[1,2,3] == '1,2,3' // true - REALLY?!
'\r\n\t' == 0 // true - Come on!
Становится хуже:
Когда равен не равен?
let A = '' // empty string
let B = 0 // zero
let C = '0' // zero string
A == B // true - ok...
B == C // true - so far so good...
A == C // **FALSE** - Plot twist!
Позвольте мне сказать это еще раз:
(A == B) && (B == C) // true
(A == C) // **FALSE**
И это просто сумасшедшие вещи, которые вы получаете с примитивами.
Это совершенно новый уровень безумия, когда вы используете ==
объекты.
На данный момент ваш, вероятно, интересно ...
Почему это происходит?
Что ж, это потому, что в отличие от «triple equals» ( ===
), который просто проверяет, совпадают ли два значения.
==
делает целую кучу других вещей .
Он имеет специальную обработку для функций, специальную обработку для нулей, неопределенных, строк, вы называете это.
Это довольно странно.
На самом деле, если вы попытаетесь написать функцию, которая делает то, что ==
делает, она будет выглядеть примерно так:
function isEqual(x, y) { // if `==` were a function
if(typeof y === typeof x) return y === x;
// treat null and undefined the same
var xIsNothing = (y === undefined) || (y === null);
var yIsNothing = (x === undefined) || (x === null);
if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);
if(typeof y === "function" || typeof x === "function") {
// if either value is a string
// convert the function into a string and compare
if(typeof x === "string") {
return x === y.toString();
} else if(typeof y === "string") {
return x.toString() === y;
}
return false;
}
if(typeof x === "object") x = toPrimitive(x);
if(typeof y === "object") y = toPrimitive(y);
if(typeof y === typeof x) return y === x;
// convert x and y into numbers if they are not already use the "+" trick
if(typeof x !== "number") x = +x;
if(typeof y !== "number") y = +y;
// actually the real `==` is even more complicated than this, especially in ES6
return x === y;
}
function toPrimitive(obj) {
var value = obj.valueOf();
if(obj !== value) return value;
return obj.toString();
}
Так что это значит?
Это означает, что ==
это сложно.
Поскольку это сложно, трудно понять, что произойдет, когда вы его используете.
Что означает, что вы можете получить ошибки.
Так что мораль этой истории ...
Сделай свою жизнь менее сложной.
Используйте ===
вместо ==
.
Конец.
Автор: Luis Perez Размещён: 09.08.2016 04:5068 плюса
Блок-схема выполнения Javascript для строгого равенства / Сравнение '==='
Блок-схема выполнения Javascript для нестрогого равенства / сравнения '=='
Автор: Samar Panda Размещён: 05.09.2015 01:5354 плюса
JavaScript ===
против ==
.
0==false // true
0===false // false, because they are of a different type
1=="1" // true, auto type coercion
1==="1" // false, because they are of a different type
Автор: user2496033
Размещён: 03.07.2013 04:08
53 плюса
Это означает равенство без приведения типов Приведение типов означает, что JavaScript не преобразует автоматически любые другие типы данных в строковые типы данных.
0==false // true,although they are different types
0===false // false,as they are different types
2=='2' //true,different types,one is string and another is integer but
javaScript convert 2 to string by using == operator
2==='2' //false because by using === operator ,javaScript do not convert
integer to string
2===2 //true because both have same value and same types
Автор: Pop Catalin
Размещён: 12.05.2010 12:59
48 плюса
В типичном скрипте не будет разницы в производительности. Более важным может быть тот факт, что тысяча "===" на 1 КБ тяжелее тысячи "==" :) Профилировщики JavaScript могут подсказать, есть ли разница в производительности в вашем случае.
Но лично я бы сделал то, что предлагает JSLint. Эта рекомендация существует не из-за проблем с производительностью, а из-за того, что приведение типов означает ('\t\r\n' == 0)
истинное значение.
44 плюса
Оператор сравнения == сбивает с толку и его следует избегать.
Если вы ДОЛЖНЫ жить с этим, то помните следующие 3 вещи:
- Это не транзитивно: (a == b) и (b == c) не приводит к (a == c)
- Он взаимоисключающий с отрицанием: (a == b) и (a! = B) всегда содержат противоположные логические значения со всеми a и b.
- В случае сомнений выучите наизусть следующую таблицу истинности:
РАВНАЯ ТАБЛИЦА РАВНЫХ ОПЕРАТОРОВ В JAVASCRIPT
- Каждая строка в таблице представляет собой набор из 3 взаимно «равных» значений, что означает, что любые 2 значения из них равны, используя знак равенства == *
** СТРАННЫЙ: обратите внимание, что любые два значения в первом столбце не равны в этом смысле. **
'' == 0 == false // Any two values among these 3 ones are equal with the == operator
'0' == 0 == false // Also a set of 3 equal values, note that only 0 and false are repeated
'\t' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\r' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\n' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
'\t\r\n' == 0 == false // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
null == undefined // These two "default" values are not-equal to any of the listed values above
NaN // NaN is not equal to any thing, even to itself.
Автор: CuongHuyTo
Размещён: 16.09.2011 02:25
38 плюса
Вряд ли будет какая-либо разница в производительности между двумя операциями при вашем использовании. Преобразование типов не требуется, поскольку оба параметра уже одного типа. Обе операции будут иметь сравнение типов с последующим сравнением значений.
Автор: Sean Размещён: 11.12.2008 02:4437 плюса
Да! Это имеет значение.
===
Оператор в javascript проверяет значение, а также тип, где ==
оператор as просто проверяет значение (выполняет преобразование типа, если требуется) .
Вы можете легко проверить это. Вставьте следующий код в файл HTML и откройте его в браузере
<script>
function onPageLoad()
{
var x = "5";
var y = 5;
alert(x === 5);
};
</script>
</head>
<body onload='onPageLoad();'>
Вы получите « ложь » в тревоге. Теперь измените onPageLoad()
метод, чтобы alert(x == 5);
вы получили истинное значение .
34 плюса
===
Оператор проверяет значения, а также типы переменных на равенство.
==
Оператор просто проверяет значение переменных на равенство.
32 плюса
Это строгий проверочный тест.
Это хорошо, особенно если вы проверяете между 0 и false и null.
Например, если у вас есть:
$a = 0;
Затем:
$a==0;
$a==NULL;
$a==false;
Все возвращает истину, и вы можете не хотеть этого. Предположим, у вас есть функция, которая может возвращать 0-й индекс массива или false при сбое. Если вы проверите «==» false, вы можете получить запутанный результат.
То же самое, что и выше, но строгий тест:
$a = 0;
$a===0; // returns true
$a===NULL; // returns false
$a===false; // returns false
Автор: Daniel
Размещён: 12.05.2010 01:19
31 плюса
JSLint иногда дает вам нереальные причины для изменения вещей. ===
имеет точно такую же производительность, как ==
если бы типы уже были одинаковыми.
Это быстрее, только когда типы не совпадают, и в этом случае он не пытается конвертировать типы, но напрямую возвращает false.
So, IMHO, JSLint maybe used to write new code, but useless over-optimizing should be avoided at all costs.
Meaning, there is no reason to change ==
to ===
in a check like if (a == 'test')
when you know it for a fact that a can only be a String.
Modifying a lot of code that way wastes developers' and reviewers' time and achieves nothing.
Автор: ashes Размещён: 05.06.2012 07:5330 плюса
Simply
==
means comparison between operands with type conversion
&
===
means comparison between operands without type conversion
Type conversion in javaScript means javaScript automatically convert any other data types to string data types.
For example:
123=='123' //will return true, because JS convert integer 123 to string '123'
//as we used '==' operator
123==='123' //will return false, because JS do not convert integer 123 to string
//'123' as we used '===' operator
Автор: Amit
Размещён: 20.03.2015 05:05
26 плюса
A simple example is
2 == '2' -> true, values are SAME because of type conversion.
2 === '2' -> false, values are NOT SAME because of no type conversion.
Автор: Vikas
Размещён: 14.05.2015 02:45
24 плюса
As a rule of thumb, I would generally use ===
instead of ==
(and !==
instead of !=
).
Reasons are explained in in the answers above and also Douglas Crockford is pretty clear about it (JavaScript: The Good Parts).
However there is one single exception:
== null
is an efficient way to check for 'is null or undefined':
if( value == null ){
// value is either null or undefined
}
For example jQuery 1.9.1 uses this pattern 43 times, and the JSHint syntax checker even provides the eqnull
relaxing option for this reason.
From the jQuery style guide:
Автор: mar10 Размещён: 27.04.2013 02:15Strict equality checks (===) should be used in favor of ==. The only exception is when checking for undefined and null by way of null.
// Check for both undefined and null values, for some important reason. undefOrNull == null;
24 плюса
The top 2 answers both mentioned == means equality and === means identity. Unfortunately, this statement is incorrect.
If both operands of == are objects, then they are compared to see if they are the same object. If both operands point to the same object, then the equal operator returns true. Otherwise, the two are not equal.
var a = [1, 2, 3];
var b = [1, 2, 3];
console.log(a == b) // false
console.log(a === b) // false
In the code above, both == and === get false because a and b are not the same objects.
That's to say: if both operands of == are objects, == behaves same as ===, which also means identity. The essential difference of this two operators is about type conversion. == has conversion before it checks equality, but === does not.
Автор: Harry He Размещён: 09.09.2013 08:3122 плюса
The problem is that you might easily get into trouble since JavaScript have a lot of implicit conversions meaning...
var x = 0;
var isTrue = x == null;
var isFalse = x === null;
Which pretty soon becomes a problem. The best sample of why implicit conversion is "evil" can be taken from this code in MFC / C++ which actually will compile due to an implicit conversion from CString to HANDLE which is a pointer typedef type...
CString x;
delete x;
Which obviously during runtime does very undefined things...
Google for implicit conversions in C++ and STL to get some of the arguments against it...
Автор: Thomas Hansen Размещён: 29.12.2008 11:5422 плюса
From the core javascript reference
Автор: Paul Butcher Размещён: 12.05.2010 12:59
===
Returnstrue
if the operands are strictly equal (see above) with no type conversion.
21 плюса
Equality comparison:
Operator ==
Returns true, when both operands are equal. The operands are converted to the same type before being compared.
>>> 1 == 1
true
>>> 1 == 2
false
>>> 1 == '1'
true
Equality and type comparison:
Operator ===
Возвращает true, если оба операнда равны и имеют одинаковый тип. Как правило, это лучше и безопаснее, если сравнивать таким образом, потому что нет никаких закулисных преобразований типов.
>>> 1 === '1'
false
>>> 1 === 1
true
Автор: user2601995
Размещён: 02.10.2013 09:54
19 плюса
* Операторы === против == *
1 == true => true
true == true => true
1 === true => false
true === true => true
Автор: Mr.G
Размещён: 19.03.2014 12:08
19 плюса
Вот удобная таблица сравнения, которая показывает, какие преобразования происходят, и различия между ==
и ===
.
В заключении говорится:
«Используйте три равных, если вы не полностью понимаете преобразования, которые имеют место для двух равных».
http://dorey.github.io/JavaScript-Equality-Table/
Автор: Christian Hagelid Размещён: 27.03.2014 12:18Вопросы из категории :
- javascript Как определить, какой из указанных шрифтов был использован на веб-странице?
- javascript Валидация клиентской стороны ASP.Net
- javascript Длина объекта JavaScript
- javascript Получение текста из выпадающего списка
- operators В чем разница между | и || или операторы?
- operators Что делает оператор запятой?
- operators Чем отличаются операторы сравнения PHP (== double equals) и тождества (=== triple equals)?
- operators Как получить десятичное значение при использовании оператора деления в Python?
- equality Comparing two collections for equality irrespective of the order of items in them
- equality Что такое «Лучшая практика» для сравнения двух экземпляров ссылочного типа?
- equality Есть ли разница между "==" и "есть"?
- equality-operator Какой оператор равенства (== vs ===) следует использовать в сравнениях JavaScript?
- equality-operator JavaScript - === vs == производительность операторов
- equality-operator Запрос относительно оператора равенства (совместимые операнды) в JAVA
- equality-operator Почему {} == false оценивается как false, а [] == false оценивается как true?
- identity-operator Почему идентичный оператор в php (===) не работает с объектами DateTimeImmutable?
- identity-operator id () против оператора `is`. Безопасно ли сравнивать идентификаторы? Означает ли один и тот же `id` один и тот же объект?