node 遵循的是CommonJS规范, 为了避免全局命名冲突,以及同名函数名或者变量名被覆盖的情况,提出了module的概念,并且内部实现了,每个js是个独立的modlue,内部的变量和方法都是私有的,其他模块要用的话,自己要先通过module关键字导出,其他模块要用的话要用require导入。
-
- require的时候,nodejs做了什么
-
- module module.export是什么关系
-
- 为什么可以直接使用
module
module.exports
以及二者直接是什么关系? 为什么可以直接使用__dirname
__filename
?
- 为什么可以直接使用
-
- 循环引用的问题
一个例子
- A 会报错
The argument 'id' must be a non-empty string. Received
, 报错的信息在nodejs源码里面写着所以直接require('') 会走到nodejs内部Modlue原型上的require方法里面,会先判断传入的路径是否为空, 为空就报错,停止往下执行。
(function (exports, require, module, __filename, __dirname) { var a = ;
- 因为,nodejs会把exports ,require, modlue当参数导入进来, 所以我们可以在写js的时候,直接使用。
- 那我们可以直接打印这几个变量,看看他们是什么关系
// console.log(module);
// Module {
// id: '.',
// exports: {},
// parent: null,
// filename:
// '/Users//development//nodeFromStratch/005.require.js',
// loaded: false,
// children: [],
// paths:
// [ '/Users//development//nodeFromStratch/node_modules',
// '/Users//development//node_modules',
// '/Users//development//node_modules',
// '/Users//development/node_modules',
// '/Users//node_modules',
// '/Users/node_modules',
// '/node_modules' ] }
- 发现是个
Modlue
对象里面有个属性,exports 值是{} 这就解释了为什么,我们导入变量或者函数的时候要这么写了
var url = "test.com";
function logUrl(message) {
//do something
console.log("log method invoked");
console.log(message);
}
module.exports.log = logUrl;
module.exports.SomeUrl = url;
- 调用的堆栈信息从下往上为:
startup
->Module.runMain
->Module._load
等一系列过程。
//b.js
var a =;
//报错信息
(function (exports, require, module, __filename, __dirname) { var a = ;
^
SyntaxError: Unexpected token ;
at new Script (vm.js:80:7)
at createScript (vm.js:274:10)
at Object.runInThisContext (vm.js:326:10)
at Module._compile (internal/modules/cjs/loader.js:664:28)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
at startup (internal/bootstrap/node.js:283:19)
nodejs requirejs大概原理
- 当我们写个nodejs文件的时候。站在nodejs角度,他大概做了这些事:
//自己实现的例子
function require() {
var modlue = {
exports: {}
// ... //省略其他属性和方法
};
(function(modlue, exports) {
//用户写的js被包装在这里
var a = 1;
modlue.exports.a = 1;
})(modlue, modlue.exports);
return modlue.exports;
}
console.log(require());//{ a: 1 }
//node官网的例子
To illustrate the behavior, imagine this hypothetical implementation of require(), which is quite similar to what is actually done by require():
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// Module code here. In this example, define a function.
function someFunc() {}
exports = someFunc;
// At this point, exports is no longer a shortcut to module.exports, and
// this module will still export an empty default object.
module.exports = someFunc;
// At this point, the module will now export someFunc, instead of the
// default object.
})(module, module.exports);
return module.exports;
}
require怎么用,用在文件的哪里?
- require的使用非常简单,它相当于module.exports的传送门,module.exports后面的内容是什么,require的结果就是什么,对象、数字、字符串、函数……再把require的结果赋值给某个变量,相当于把require和module.exports进行平行空间的位置重叠。
而且require理论上可以运用在代码的任何地方,甚至不需要赋值给某个变量之后再使用,比如:
require('./a')(); // a模块是一个函数,立即执行a模块函数
var data = require('./a').data; // a模块导出的是一个对象
var a = require('./a')[0]; // a模块导出的是一个数组
你在使用时,完全可以忽略模块化这个概念来使用require,仅仅把它当做一个node内置的全局函数,它的参数甚至可以是表达式
require(process.cwd() + '/a');
或者
nodejs如何解决循环引用的问题?官网给出的是 unfinished copy
- 看一个例子 a.js require b.js 同时b.js 引用a.js
//a.js
var b = require("./b");
console.log("in a.js get b is :" + b.b);
module.exports.a = "this is a";
//in b.js get a is :undefined
// in a.js get abis :this is b
// b.js
var a = require("./a");
console.log("in b.js get a is :" + a.a);
module.exports.b = "this is b";
//运行a .js 结果是有个没有输出
//in b.js get a is :undefined
// in a.js get abis :this is b
//如何解决? 修改a b 中 先导出 再 reqiure
//a.js
module.exports.a = "this is a";
var b = require("./b");
console.log("in a.js get b is :" + b.b);
//b.js
module.exports.b = "this is b";
var a = require("./a");
console.log("in b.js get a is :" + a.a);
//再次运行a .js 得到结果为
in b.js get a is :this is a
in a.js get b is :this is b
//再次运行b.js 得到结果为
in a.js get b is :this is b
in b.js get a is :this is a
总结
-
- 为什么nodejs可以使用module ? 因为nodejs包装了一层,包装的时候传入了module ,require,等参数
- modlue 和module.exports 关系是? var module = { exports: {}} 这样的关系
- 所以不要写exports.xx = {} 这种 会覆盖引用,应该写
modlue.exports.xxKey = xxValue
modlue.exports.xxKey1 = xxValue1
或者modlue.exports = { key1: val1, key2:val2, ...}
- node如何解决循环引用的问题?写的时候尽量避免,或者先导出 再require (有待再次验证)
- 感谢阅读,希望有帮助。
参考
- nodejs官网
- nojejs源码 reqiure node/-/blob/lib/internal/modules/cjs/helpers.js#L16:3
- nodejs vm vm.runInThisContext
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!