-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to inherit from new Buffer implementation #2882
Comments
ES6
|
Thanks @bnoordhuis , I know it can be seen as going backward, but is there a way in ES5 too? |
I think that's going to be less easy for the same reason that it's difficult to inherit from Array or Uint8Array in ES5. You can maybe hack something together through the |
Try something like this: function Ogg() {
const ui = new Uint8Array(size);
Object.setPrototypeOf(ui, Ogg.prototype);
return ui;
}
Ogg.prototype.__proto__ = Buffer.prototype;
Ogg.__proto__ = Buffer; Yeah, ugly as sin. |
This should probably go into the buffer docs. |
Thanks a lot for your answers, @trevnorris : function ogg_packet (buffer) {
if (!Buffer.isBuffer(buffer)) {
buffer = new Uint8Array(binding.sizeof_ogg_packet);
}
if (buffer.length != binding.sizeof_ogg_packet) {
throw new Error('"buffer.length" = ' + buffer.length + ', expected ' + binding.sizeof_ogg_packet);
}
Object.setPrototypeOf(buffer, ogg_packet.prototype);
console.log('BUFFER', buffer.toString());
return buffer;
}
ogg_packet.prototype.__proto__ = Buffer.prototype;
ogg_packet.__proto__ = Buffer; However, it seems that I can't use Buffer methods (at least toString()) since there is a strict equality check of the instance. For example, trying to print buffer.toString() in the constructor function give me that error:
|
@corentingurtner That would be from the /cc @domenic Know of a way to do this proto transversal check in C++? If there's not a quick fix then let's open a new issue for this. |
@trevnorris you can use v8::Object::GetPrototype(). Something like |
What you really want though is to check that the appropriate internal data is set on the object. Which I think just would be |
@domenic ah yup. sure enough. when I had to reimplement the check I was focused on not allowing users to bypass the I agree that the check should be simplified down to checking internal data. All methods will work from that point regardless of whether it's actually a Buffer instance. I'll make a PR. |
+1 This stops me from migrating to 4.x. |
@bnoordhuis using classes won't work: 'use strict';
class Foo extends Buffer {
constructor(n) { super(n); }
foo() {
let cntr = 0;
for (let i = 0; i < this.length; i++) {
cntr += this[i];
}
return cntr;
}
}
let foo = new Foo(17).fill('abc');
console.log(foo.foo()); // TypeError: foo.foo is not a function We are overwriting the prototype in the Buffer constructor, and loosing all the child's class methods. Want to examine this a bit more. |
This is fixable once new.target ships in V8. You'd use new.target.prototype instead of Buffer.prototype. |
We'll be able to fix this with
|
This still requires that |
@domenic The inconsistency must come from from mixing ES5 and ES6 style inheritance together. Take this example: class B extends Uint8Array { constructor() { super(0); } }
class C extends B { constructor() { super(); } }
let c = new C();
console.log(c.constructor == C);
console.log(c.__proto__ == C.prototype);
console.log(c.__proto__.__proto__ == B.prototype);
console.log(c.__proto__.__proto__.__proto__ == Uint8Array.prototype); But now doing the same thing with Buffer: class C extends Buffer { constructor() { super(0); } }
let c = new C();
console.log(c.constructor == Buffer);
console.log(c.__proto__ == Buffer.prototype);
console.log(c.__proto__.__proto__ == Uint8Array.prototype); As you can see it completely dropped anything related to What I'm missing is what |
@trevnorris right now To fix this, you need to pass Then the returned object will have the correct prototype. In this case it would be |
Native Buffer method calls do not require anything from the prototype. So it is unnecessary to check if the Object's prototype is equal to Buffer.prototype. This fixes an issue that prevents Buffer from being inherited the ES5 way. Now the following will work: function A(n) { const b = new Buffer(n); Object.setPrototypeOf(b, A.prototype); return b; } Object.setPrototypeOf(A.prototype, Buffer.prototype); Object.setPrototypeOf(A, Buffer); console.log(new A(4)); Fix: nodejs#2882
Native Buffer method calls do not require anything from the prototype. So it is unnecessary to check if the Object's prototype is equal to Buffer.prototype. This fixes an issue that prevents Buffer from being inherited the ES5 way. Now the following will work: function A(n) { const b = new Buffer(n); Object.setPrototypeOf(b, A.prototype); return b; } Object.setPrototypeOf(A.prototype, Buffer.prototype); Object.setPrototypeOf(A, Buffer); console.log(new A(4)); Fix: #2882 PR-URL: #3080 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Hi,
I would like to know how a class could inherit from the new Buffer implementation.
I'm trying to upgrade the node-ogg module for node v4 and nan v2.
(Here is my work so far)
I tried this classic inheritance model:
But I get this error when trying to access this.length :
Thanks
Note: I also asked the question on SO:
http://stackoverflow.com/questions/32555714
The text was updated successfully, but these errors were encountered: