1

I opened up node repl and typed in

process.__proto__ === process.constructor.prototype

and I was surprised that the answer is

false

this perplexes me quite a bit. Isn't that o.__proto__ was defined to be its constructors prototype?

xzhu
  • 5,675
  • 4
  • 32
  • 52
  • 1
    The `constructor` property can be set to any value, so this equality is really only guaranteed if you control the code. – Felix Kling Dec 04 '14 at 03:34
  • @Felix Kling: But if that's the case, I believe in V8 engine you will see the output of `Object.keys(process)` to have `"constructor"`, however that's not the case. – xzhu Dec 04 '14 at 03:37
  • Nothing prevents you from creating a non-enumerable property. However, I didn't necessarily mean that it was changed *explicitly*. Here is another example: `function Parent() {}; function Child(); Child.prototype = Object.create(Parent.prototype); var child = new Child();`. Here the condition would also be `false` because `child.constructor` points to `Parent`, not `Child`. – Felix Kling Dec 04 '14 at 03:40
  • 1
    Whether that boolean comparison would be true or not depends entirely upon how the object was created and whether it was purposely set to have a constructor property that will make your test `true`. For custom objects, the language does not make that statement true for you automatically, specific code must do the right thing to make that `true`. – jfriend00 Dec 04 '14 at 03:47

1 Answers1

1

TL;DR: Because it has been tampered with.

How process is constructed is not immediately clear from the source code as it is a host object, but let's trace it down:

  1. When an Environment is created, it creates a process object. This C++ code creates a V8::Object equivalent to the JS

    var process = new function process() { };
    

    Yes, we should not do that. But anyway, this is how it was done, and this function is what you get when you log process.constructor: the function process() { [native code] }. Oh, and Object.getPrototypeOf(new process.constructor) == process.constructor.prototype holds as expected.

    Then, it places the object in the environment and SetupProcessObject is called on the environment, which sets up all the methods and properties on the process object that you know from the docs.

  2. When Node loads the environment, it will read and eval the node.js file to get the function that is defined in it. Then it will take the environment's process object and call the obtained function with it as an argument.

  3. That function defined in node.js now does lots of bootstrapping, such as setting the global global variable to the global object. It also calls the startup function, which is defined as follows:

    var EventEmitter = NativeModule.require('events').EventEmitter;
    process.__proto__ = Object.create(EventEmitter.prototype, {
        constructor: {
            value: process.constructor
        }
    });
    EventEmitter.call(process);
    …
    

    There you have it. This snippet replaces the __proto__ of process with a new prototype object that is inheriting from EventEmitter.prototype, but retains the original value of the constructor property. process does no more inherit from process.constructor.prototype, which points to the "old" prototype object.

    I can't explain why they do this :-) Maybe a better approach would have been to simply do

    process.__proto__.__proto__ = EventEmitter.prototype;
    
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375