Man*_*ner 18 javascript node.js ecmascript-6
在此代码段中,语句f instanceof PipeWritable返回true(Node v8.4.0):
const stream = require('stream');
const fs = require('fs');
class PipeWritable extends stream.Writable {
constructor () {
super();
}
}
const s = new PipeWritable();
const f = fs.createWriteStream('/tmp/test');
console.log(f instanceof PipeWritable); // true ... ???
Run Code Online (Sandbox Code Playgroud)
对象s:
Object.getPrototypeOf(s) 是 PipeWritable {} s.constructor 是 [Function: PipeWritable]PipeWritable.prototype 是 PipeWritable {}对象f:
Object.getPrototypeOf(f) 是 WriteStream { ... } f.constructor 是 [Function: WriteStream] ... stream.WriteStream.prototype 是 Writable { ... }原型链:
Object f Object s
--------------------- --------------------
Writable PipeWritable
Stream Writable
EventEmitter Stream
Object EventEmitter
Object
Run Code Online (Sandbox Code Playgroud)
遵循instanceof的定义:
instanceof运算符测试其原型链中的对象是否具有构造函数的prototype属性.
我希望如此(f instanceof PipeWritable) === false,因为PipeWritable不在原型链中f(上面的链通过调用来验证Object.getPrototypeOf(...)).
但它返回true,因此我的分析中出现了问题.
什么是正确的答案?
Li3*_*357 15
这是由于Node.js源代码中的某些代码所在_stream_writable.js:
var realHasInstance;
if (typeof Symbol === 'function' && Symbol.hasInstance) {
realHasInstance = Function.prototype[Symbol.hasInstance];
Object.defineProperty(Writable, Symbol.hasInstance, {
value: function(object) {
if (realHasInstance.call(this, object))
return true;
return object && object._writableState instanceof WritableState;
}
});
} else {
realHasInstance = function(object) {
return object instanceof this;
};
}
Run Code Online (Sandbox Code Playgroud)
根据语言规范,instanceof运算符使用众所周知的符号@@hasInstance来检查对象O是否是构造函数C的实例:
12.9.4运行时语义:InstanceofOperator(O,C)
抽象操作InstanceofOperator(O,C)实现了通用算法,用于确定对象O是否继承自构造函数C定义的继承路径.此抽象操作执行以下步骤:
- 如果Type(C)不是Object,则抛出TypeError异常.
- 让instOfHandler成为GetMethod(C,@@ hasInstance).
- ReturnIfAbrupt(instOfHandler).
- 如果instOfHandler没有未定义,那么
一个.返回ToBoolean(调用(instOfHandler,C,«O»)).- 如果IsCallable(C)为false,则抛出TypeError异常.
- 返回OrdinaryHasInstance(C,O).
现在让我逐节为您分解上面的代码:
var realHasInstance;
if (typeof Symbol === 'function' && Symbol.hasInstance) {
…
} else {
…
}
Run Code Online (Sandbox Code Playgroud)
上面的代码段定义realHasInstance,检查是否Symbol已定义以及是否hasInstance存在已知符号.在你的情况下,它确实如此,所以我们将忽略else分支.下一个:
realHasInstance = Function.prototype[Symbol.hasInstance];
Run Code Online (Sandbox Code Playgroud)
在这里,realHasInstance分配给Function.prototype[@@hasInstance]:
19.2.3.6 Function.prototype [@@ hasInstance](V)
当使用值V调用对象F的@@ hasInstance方法时,将执行以下步骤:
- 让˚F是这个值.
- 返回OrdinaryHasInstance(F,V).
只需调用OrdinaryHasInstance 的@@hasInstance方法Function.下一个:
Object.defineProperty(Writable, Symbol.hasInstance, {
value: function(object) {
if (realHasInstance.call(this, object))
return true;
return object && object._writableState instanceof WritableState;
}
});
Run Code Online (Sandbox Code Playgroud)
这在Writable构造函数上定义了一个新属性,即众所周知的符号hasInstance- 基本上实现了自己的自定义版本hasInstance.值hasInstance是一个函数,它接受一个参数instanceof,在这种情况下,正在测试的对象f.
下一行if语句检查是否realHasInstance.call(this, object)真实.前面提到过,realHasInstance分配给Function.prototype[@@hasInstance]它实际调用内部操作OrdinaryHasInstance(C,O).通过查找原型链中的构造函数,OPERaryHasInstance操作只是检查O是否是您和MDN所描述的C的实例.
在这种情况下,Writable f不是Writable(PipeWritable)的子类的实例,因此realHasInstance.call(this, object)是false.由于这是错误的,它会转到下一行:
return object && object._writableState instanceof WritableState;
Run Code Online (Sandbox Code Playgroud)
因为object,或者f在这种情况下,是真实的,并且因为f是具有_writableState属性的Writable WritableState,f instanceof PipeWritable是真实的.
这个实现的原因在于评论:
// Test _writableState for inheritance to account for Duplex streams,
// whose prototype chain only points to Readable.
Run Code Online (Sandbox Code Playgroud)
因为Duplex流在技术上是可写的,但它们的原型链只指向Readable,所以额外检查是否_writableState是一个WritableState允许duplexInstance instanceof Writable为true 的实例.这有你发现的副作用 - Writable是'子类的一个实例'.这是一个错误,应该报告.
这实际上甚至在文档中报告:
注:
stream.Duplex类prototypically从继承stream.Readable和寄生从stream.Writable,但instanceof可以正常工作了,由于覆盖两基类Symbol.hasInstance上stream.Writable.
如此处所示,从Writable继承parasitcally会产生后果.
我在GitHub上提交了一个问题,看起来它将被修复.正如Bergi所提到的,添加一个检查以查看是否this === Writable确保在使用时只有Duplex流是Writable的实例instanceof.有拉动请求.
| 归档时间: |
|
| 查看次数: |
515 次 |
| 最近记录: |