Eloquent Javascript需要功能解释

时间:2015-04-14 04:58:40

标签: javascript module require

作者解释了需要函数here的最小实现,如下所示:

function require(name) {
  var code = new Function("exports", readFile(name));
  var exports = {};
  code(exports);
  return exports;
}

console.log(require("weekDay").name(1));
// → Monday

我很难理解到底发生了什么,主要是因为这个例子不完整。目前,我已接受readFile()以字符串格式返回代码。这部分让我很困惑:为什么var exports被传递到代码中,它在做什么,为什么要返回? exports对象如何返回readFile已检索到的代码?

2 个答案:

答案 0 :(得分:6)

new Function("exports", body)将创建一个匿名函数,该函数接受一个参数(exports)并执行body中的代码。 将传递给函数体的exports作为空对象开始,目的是模块体将用它想要向世界其他地方公开的东西填充它。然后执行该函数(我们传入我们的exports对象)。最后,返回模块导出的内容。

这是一个更完整的例子:

fakeFileSystem = {
  "weekDay.js": "                \
      var days = [               \
        'Sunday',                \
        'Monday',                \
        'Tuesday',               \
        'Wednesday',             \
        'Thursday',              \
        'Friday',                \
        'Saturday'               \
      ];                         \
      function name(dayNo) {     \
        return days[dayNo];      \
      }                          \
      exports.name = name;       \
  "
};

function require(name) {
  var code = new Function("exports", fakeFileSystem[name + ".js"]);
  var exports = {};
  code(exports);
  return exports;
}

console.log(require("weekDay").name(1));
// → Monday

这是有效的,因为code的构造就像它是这个函数一样:

function(exports) {
  var days = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday'
  ];
  function name(dayNo) {
    return days[dayNo];
  }
  exports.name = name;
}

我们将{}传递给此函数,并将其修改为

{
  name: function(dayNo) {
    return days[dayNo];
  }
}

其中days在闭包中被捕获,但对外界不可见。这使我们只能访问模块中明确添加到exports的内容(如name),同时隐藏所有不属于days的内容。

答案 1 :(得分:2)

此示例需要了解函数构造函数。

这可能会有所帮助:

$ node
> f = new Function("x", "return x + 2");
[Function]
> f(8)
10

在您的示例中,函数的主体是文件中的代码,您将在其中看到变量exports的属性的赋值。那么exports是什么?这是一个最初为空的对象。调用时,模块的主体将“填充”。在调用code(exports)之后,您将拥有一个包含许多好东西的填充对象,该对象从require返回。

示例:

假设文件包含

var x = 3
exports.y = 10 * x

然后你的调用会传入一个空对象,但是执行该函数会将y属性添加到对象中,然后你会回来

{y: 30}