从实例化的对象到外部作用域的变量引用如何在NodeJS中工作

时间:2019-01-07 15:00:35

标签: javascript node.js scope closures

我对内部对象如何看待/与内部对象相关的范围感到有些困惑。我知道范围定义了如何封闭/看到变量,上下文指的是变量的创建和绑定到对象,内部对象和函数可以访问全局对象。但是,我不了解范围如何(或是否)与对象相关。

  1. 范围界定如何进行?
  2. 是否只有通过(a)将包含外部变量的this绑定到对象或(b)将该变量添加到全局对象来访问对象中的外部变量的唯一方法?或者,对象是否使用javascript作用域来引用外部作用域?

我正在尝试设置NodeJS Web服务器,并希望定义一个本地变量,该条目可以由条目(索引)文件中构造的所有其他内部对象访问。我尝试使用入口文件中的var x = 10;来执行此操作;但是,当我尝试从稍后在代码中实例化的对象访问变量时,无法访问该变量。我使用new运算符实例化了一个对象,然后在该对象中调用了一个方法,该方法将x记录到控制台,但出现“未定义x”错误。在chrome中调试时,找不到在任何地方定义的x。我看到了全局上下文,它似乎只是全局对象,我看到了本地上下文,它似乎是实例化的对象,但是我没有看到对实例化该对象的上下文的引用。我可以将变量放在全局对象上,然后可以对其进行引用,但我不想陷入将所有内容都放在全局对象上的坏习惯。

顶层(名为startup.js的文件,使用node startup.js进行调用):

  var express = require('express');
  var web = express();
  var Controller = require('./classes/Controller');
  var x = 10;
  var controller = new Controller(props);
  web.post('/addEntry', function(req, res){
    controller.createEntry(req.body, (error, status) =>{
      if (error) {
          res.send('Error: ' + error);
          console.log(error);
      }
      res.send("Success:" + status);
    });
 });

 web.listen(3000);

控制器文件:

class Controller {
  constructor()

  createEntry(entry, callback) {
     console.log(x);
     return callback(entry);
  }
}

module.exports = Controller;
  1. 我希望能够以公认的惯例从内部范围以已建立的模式引用x。如果在更高级别的上下文中使用变量而不是在实例化对象中使用方法不能实现这一点,那么,如果您可以提出一个替代方案(最好不要附加到全局对象),我将不胜感激。 感谢您的时间和帮助,请让我知道我是否以及如何改善该职位!

2 个答案:

答案 0 :(得分:1)

您的示例中的x仅可用于startup.js中的代码。在其他任何地方都无法访问。它不是全局的(我想您已经知道),它是startup.js模块中的模块全局

要使其可用于Controller的代码,通常要做的是将其作为参数传递给Controller

var controller = new Controller(props, x);
// ------------------------------------^

这不会传递变量,但会在执行该行代码时传递变量的当前值。

如果您想传递Controller的某个内容,即使您对其进行更改,它也会看到x的当前值,您可以将x作为属性放入对象,然后传递对象引用改为Controller

var stuff = {x: 10};
// ...
var controller = new Controller(props, stuff);

Controller会记住对象引用,然后在该对象上查找x

class Controller {
  constructor(props, stuff) {
      this.stuff = stuff; // <====
  }

  createEntry(entry, callback) {
     console.log(stuff.x);
     // ---------^^^^^^
     return callback(entry);
  }
}

module.exports = Controller;

或者,根据x是什么(系统范围的配置参数?):您可以将x和其他与之相关的东西放在自己的模块中(例如{{1 }}):

stuff.js

...并拥有module.exports = {x: 10}; 和其他需要加载模块的内容:

controller.js

我认为以上内容回答了问题2和问题3,但是:

  

1。范围界定是如何工作的?

作用域定义是一个词法(文本)概念,它确定哪些标识符等。等,可访问代码。范围就像嵌套框一样工作:每个范围都可以访问其包含的范围中的所有内容。例如:

var stuff = require("./stuff");
// ...
class Controller {
  constructor(props) {
  }

  createEntry(entry, callback) {
     console.log(stuff.x);
     // ---------^^^^^^
     return callback(entry);
  }
}

您可能会想:“嘿,等等,但是如果您两次打var x; // Code here has access to `x` function outer() { var y; // Code here has access to `x` and `y` function inner() { var z; // Code here has access to `x`, `y`, and `z` } inner(); } outer(); ,该怎么办?然后有两个outer!”而且您绝对正确,有!还有两个y。每个inner都可以访问相同的inner,但是每个实体都有一个不同 x:为调用{{1}而创建的y }创建了y

这是关闭的工作方式。更多:


关于outer:您提到使用inner访问this.x(例如this)。该机制(x对象上查找属性。相反,您的this.x变量不是属性,而是变量。 JavaScript对象和范围彼此之间关系不大。尽管我们经常将作用域概念化为使用幕后的隐藏对象(规范确实如此),但这些对象纯粹是概念性的,无法在代码中访问(唯一的例外是:全局对象,它同时作为真实对象和< / em>一个容器,用于存储用this.x声明的全局变量和全局声明的函数[但不适用于用xvar声明的变量,或用let定义的类)。

答案 1 :(得分:0)

  

范围界定如何进行?

作用域由功能(var)或块(let)界定。

如果var具有相同的功能或let位于相同的块中,则可以访问它。

如果当前作用域定义在可用变量的作用域内,则可以访问它,除非该作用域在较窄的作用域内被另一个同名变量掩盖。

  

是否只有通过(a)将包含外部变量的this绑定到对象或(b)将该变量添加到全局对象来访问对象中的外部变量的唯一方法?或者,对象是否使用javascript作用域来引用外部作用域?

您的情况(a)无法访问该变量。对象属性不是变量。

您的情况(b)仅表示变量存储在最大范围内。最好避免全局变量。尽量缩小范围。这样可以更轻松地管理代码。

  

我希望能够以公认的惯例从内部范围中引用x。

x的值作为参数传递给函数。不要尝试直接访问x