1

I recently started learning JavaScript and NodeJS. I'm not sure why I see varying results. I'd really appreciate if someone can explain the nuances that's causing varying output.

var stream = require('stream');
var EventEmitter = require('events').EventEmitter; //typeof == function

console.log(new stream().Stream() instanceof EventEmitter); // error
console.log(new stream().Stream instanceof EventEmitter); // false
console.log(stream.Stream instanceof EventEmitter); // false...

console.log(new stream.Stream() instanceof EventEmitter); // true
console.log(new stream.Stream instanceof EventEmitter); // true

1 Answer 1

1

I'll try to keep it concise, lots of these things have answers, but there is a lot here.

var EventEmitter = require('events').EventEmitter; //typeof == function

EventEmitter is something you typically use with new. E.g. new EventEmitter(). In older javascript you might do function Thing() { this.someprop = 2; } and then do var a = new Thing() and be able to access a.someprop. In ecmascript 6+ you get to use class sugar. Anyways. You can new up function implementations and get the this of the function. This "instance" should also have the .constructor property set to the EventEmitter function in your case, were you to new it up. It will also have .prototype set to EventEmitter.prototype

console.log(new stream().Stream() instanceof EventEmitter); // error

This is erroring because Stream is not a property on new stream(). and Stream is undefined. Accessing/invoking a property of undefined or null will always cause a runtime error.

console.log(new stream().Stream instanceof EventEmitter); // false

You should be doing new stream() instanceof events.EventEmitter. again, Stream is undefined and shouldn't be an instance of anything. Note that it is true that stream == stream.Stream; the export is a shortcut for Stream.

console.log(stream.Stream instanceof EventEmitter); // false...

The constructor itself is just a function, and a function is not an EventEmitter.

console.log(new stream.Stream() instanceof EventEmitter); // true

When you new a function, the "instance" returned has a prototype which is the function's prototype. That prototype can in turn have a prototype which is how prototypical inheritance works in javascript. When you access a method or property, JS walk walks the prototype chain looking for it. When you do instanceof, it just checks the levels of the prototype chain for a match. Basically, Stream has EventEmitter in its prototype chain somewhere. It's actually just a level above - stream.prototype.__proto__ in the repl will show you.

console.log(new stream.Stream instanceof EventEmitter); // true

stream === stream.Stream, and you don't have to use parenthesis when you use new.

Sign up to request clarification or add additional context in comments.

6 Comments

Hi, Lot of things make sense and are clear now. Dint realize stream === stream.Stream When I do an import, the resulting stream function has multiple functions inside it like - Readable, Transform etcc... On a side note, are these functions static in nature ?
depends on which static you're referring to (C / Java) but the answer is static within their scope. At the top level of a file the answer is yes, and the prototype can be thought of as a static function, so if you call new 10 times the prototype is the same thing for all of them. NOTE within functions variables are always re-declared if the function is re-called. Unlike C.
Yeah...stream here is a circular reference. When I define a function, for example - var test = function() { function rr() { console.log("rr"); } this.msg = "test"; }, I cannot access the functions and variables inside it unless I initiate it. I know they are scoped. So, wondering how can functions (like readable, transform, etc..) inside 'stream' be accessible without initiating 'stream' object. For example - stream.Readable (which returns a function) vs test.rr (which returns undefined).
People define them on stream.prototype. So instead of doing this.msg = 'test', you do rr.prototype.msg = 'test'. You do the prototype assignments outside of the rr scope. function T() {}; T.prototype.msg = 'test'. Then new T().msg is 'test'
Got you. Thanks a lot catalyst. Trying to understand nuances of JavaScript.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.