节点功能范围

时间:2017-12-28 15:52:22

标签: javascript

我最近跳进了深处,一直在慢慢学习游泳。我正在开发一个用于构建简单文本游戏世界的CLI。该代码正在成为一个令人费解的混乱,因此我尝试重新创建我在下面以更简单的形式获得的错误。

尽我所能,我似乎无法理解构建我所有功能的最佳方法。在我的项目中,我有一个解析器功能,可以打破输入并搜索动词'通过try / catch块调用。当一个动词,即“看”'运行它访问我的数据库模块并基于几个参数发送查询以返回房间或事物的描述。因为这几乎都是异步的,所以所有内容都包含在一个承诺中,但我将离开这个例子。以下不是实际的项目,只是简单地重新设置我的对象设置方式。

APP:

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

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

模块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();
  }
};

单词数:

// ***********************
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;
  }
};

在上面的代码中我得到了' TypeError:apple_tree.grow不是一个函数'来自水或未定义的外观。这是我存在的祸根,在我的主要项目中我似乎随意得到这个,这让我相信我不理解范围。我知道我可以在函数中要求模块,它可以工作,但这很可怕,最后会添加数百行代码。如何从其他对象中干净地访问对象的功能?

4 个答案:

答案 0 :(得分:1)

您的问题是项目中存在循环依赖项,并且您覆盖了模块的exports属性。由于这个以及节点cachges所需模块的方式,您将获得module.exports文件中的原始scope_test_player对象,而不是您已覆盖的对象。要解决这个问题,你需要这样写:

// ***********************
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();
};

// ***********************
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;
}

但这对于gerenal来说是一个非常糟糕的设计,你应该找到另一种解决方法。您应始终避免依赖树中的循环/圆圈。

<强>更新

在节点中,每个文件都以这种方式包装到 load 函数中:

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

node.js在内部对require执行类似的操作:

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
}

由于循环要求,require函数将返回原始cache[resolvedPath].exports,即在您将自己的对象绑定到它之前最初设置的foreach ($s in $servers) { foreach ($srv in $services) { $Asrv = Get-Service -Name $srv -ComputerName $s if ($Asrv -ne $null) { $HashSrvs.Add($Asrv.Name, $Asrv.Status) } } $infoObject = @() $infoObject = New-Object PSObject $infoObject | Add-Member -MemberType NoteProperty -Name "Server name" -Value $s $infoObject | Add-Member -MemberType NoteProperty -Name "ServerAvailability" -Value $ConStatus $i=0 foreach ($key in $HashSrvs.GetEnumerator()) { $infoObject | Add-Member -MemberType NoteProperty -Name "ServiceName[$i]" -Value $key.Key -Force $infoObject | Add-Member -MemberType NoteProperty -Name "ServiceStatus[$i]" -Value $key.Value -Force $i++ } $infoColl += $infoObject } $infoColl | Export-Csv -NoTypeInformation -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -Encoding UTF8

答案 1 :(得分:0)

Module1 = scope_test_player,Module2 = scope_test_apple_tree? 也许你在这里有一个循环引用?

APP需要scope_test_player

//循环

scope_test_player需要scope_test_apple_tree

scope_test_apple_tree需要scope_test_player

//循环

我可以看到scope_test_apple_tree没有使用播放器。

您可以尝试删除:

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

来自Module2?

答案 2 :(得分:0)

有几个问题需要解决。

删除第2单元(scope_test_apple_tree.js)中的玩家要求:

const player = require('./scope_test_player')

它不会造成任何损害,但这只是不必要的。

另外,将=+替换为+=中的fertilizegrow,这是我认为您的目标。

我能够使用这些修复程序自然地运行代码。

如果你想重构,我可能会将require文件弄平并在控制播放器操作的主文件中执行,并使用运行它所需的内容明确命名函数(在这种情况下......树) )。

主要保留您的编码约定,我的轻微重构看起来像:

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

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

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

答案 3 :(得分:0)

是的,我的代码中存在循环依赖,因为我没有意识到它们带来的危险。当我从主项目中删除它们肯定它再次开始工作。现在看来,我将被迫重新设计项目,因为有两个模块随机相互引用会导致更多问题。