Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 模块中未更新Nodejs闭包变量_Javascript_Node.js_Closures - Fatal编程技术网

Javascript 模块中未更新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; 当

我需要一些帮助来理解NodeJs。我显然错过了一些基本的东西。我有一个类似于下面的模块,使用一个基本的模块模式

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仍然指向源代码