Is it possible to get a different scope for a requ

2019-02-20 06:49发布

问题:

Assume I have this example file called import.js

var self;
function Test(a,b){
   this.a = a;
   this.b = b;
   self = this;
}
Test.prototype.run = function(){
   console.log(self.a, self.b)
}
module.exports = Test

When I require the file and create one new 'object' everything works perfectly, but when I create a 2nd object, they both have access to self, only the latter one works.

var Test = require('./import.js');

var one = new Test(1,2);
one.run()
1 2

var two = new Test(3,4);
two.run()
3 4
one.run()
3 4

Is there a way to re-require the file such that it creates separate scopes?

Putting it as two different variables doesn't work,

var Test1 = require('./import')
var Test2 = require('./import')
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run()
3 4

But duplicating the file does exactly what I am looking for..

var Test1 = require('./import1');
var Test2 = require('./import2');
var one = new Test1(1,2);
var two = new Test2(3,4);
one.run();
1 2

Yes re-writing self into this would work but, But is this possible without modifying the import.js file, or duplicating it?

回答1:

In short, it is not possible to do this without modifying import.js file or duplicating the file. This is because self is a global variable for that document, which will be the same for every instance of the function object.

Alternative #1

The problem is that you assign self to a global variable. Both of these have access to the same variable and therefore you get the observed results. Also, your use of self is unneccessary. The code below works as you described.

function Test(a,b){
   this.a = a;
   this.b = b;
}
Test.prototype.run = function(){
   // Simply using 'this' to access the properties of the function is sufficient - no need for self
   console.log(this.a, this.b)
}
module.exports = Test

Working example

In this case with each new Test() instance you will have a separate instance, so you will not need to 're-require' the files.

Alternative #2

If you want to keep self as per your edit, another option would be to just rewrite the function you want to call. For example:

var Test = require('./import.js');

Test.prototype.run = function(){
   console.log(this.a, this.b)
}

If this is also not an option, then you need to provide more information as to what you can or cannot do.



回答2:

Answering my own question here, but there are at least two ways this is possible....

(1) Deleting Cache

How to remove module after "require" in node.js?

var Test1 = require('./import.js');
delete require.cache[require.resolve('./import.js')]
var Test2 = require('./import.js');

var one = new Test1(1,2);
var two = new Test2(3,4);

one.run()
1 2
two.run()
3 4

Doesn't even look that messy, although it's grossly inefficient and would get costly very fast to write code this way...


(2) Using function Scope

Because require reads the file and then runs it,

var Test = require('./test.js');

is equivelent to

var Test = eval( fs.readFileSync('./test.js', 'utf8') );

So, if instead of using require, you read the file you can establish new scopes inside of functions:

var fs = require('fs');
var File = fs.readFileSync('./import.js', 'utf8');
var Test1, Test2;
(function(){ Test1 = eval(File); })();
(function(){ Test2 = eval(File); })(); 

The self inside the file would now be stored inside the function scope you created. so once again:

var one = new Test1(1,2);
var two = new Test2(3,4);

one.run()
1 2
two.run()
3 4

Slightly messier, but far faster then deleting the cache and re-reading the file every time.