简体   繁体   English

节点功能范围

[英]Node Function Scope

I jumped into the deep end recently and have been slowly learning to swim. 我最近跳入深渊,一直在慢慢学习游泳。 I'm working on a CLI for building out a simple text game world. 我正在使用CLI构建一个简单的文本游戏世界。 That code is becoming a convoluted mess and so I have tried to recreate the error I am getting in a simpler form below. 该代码变得一团糟,所以我尝试重新创建下面以更简单形式出现的错误。

Try as I might I can't seem to understand the best way to structure all of my functions. 尝试尝试,我似乎无法理解构造所有函数的最佳方法。 In my project I have a parser function that breaks input up and searches for a 'verb' to invoke via a try/catch block. 在我的项目中,我有一个解析器函数,该函数分解输入并搜索通过try / catch块调用的“动词”。 When a verb ie 'look' runs it accesses my database module and sends a query based on several parameters to return the description of a room or thing. 当一个动词(即“ look”)运行时,它访问我的数据库模块并基于几个参数发送查询以返回房间或事物的描述。 Because this is all asynchronous virtually everything is wrapped in a promise but I am leaving that out of this example. 因为这都是异步的,所以实际上所有内容都包含在一个Promise中,但是我将其排除在本示例之外。 The following is not the actual project, just a simple recreation of the way I have my objects set up. 以下不是实际的项目,只是我设置对象的一种简单方式。

APP: APP:

// ***********************
const player = require('./scope_test_player');

player.look();
player.water();

Module1: 模块1:

// ***********************
const apple_tree = require('./scope_test_apple_tree');

module.exports = {
  look: function(){
    console.log(
      'The apple tree is '+apple_tree.height+'ft tall and has '
      +apple_tree.apples+' apples growing on it'
    );
  },
  water: function() {
    apple_tree.grow();
  }
};

Module2: 模块2:

// ***********************
const player = require('./scope_test_player');

module.exports = {
  height: 10,
  nutrition: 0.3,
  apples: [],
  fertilize: function(number) {
    this.nutrition+=number;
  },
  grow: function() {
    this.height+=this.nutrition;
  }
};

In the above code I get 'TypeError: apple_tree.grow is not a function' from water or undefined from look. 在上面的代码中,我从水中得到“ TypeError:apple_tree.grow不是一个函数”,或者从外观中未得到定义。 This is the bane of my existence and I have been getting this seemingly at random in my main project which leads me to believe I dont understand scope. 这是我生存的祸根,在我的主要项目中,我似乎一直在随意获取它,这使我相信我不了解范围。 I know I can require the module within the function and it will work, but that is hideous and would add hundreds of lines of code by the end. 我知道我可以在函数中要求该模块,并且该模块可以工作,但这很丑陋,最后会增加数百行代码。 How do I cleanly access the functions of objects from within other objects? 如何从其他对象中干净地访问对象的功能?

You problem is that have a cyclic dependencies in your project and that you overwrite the exports property of the module. 您的问题是项目中具有循环依赖性,并且您覆盖了模块的exports属性。 Because of that and the way node cachges required modules, you will get the original module.exports object in scope_test_player file and not the one you have overwritten. 因此,节点将缓存所需模块的方式,您将在scope_test_player文件中获得原始module.exports对象,而不是被覆盖的对象。 To solve that you need to write it that way: 为了解决这个问题,您需要这样写:

// ***********************
const apple_tree = require('./scope_test_apple_tree');

module.exports.look = function() {
  console.log(
    'The apple tree is ' + apple_tree.height + 'ft tall and has ' + apple_tree.apples + ' apples growing on it'
  );
};

module.exports.water = function() {
  apple_tree.grow();
};

And

// ***********************
const player = require('./scope_test_player');

module.exports.height = 10;
module.exports.nutrition = 10;
module.exports.apples = [];
module.exports.fertilize = function(number) {
  this.nutrition = +number;
};

module.exports.growth = function() {
  this.height = +this.nutrition;
}

But this is a really bad design in gerenal and you should find another way how to solve that. 但这对于Gerenal来说确实是一个糟糕的设计,您应该找到另一种解决方法。 You should always avoid loops/circles in your dependency tree. 您应始终避免在依赖关系树中出现循环/圆。

UPDATE UPDATE

In node each file is wrappted into load function in this way: 在节点中,每个文件都以这种方式包装到装入函数中:

function moduleLoaderFunction( module, exports /* some other paramteres that are not relavant here*/)
{
   // the original code of your file
}

node.js internally does something like this for a require: node.js在内部需要执行以下操作:

var loadedModules = {}

function require(moduleOrFile) {
    var resolvedPath = getResolvedPath(moduleOrFile)
    if( !loadedModules[resolvedPath] ) {
       // if the file was not loaded already create and antry in the loaded modules object
       loadedModules[resolvedPath] = {
         exports : {}
       }

       // call the laoded function with the initial values
       moduleLoaderFunction(loadedModules[resolvedPath], loadedModules[resolvedPath].exports)
    }

    return loadedModules[resolvedPath].exports
}

Because of the cyclic require, the require function will return the original cache[resolvedPath].exports , the one that was initially set before you assinged your own object to it. 由于周期性的需求, require函数将返回原始的cache[resolvedPath].exports ,它是在将自己的对象赋给它之前最初设置的。

Is Module1 = scope_test_player and Module2 = scope_test_apple_tree? 是Module1 = scope_test_player和Module2 = scope_test_apple_tree吗? Maybe you have a cyclic reference here? 也许您在这里有循环参考?

APP requires scope_test_player APP需要scope_test_player

// loop //循环

scope_test_player requires scope_test_apple_tree scope_test_player需要scope_test_apple_tree

scope_test_apple_tree requires scope_test_player scope_test_apple_tree需要scope_test_player

// loop //循环

As I can see scope_test_apple_tree doesn't use player. 如我所见,scope_test_apple_tree不使用播放器。

Can you try to remove: 您可以尝试删除:

const player = require('./scope_test_player');

from Module2 ? 来自Module2吗?

There are a few issues to address. 有几个问题要解决。

Remove the player require in Module 2( scope_test_apple_tree.js ): 删除模块2( scope_test_apple_tree.js )中的播放器要求:

const player = require('./scope_test_player')

It doesn't do any damage keeping it there but it's just unnecessary. 将其保留在此处不会造成任何损害,但这只是不必要的。

Also, replace =+ with += in fertilize and grow which is what I think you are going for. 另外,在我的fertilizegrow ,用+=代替=+ ,这就是我认为的目标。

I was able to run the code natually with those fixes. 我能够使用这些修复程序自然地运行代码。


If you want to refactor, I'd probably flatten out the require files and do it in the main file controlling the player actions and explicitly name the functions with what is needed to run it (in this case...the tree). 如果您想重构,我可能会整理需求文件,并在控制播放器动作的主文件中进行处理,并使用运行它所需的内容(在本例中为树)显式命名函数。

Keeping mostly your coding conventions, my slight refactor would look something like: 基本上保持您的编码约定,我的轻微重构看起来像:

index.js index.js

const player = require('./scope_test_player');
const apple_tree = require('./scope_test_apple_tree');

player.lookAtTree(apple_tree);
player.waterTree(apple_tree);

scope_test_player.js scope_test_player.js

module.exports = {
  lookAtTree: function(tree){
    console.log(
      'The apple tree is '+tree.height+'ft tall and has '
      +tree.apples.length+' apples growing on it'
    );
  },
  waterTree: function(tree) {
    tree.grow();
    console.log('The apple tree grew to', tree.height, 'in height')
  }
};

scope_test_apple_tree.js scope_test_apple_tree.js

module.exports = {
  height: 10,
  nutrition: 0.3,
  apples: [],
  fertilize: function(number) {
    this.nutrition += number;
  },
  grow: function() {
    this.height += this.nutrition;
  }
};

Yes, I had circular dependencies in my code because I was unaware of the danger they imposed. 是的,我的代码中有循环依赖项,因为我没有意识到它们带来的危险。 When I removed them from the main project sure enough it started working again. 当我从主项目中删除它们时,请确保它又可以开始工作了。 It now seems that I'm going to be forced into redesigning the project as having two modules randomly referencing each other is going to cause more problems. 现在看来,我将不得不重新设计该项目,因为具有两个彼此随机引用的模块会引起更多问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM