Nodejs闭包variables没有在模块中更新

我需要一些帮助来理解NodeJs。 我显然缺less一些根本性的东西。 我有一个类似于以下的模块,使用基本的揭示模块模式…

var someArray = []; var publicApi = { someArray: someArray, someFunction: someFunction }; function someFunction() { someArray = ['blue', 'green']; } module.exports = publicApi; 

当我使用这个模块时,当我调用一些函数时someArray不会被改变…

 var myModule = require('myModule'); myModule.someFunction(); var test = myModule.someArray; // test is always an empty array 

请帮我理解为什么。 我意识到我可以使用构造函数来获得这个工作,但是我想填补我为什么上述不起作用的知识。

更新:

我可以得到这个与模块的以下修改工作…

 var theModule = { someArray: [], someFunction: someFunction }; function someFunction() { theModule.someArray = ['blue', 'green']; } module.exports = theModule; 

但我仍然想明白为什么第一个模块中的代码不起作用。 我正在使用的模块作为单例很好,所以我很乐意看到模块中的variables可以被该模块中的函数改变的最佳做法,并且可以在该模块之外公开访问。

你做的第一种方式不起作用的原因是与没有Node的JavaScript相同的原因:

 var someArray = []; var object = { someArray: someArray, } someArray = [1, 2, 3]; console.log(object.someArray); 

这将打印[]因为object.someArray是对您创build的第一个数组的引用。 这是一个过程:

 var someArray = []; 

创build一个空数组,然后将该数组的引用保存为someArray名称。 我们来调用这个array1

 var object = { someArray: someArray } 

使用属性someArray创build一个对象,使该属性引用someArray引用的数组。 知道这一点很重要,这意味着这个引用现在是对array1的引用,而不是someArray 。 这导致我们:

 someArray = [1, 2, 3]; 

其中创build一个新的数组(我们称之为array2 ),然后它存储为someArray 。 这个数组完全独立于array1 ,所有将来someArray引用都会得到array2 ,但是它对以前的访问没有任何影响。

这和Node的例子完全一样 – 当你覆盖someArray而不是publicApi.someArray ,你不会改变publicApi.someArray ,所以你不能指望它是不同的。

希望能够清楚地说明,你可以从以下方面着手:

 someArray -> array1[] object.someArray -> array1[] 

对此:

 someArray -> array2[1, 2, 3] object.someArray -> array1[] 

请注意object.someArray没有改变。

你在想这个,好像是一个对象而不是封闭的。 当一个函数访问特权数据时,会产生一个闭包。 也就是说,数据绑定从程序的其余部分“消失”。 这是一个例子:

 function SomeFunction(x) { var closureVar = x; toReturn = function(y) { var answer = closureVar; closureVar = y; return answer; } return toReturn; } var runIt = SomeFunction(15); 

会发生什么情况是,当调用SomeFunction时,它会为“closureVar”创build一个本地绑定。 当函数退出时,其所有本地绑定(通常)都会消失。 但是,在这种情况下,返回的函数包含对'closureVar'的引用,所以它不能被完全删除。 因此,定义为“toReturn”的函数仍然可以使用它。

但是,程序中没有其他任何东西可以实现。 如果再次调用SomeFunction(),它将为closureVar创build一个新的(本地)绑定,这个绑定将被由SomeFunction()调用给定的toReturn函数使用。 每次调用SomeFunction()都会导致新的closures。

FWIW,它确实工作,如果你这样做:

 function someFunction() { //someArray = ['blue', 'green']; someArray[0] = 'blue' someArray[1] = 'green' } 

我认为这意味着当你用[]创build一个新的数组时,你以某种方式打破了参考链。 我的理解还不够好。

在模块中访问variables的最佳做法可能是定义get / set方法:

 var someArray = []; var publicApi = { getSomeArray: function () { return someArray; }, setSomeArray: function (s) { someArray = s; }, /* * Or if you know you can support get/set syntax: * * get someArray () { return someArray; } * set someArray (s) { someArray = s; } */ someFunction: someFunction }; function someFunction() { someArray = ['blue', 'green']; } module.exports = publicApi; 

在MDN上获取和设置语法定义。

但是,如果您希望直接访问对象本身,请使用您提到的模块名称空间:

 theModule.someArray = ['blue', 'green']; 

但是你所看到的问题是因为你用一个新的数组来replace而不是修改数组,例如

 function someFunction() { someArray.splice(0); someArray.push('blue', 'green'); } 

我相信赋值会导致创build一个新的对象引用,而修改现有的对象将维护现有的引用。

这是共享呼叫的结果:
JavaScript是传递引​​用还是传值语言?
https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing