我是Node.js的新手.没有缓冲区比较,我应该使用像buffertools这样的模块 来实现这些功能.
但是当我在纯Node中比较Buffer对象时,我看到了一种非常奇怪的行为.
> var b1 = new Buffer([170]);
> var b2 = new Buffer([171]);
> b1
<Buffer aa>
> b2
<Buffer ab>
> b1 < b2
false
> b1 > b2
false
> b1 == b2
false
Run Code Online (Sandbox Code Playgroud)
和
> var b1 = new Buffer([10]);
> var b2 = new Buffer([14]);
> b1
<Buffer 0a>
> b2
<Buffer 0e>
> b1 > b2
false
> b1 < b2
true
> b1 == b2
false
Run Code Online (Sandbox Code Playgroud)
引擎盖下究竟发生了什么?
Zir*_*rak 40
这就是比较运算符在对象上的工作方式:
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
Run Code Online (Sandbox Code Playgroud)
(有点)
这是最简单的部分.抽象相等(==,spec)和严格相等(===,spec)都检查你是否引用了同一个对象(比较引用的类型).在这种情况下,它们显然不是,所以他们回答的是false(==规范步骤10,===规范步骤7).
因此,在这两种情况下:
b1 == b2 //false
b1 === b2 //false
Run Code Online (Sandbox Code Playgroud)
这是有趣的部分.我们来看看如何定义关系运算符(<和>).让我们在两种情况下跟随调用链.
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's toString method. If it's defined, call it.
Run Code Online (Sandbox Code Playgroud)
在这里,我们达到了高潮:什么是缓冲区的toString方法?答案位于node.js内部深处.如果你愿意,请拥有它.我们可以通过实验找到琐碎的东西:
> b1.toString()
'?'
> b2.toString()
'?'
Run Code Online (Sandbox Code Playgroud)
好吧,那没用.你会注意到在抽象关系比较算法(这是一个很棒的名字<)中,有一个处理字符串的步骤.它只是将它们转换为它们的数值 - 字符代码.我们这样做:
> b1.toString().charCodeAt(0)
65533
> b2.toString().charCodeAt(0)
65533
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
就是这样.
好吧,这一定令人困惑,因为我的解释工作还没有经过深思熟虑.回顾一下,这是发生了什么:
你创建了一个缓冲区.Benjamin Gruenbaum通过以下方式帮助我重建您的测试用例:
var b1 = new Buffer([170]), b2 = new Buffer([171]);
输出到控制台时,值将变为十六进制等效值(请参阅Buffer#inspect):
170..toString(16) === 'aa'
171..toString(16) === 'ab'
但是,在内部,它们代表无效字符(因为它不是十六进制编码;再次,你可以自由地深入研究实现细节,我不会(讽刺的是)).因此,转换为字符串时,它们用Unicode替换字符表示.
由于它们是不同的对象,因此任何相等运算符都将返回false.
但是,由于工作方式不及大于工作,因此将它们转换为字符串(然后转换为数字)进行比较.根据第3点,这是相同的值; 因此,它们不能小于或大于彼此,导致false.
最后,只是为了笑容:
b1 <= b2 //true
b1 >= b2 //true
Run Code Online (Sandbox Code Playgroud)
已经有一个已经接受的答案,但我想我可能仍然会发表评论,因为我没有发现接受的答案特别明确或有帮助.如果只是因为它回答OP没有提出的问题,那甚至是不正确的.所以让我们把它煮沸:
> var b1 = new Buffer([170]);
> var b2 = new Buffer([171]);
> b1 < b2
> b1 > b2
> b1 == b2
Run Code Online (Sandbox Code Playgroud)
所要求的只是:"我如何在缓冲区上执行等效并且小于/大于比较(也称为(总)排序)".
答案是:
要么通过逐步执行两个缓冲区的所有字节来手动执行,并执行相应字节之间的比较,例如b1[ idx ] === b2[ idx ],
或用Buffer.compare( b1, b2 )它给你的一个-1,0或者+1,这取决于第一缓冲器将排序之前,酷似,或之后的第二(排序列表d包含缓冲区是那么容易,因为d.sort( Buffer.compare )).
观察我===在我的第一个例子中使用; 我经常在本网站上发表有关==JavaScript 滥用的评论应该非常清楚为什么会这样.
| 归档时间: |
|
| 查看次数: |
8241 次 |
| 最近记录: |