Ответ 1
То, как операторы сравнения работают с объектами:
var a = {}, b = {};
a === b; //false
a == b; //false
a > b; //false
a < b; //false
var c = { valueOf : function () { return 0; } };
var d = { valueOf : function () { return 1; } };
c === d; //false
c == d; //false
c > d; //false
c < d; //true
Под капотом
(вид)
Часть 1: Равенство
Это самая легкая часть. И абстрактное равенство (==
, spec) и строгое равенство (===
, spec) проверьте, ссылаетесь ли вы на один и тот же объект (сравнительный пример сравнения). В этом случае они, очевидно, нет, поэтому они отвечают на false
(==
spec step 10, ===
spec step 7).
Поэтому в обоих случаях:
b1 == b2 //false
b1 === b2 //false
Часть 2: сравнение ударяет
Вот интересная часть. Давайте посмотрим, как определяются реляционные операторы (<
и >
) . Пусть в двух случаях следуют цепочке вызовов.
x = b1 //<Buffer aa>
y = b2 //<Buffer ab>
//11.8.5 The Abstract Relational Comparison Algorithm (http://es5.github.com/#x11.8.5)
Let px be the result of calling ToPrimitive(x, hint Number).
Let py be the result of calling ToPrimitive(y, hint Number).
//9.1 ToPrimitive (http://es5.github.com/#x9.1)
InputType is Object, therefore we call the internal [[DefaultValue]] method with hint Number.
//8.12.8 [[DefaultValue]] (hint) http://es5.github.com/#x8.12.8
We try and fetch the object toString method. If it defined, call it.
И вот мы достигли кульминации: какой метод буфера toString
? Ответ лежит внутри внутренней части node.js. Если вы хотите, у вас есть. То, что мы можем найти тривиально, - это эксперимент:
> b1.toString()
'�'
> b2.toString()
'�'
ладно, это не помогло. Вы заметите, что в Алгоритме абстрактного реляционного сравнения (какое большое причудливое имя для <
) есть шаг для работы со строками. Он просто преобразует их в их числовое значение - коды char. Позвольте сделать это:
> b1.toString().charCodeAt(0)
65533
> b2.toString().charCodeAt(0)
65533
65533 - важное число. Это сумма двух квадратов: 142^2 + 213^2
. Это также является символом замены Unicode, символом, означающим "я не знаю, что случилось". Вот почему его шестнадцатеричный эквивалент FFFD.
Очевидно, 65533 === 65533
, поэтому:
b1 < b2 //is
b1.toString().charCodeAt(0) < b2.toString().charCodeAt(0) //is
65533 < 65533 //false
b1 > b2 //following same logic as above, false
И что это.
Чувак, какого черта?
Хорошо, это, должно быть, сбивало с толку, так как мои усилия по разъяснению не были продуманы. Напомним, вот что произошло:
-
Вы создали буфер. Бенджамин Груэнбаум помог мне воссоздать ваш тестовый пример, сделав:
var b1 = new Buffer([170]), b2 = new Buffer([171]);
-
При выводе на консоль значения преобразуются в их шестнадцатеричный эквивалент (см. Проверка буфера #:
170..toString(16) === 'aa'
171..toString(16) === 'ab'
-
Однако внутренне они представляли недопустимые символы (поскольку это не шестнадцатеричное кодирование, опять же, вы можете вникать в реализацию nitty gritty, я не буду (о иронии)). Поэтому при преобразовании в строку они были представлены символом замены Unicode.
-
Так как они разные объекты, любой оператор равенства вернет
false
. -
Однако из-за того, что работа была меньше, чем больше, чем больше, они были превращены в строки (а затем и цифры) для сравнения. В свете пункта № 3 это то же значение; поэтому они не могут быть меньше или больше друг друга, что приводит к
false
.
Наконец, просто чтобы улыбнуться на лице:
b1 <= b2 //true
b1 >= b2 //true