Javascript 模块中未更新Nodejs闭包变量
我需要一些帮助来理解NodeJs。我显然错过了一些基本的东西。我有一个类似于下面的模块,使用一个基本的模块模式Javascript 模块中未更新Nodejs闭包变量,javascript,node.js,closures,Javascript,Node.js,Closures,我需要一些帮助来理解NodeJs。我显然错过了一些基本的东西。我有一个类似于下面的模块,使用一个基本的模块模式 var someArray = []; var publicApi = { someArray: someArray, someFunction: someFunction }; function someFunction() { someArray = ['blue', 'green']; } module.exports = publicApi; 当
var someArray = [];
var publicApi = {
someArray: someArray,
someFunction: someFunction
};
function someFunction() {
someArray = ['blue', 'green'];
}
module.exports = publicApi;
当我使用这个模块时,当我调用someFunction时,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;
但是我仍然想确切地理解为什么第一个模块中的代码不起作用。我正在处理的模块作为一个单独的模块是很好的,因此我想看看在模块中设置变量的最佳实践是什么,这些变量可以由该模块中的函数进行更改,并且可以在该模块外部公开访问。您将其视为一个对象而不是闭包。当函数可以访问特权数据时,将导致闭包。也就是说,数据绑定从程序的其余部分“消失”。下面是一个例子:
function SomeFunction(x) {
var closureVar = x;
toReturn = function(y) {
var answer = closureVar;
closureVar = y;
return answer;
}
return toReturn;
}
var runIt = SomeFunction(15);
当调用SomeFunction时,它会为“closureVar”创建一个本地绑定。当函数退出时,它的所有本地绑定(通常)都会消失。但是,在这种情况下,返回的函数包含对“closureVar”的引用,因此不能完全删除它。因此,定义为“toReturn”的函数仍然可以使用它
然而,程序中的其他任何内容都无法实现。如果再次调用SomeFunction(),它将为closureVar创建一个新的(本地)绑定,该绑定将由调用SomeFunction()的toReturn函数使用。对SomeFunction()的每次调用都会产生一个新的闭包。FWIW,如果您这样做,它实际上会工作:
function someFunction() {
//someArray = ['blue', 'green'];
someArray[0] = 'blue'
someArray[1] = 'green'
}
我认为这意味着当你用[]创建一个新数组时,你不知何故破坏了引用链。我的理解还不够透彻。访问模块内变量的最佳实践可能是定义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'];
但出现问题的原因是您正在使用新阵列替换,而不是修改阵列,例如
function someFunction() {
someArray.splice(0);
someArray.push('blue', 'green');
}
我相信赋值会导致创建新的对象引用,而修改现有对象会保持现有引用
这是通过共享调用的结果:第一种方法不起作用的原因与在没有节点的JavaScript中不起作用的原因相同:
var someArray = [];
var object = {
someArray: someArray,
}
someArray = [1, 2, 3];
console.log(object.someArray);
这将打印[]
,因为对象。someArray
是对您创建的第一个数组的引用。这是一个过程:
var someArray = [];
创建一个空数组,然后将对该数组的引用另存为名称someArray
。我们将其称为array1
var object = {
someArray: someArray
}
使用属性someArray
创建对象,使该属性引用someArray
引用的数组。重要的是要知道,这意味着该引用现在是对array1
的引用,而不是对someArray
的引用。这导致我们:
someArray = [1, 2, 3];
它创建了一个新数组(我们称之为array2
),然后将其存储为someArray
。此数组完全独立于array1
,并且someArray
的所有未来引用将获得array2
,但它对以前的访问没有影响
这与您的节点示例完全相同-当您覆盖someArray
而不是publicApi.someArray
时,您不会对publicApi.someArray
进行任何更改,因此您不能期望它有所不同
为了明确这一点,您可以从以下几点着手:
someArray -> array1[]
object.someArray -> array1[]
为此:
someArray -> array2[1, 2, 3]
object.someArray -> array1[]
注意,
object.someArray
没有改变。这里有一个打字错误:someArray=[{'blue'},{'green'}]代码>已更正。是的,这是我将实际代码配对到最小值来显示问题。我在真实的代码中使用对象。这对于闭包来说是有意义的,但也许我的问题与闭包无关。也许我的题目写得不对。我的问题更多的是针对节点模块,也许我创建的根本不是闭包。因此我感到困惑。我需要了解Node对我上面写的代码做了什么。Tim,这仍然是一个可变范围的问题。您试图更改的数组的全名为“MyModule.someArray”。您的函数正在创建一个名为“someArray”的新局部变量。如果希望它引用在模块中定义的someArray,则需要使用MyModule.someArray=[“蓝色”、“绿色”]代码>那不正确。如果我将someArray的声明更改为var someArray=['yellow'];然后,当我调试到someFunction中时,someArray将以值['yellow']开始。此外,在WebStorm中,someArray列在“Closure”变量下,而不是“Local”变量下,因此它肯定与初始变量相关联。欢迎您试用。@TimHardy这是真的,someArray
可以从publicApi
中完全访问,但它只用于初始化publicApi。someArray
,它不是与someArray
的必然链接。someArray
引用的数组的任何更改都将反映在publicApi.someArray
中,因为它们此时引用的是同一个数组。但是,如果执行someArray=[…]
,则将someArray
设置为不同的数组,并且不能再通过someArray
更改publicApi.someArray
的值。我试图在我的回答中澄清。这和csum的回答都是准确的,但这一个更清楚一点。我的解释是,我的publicApi.someArray仍然指向源代码