Javascript 模块是什么?模块导出与导出之间的区别是什么?
我已经读了好几个小时关于这个话题的书,只是没有发现任何东西可以帮助我坚持下去 模块只是节点中具有几个属性的对象,一个是引用对象的导出属性 “exports”变量为Javascript 模块是什么?模块导出与导出之间的区别是什么?,javascript,node.js,Javascript,Node.js,我已经读了好几个小时关于这个话题的书,只是没有发现任何东西可以帮助我坚持下去 模块只是节点中具有几个属性的对象,一个是引用对象的导出属性 “exports”变量为 var exports = module.exports 它是指向module.exports引用的对象的变量 我正在努力想象模块是什么。我知道这是个物体,但只有一个吗 我知道这不是node实现模块的确切方式,但我将其可视化,如下所示: var module = {} module.exports = {} // now mod
var exports = module.exports
它是指向module.exports引用的对象的变量
我正在努力想象模块是什么。我知道这是个物体,但只有一个吗
我知道这不是node实现模块的确切方式,但我将其可视化,如下所示:
var module = {}
module.exports = {}
// now module has a property module.exports
var exports = module.exports
evaledFn(module.exports, require, module, filename, dirname);
现在,从我读到的所有内容来看,如果要为module.export='xyz'分配一些内容
它将保存值“xyz”。它是否丢失了原始对象?最重要的是,如果我在同一个文件中为module.exports分配了其他内容,它会被替换为新值吗
EX:
// file = app.js
module.export = 'hello'
module.export = 'bye'
// file = newApp.js
require(./app);
模块的值是多少?我是重写同一个模块对象还是有多个模块对象?您正在重写模块-导出是使用
require
拉入单个对象。通常,当使用require
执行这种模块化JavaScript时,您的导出将是一个构造函数,而不是像示例中的字符串那样的原语。这样,您就可以创建模块中定义的新功能实例。例如:
// module.js
var MyConstructor = function(prop) {
this.prop = prop;
});
module.exports = MyConstructor;
// app.js
var MyConstructor = require('module');
var instance = new MyConstructor('test');
console.log(instance.prop) // 'test'
Node.js中的模块只是文件。每个文件都是一个模块,每个模块都是一个文件。如果有多个文件,则可以有多个模块(每个文件中有一个) 根据
模块。导出
:将阐明以下主题:
module.exports
对象由模块系统创建。有时
这是不能接受的;许多人希望他们的模块成为
一些班级。为此,请将所需的导出对象指定给
模块。导出
。请注意,将所需对象指定给导出将
只需重新绑定本地导出
变量,这可能不是
你想做什么
及
导出模块中可用的
变量,该变量以
参考模块。导出
。与任何变量一样,如果您分配一个新的
值,它不再绑定到上一个值。。。作为指导方针,
如果导出和module.exports之间的关系
对您来说似乎很神奇,忽略导出,只使用module.exports
那么,这一切意味着什么?在您的特定示例中,module.exports
将等于它的最后一个赋值('bye'
)。在继续之前,请务必了解
要从节点的模块加载系统中去掉的关键点是,在它实际运行您所需的代码之前(发生在中),一个新的空将对象导出为模块的属性。(换句话说,您的可视化是正确的。)
节点,然后使用匿名函数将require
d文件中的文本:
(function (exports, require, module, __filename, __dirname) {
// here goes what's in your js file
});
…本质上是eval
s该字符串。eval
ing该字符串的结果是一个函数(匿名包装器),节点立即调用该函数,传入如下参数:
var module = {}
module.exports = {}
// now module has a property module.exports
var exports = module.exports
evaledFn(module.exports, require, module, filename, dirname);
require
、filename
和dirname
是对require
函数(实际上是)的引用,以及包含加载模块路径信息的字符串。(这就是他们所说的“\uu filename
实际上不是一个全局模块,而是每个模块的本地模块。”)
所以我们可以看到,在一个模块中,确实是exports===module.exports
。但是为什么模块同时获得模块
和导出
向后兼容性。在节点的早期,模块内部没有模块
变量。您只需分配到导出
。但是,这意味着您永远不能将构造函数导出为模块本身
模块将构造函数导出为模块的常见示例:
var express = require('express');
var app = express();
这是因为,在默认情况下覆盖节点提供给您的空对象:
module.exports = function() { ... }
但是,请注意,您不能只写:
exports = function { ... }
这是因为。从技术上讲,JavaScript可能被认为是“纯粹的按值传递”,但实际上参数是“按值引用”传递的
这意味着,当您将对象传递给函数时,它将接收对该对象的引用作为值。您可以通过该引用访问原始对象,但不能更改调用方对该引用的感知。换句话说,没有像您在C/C++/C#中看到的那样的“out”参数
作为一个具体例子:
var obj = { x: 1 };
function A(o) {
o.x = 2;
}
function B(o) {
o = { x: 2 };
}
调用A(obj)
将导致obj.x==2
,因为我们访问作为o
传入的原始对象。然而,B(obj)代码>将什么也不做<代码>对象x==1
。将一个全新的对象分配给B
的本地o
只会更改o
指向的对象。它对调用者的对象obj不做任何操作,该对象保持不变
现在应该很清楚为什么有必要将模块
对象添加到节点模块的本地范围。为了允许模块完全替换导出
对象,它必须作为传递给模块匿名函数的对象的属性可用。显然没有人想破坏现有的代码,所以exports
被作为module.exports
的参考
因此,当您只是将属性分配给exports对象时,无论是使用exports
还是module.exports
;它们是同一个,指向完全相同的对象的引用
只有当您希望将函数导出为必须使用的顶级导出时,才可以使用该函数