Where are vars stored in Nodejs?

2019-02-10 07:48发布

问题:

In any web browser executing the following script will result in 'wee' being sent to the console. In Node it sends {}.

var d = 'wee';
console.log(this.d);

I realize that in Node this refers to the exports object in this case. I do know about the global variable, and that isn't what I'm trying to access. Besides, the script above does not set d on the global object either. Where the hell does it go? I can access it explicitly by console.log(d); in the script above but it appears to be stashed away in some nonstandard space for no good reason at all.

I also realize that removing the var will declare d on the global object, which is the expected behavior although it seems stupid to have var at the top level scope storing its values in a different place than "naked" variables. I mean, isn't the point of the module system supposed to be some sort of digital prophylactic to guard against global pollution? Here it seems so easy to break the pattern and so difficult to do something standard.

d is not declared on the module object either.

I don't have to justify why I'm asking this question but I'll answer the first troll to come along with a "but why do you want to do taht hurr durrrr".

var d = {};
d.bleep = 'y';
var a = Object.keys(d);

d.bloop = 'y';
d.blop = 'y';

var b = Object.keys(d);

// c = b - a;
var c = b.filter(function (item) {
    if(a.indexOf(item) === -1) {
        return true;
    }
    return false;
});

console.log(a,b,c);

In the same way that I can differentiate between certain object states of d, I should be able to differentiate the states of the top level scope. In a browser this is the window object, referred to by this in the top level scope. I should be able to asses the properties of the environment before and after script execution to determine a great many things, one of which would be inspection of functions and variables declared in the top scope of an arbitrary script that they may then be applied to the exports object. This would make it easy to programatically generate module wrappers for scripts which were not written as modules with a simple forEach applied to the list of top level functions and variables to assign whateverThisIs['varFunc'] to module.exports['varFunc']...

and stuff...

This behavior appears to be like that of an anonymous function. In an anonymous function this could refer to the window object, vars would have to be called directly ( as they're in the anon func's scope ) and, leaked vars declared without the var keyword could end up at the window object. I haven't yet read the entire manual, maybe this is exactly what is going on but, I was under the impression that each module executed in it's own context (window) and that Node passed messages between module contexts through the use of global and module.exports...

I don't know. I want to know though. If you know, let me know.

回答1:

So every node module is wrapped as the body of a function as shown here in the node source code

NativeModule.wrapper = [
  '(function (exports, require, module, __filename, __dirname) { ',
  '\n});'
];

So if you declare a variable with var, it is function-local to the module, basically a private variable for that module. It is not a property of global, module, module.exports, or this. If you forget var, it goes into the global object as a property. If you explicitly create a property on this, that goes into exports and is available to other modules.

Here's a little program that is hopefully enlightening.

var aDeclaredVar = '*aDeclaredVar*';
undeclaredVar = '*undeclaredVar*';
this.aThisProperty = '*aThisProperty*';
module.aModuleProperty = '*aModuleProperty*';
module.exports.anExportProperty = '*anExportProperty*';

console.log('this', this);
console.log('this === exports', this === exports);
console.log('this === module', this === module);
console.log('this === module.exports', this === module.exports);
console.log('aDeclaredVar', aDeclaredVar);
console.log('undeclaredVar', undeclaredVar);
console.log('this.aThisProperty', this.aThisProperty);
console.log('module.aModuleProperty', module.aModuleProperty);
console.log('module.exports.anExportProperty', module.exports.anExportProperty);
console.log('global.undeclaredVar', global.undeclaredVar);
console.log('global.aDeclaredVar', global.aDeclaredVar);

And it's output:

this { aThisProperty: '*aThisProperty*',
  anExportProperty: '*anExportProperty*' }
this === exports true
this === module false
this === module.exports true
aDeclaredVar *aDeclaredVar*
undeclaredVar *undeclaredVar*
this.aThisProperty *aThisProperty*
module.aModuleProperty *aModuleProperty*
module.exports.anExportProperty *anExportProperty*
global.undeclaredVar *undeclaredVar*
global.aDeclaredVar undefined