이번에는 commonJS에 대한 자세한 설명을 가져왔습니다. commonJS 사용 시 주의사항은 무엇인가요? 실제 사례를 살펴보겠습니다.
CommonJS 개요
모든 코드는 모듈 범위에서 실행되며 전역 범위를 오염시키지 않습니다.
모듈은 여러 번 로드할 수 있지만 처음 로드할 때 한 번만 실행되며, 나중에 로드할 때 실행 결과가 캐시됩니다. 캐시된 결과는 직접 읽혀집니다. 모듈이 다시 작동하려면 캐시를 지워야 합니다.
모듈이 로드되는 순서는 코드에 나타나는 순서입니다.
2.모듈 객체
각 모듈 내부에는 현재 모듈을 나타내는 모듈 객체가 있습니다. 다음과 같은 속성을 가지고 있습니다.
console.log(module.id) //模块的识别符,通常是带有绝对路径的模块文件名。console.log(module.filename) //模块的文件名,带有绝对路径。console.log(module.loaded) //返回一个布尔值,表示模块是否已经完成加载。console.log(module.parent) //返回一个对象,表示调用该模块的模块。console.log(module.children) //返回一个数组,表示该模块要用到的其他模块。console.log(module.exports) //表示模块对外输出的值。
2.1 module.exports 속성
module.exports 속성은 현재 모듈의 외부 출력 인터페이스를 나타냅니다. 다른 파일이 모듈을 로드하면 실제로 module.exports 변수를 읽습니다.
2.2 내보내기 변수
편의를 위해 Node는 각 모듈에 대해 module.exports를 가리키는 내보내기 변수를 제공합니다. 이는 각 모듈의 머리 부분에 다음과 같은 줄을 두는 것과 동일합니다:
var exports = module.exports;(commonJS隐式做了这个赋值)
이것의 장점은 모듈 인터페이스를 내보낼 때 내보내기 개체에 메서드를 추가하고 노출할 수 있다는 것입니다.
따라서 module.exports를 변경했지만 여전히 뭔가를 노출하기 위해 내보내기를 사용하고 싶다면, 우리는 직접 imports = module.exports를 작성해야 합니다.
Li:
module.exports = songthing;//接下来把exports指回来exports = module.exports;//常见写法是:exports = module.exports = something;
3 AMD 사양과 CommonJS 사양 기능의 호환성
CommonJS 사양 로딩 모듈은 로딩이 완료된 후에만 후속 작업을 수행할 수 있습니다. AMD 사양은 콜백 함수를 지정할 수 있는 비동기 로딩 모듈입니다. Node.js는 주로 서버 프로그래밍에 사용되기 때문에 모듈 파일은 일반적으로 로컬 하드 디스크에 이미 존재하므로 빠르게 로드할 수 있으므로 비동기 로딩을 고려할 필요가 없으므로 CommonJS 사양이 더 적합합니다. 하지만 브라우저 환경이고 서버에서 모듈을 로딩할 경우 비동기 모드를 사용해야 하므로 브라우저는 일반적으로 AMD 사양을 사용한다.
define(['package/lib'], function(lib){ function foo(){ lib.log('hello world!'); } return { foo: foo }; });
AMD 사양을 사용하면 출력 모듈이 CommonJS 사양과 호환될 수 있습니다. 이 경우 정의 메서드는 다음과 같이 작성해야 합니다.
define(function (require, exports, module){ var someModule = require("someModule"); var anotherModule = require("anotherModule"); someModule.doTehAwesome(); anotherModule.doMoarAwesome(); exports.asplode = function (){ someModule.doTehAwesome(); anotherModule.doMoarAwesome(); }; });
4.require command
4.1 기본 사용법
Node는 CommonJS 모듈 사양을 사용합니다. 내장된 require 명령은 모듈 문서를 로드하는 데 사용됩니다.
require 명령의 기본 기능은 JavaScript 파일을 읽고 실행한 다음 모듈의 내보내기 개체를 반환하는 것입니다. 지정된 모듈을 찾을 수 없으면 오류가 보고됩니다. (직설적으로 말하면 다른 파일에 노출된 값이 이 파일에서 참조됩니다.)
// example.jsvar invisible = function () { console.log("invisible"); } exports.message = "hi"; exports.say = function () { console.log(message); }
다음 명령을 실행하여 내보내기 개체를 출력합니다.
//someelse.jsvar example = require('./example.js');console.log(example);// {// message: "hi",// say: [Function]// }
모듈이 함수를 출력하는 경우 내보내기 개체에 정의할 수 없으며 module.exports 변수에 정의해야 합니다.
//example2.jsmodule.exports = function () { console.log("hello world") }require('./example2.js')()
위 코드에서는 require 명령어가 자기 자신을 호출하는데, 이는 module.exports를 실행하는 것과 동일하므로 hello world가 출력됩니다.
4.2 로드 규칙
require 명령은 파일을 로드하는 데 사용되며 접미사는 기본적으로 .js입니다.
var foo = require('foo');// 等同于var foo = require('foo.js');
require 명령은 다양한 매개변수 형식에 따라 다양한 경로에 있는 모듈 파일을 검색합니다.
(1) string 매개변수가 "/"로 시작하면 절대 경로에 있는 모듈 파일이 짐을 실은. 예를 들어, require('/home/marco/foo.js')는 /home/marco/foo.js를 로드합니다.
(2) 매개변수 문자열이 "./"로 시작하면 (현재 스크립트 실행 위치와 비교하여) 상대 경로에 위치한 모듈 파일이 로드된다는 의미입니다. 예를 들어, require('./circle')는 현재 스크립트와 동일한 디렉터리에 Circle.js를 로드합니다.
(3) 매개변수 문자열이 "./" 또는 "/"로 시작하지 않으면 기본적으로 제공되는 핵심 모듈(Node의 시스템 설치 디렉터리에 위치) 또는 node_modules 디렉터리에 있는 기존 모듈을 의미합니다. 모든 수준에서 모듈을 설치합니다(전역적으로 또는 로컬로).
예를 들어 /home/user/projects/foo.js 스크립트가 require('bar.js') 명령을 실행하면 Node는 다음 파일을 순차적으로 검색합니다.
/usr/local/lib/node/bar.js /home/user/projects/node_modules/bar.js /home/user/node_modules/bar.js /home/node_modules/bar.js /node_modules/bar.js
이 디자인의 목적은 다양한 모듈이 의존하는 모듈을 현지화할 수 있도록 하는 것입니다.
(4) 매개변수 문자열이 "./" 또는 "/"로 시작하지 않고 require('example-module/path/to/file')와 같은 경로인 경우 example-module의 위치는 다음과 같습니다. 먼저 찾은 다음 이를 매개변수로 사용하여 후속 경로를 찾습니다.
(5) 지정된 모듈 파일을 찾을 수 없으면 Node는 검색하기 전에 파일 이름에 .js, .json 및 .node를 추가하려고 시도합니다. .js 파일은 텍스트 형식의 JavaScript 스크립트 파일로 구문 분석되고, .json 파일은 JSON 형식의 텍스트 파일로 구문 분석되며, .node 파일은 컴파일된 바이너리 파일로 구문 분석됩니다.
(6) require 명령으로 로드된 정확한 파일 이름을 얻으려면 require.resolve() 메서드를 사용하세요.
4.3 디렉터리 로딩 규칙
通常,我们会把相关的文件会放在一个目录里面,便于组织。这时,最好为该目录设置一个入口文件,让require方法可以通过这个入口文件,加载整个目录。
在目录中放置一个package.json文件,并且将入口文件写入main字段。下面是一个例子。
// package.json{ "name" : "some-library", "main" : "./lib/some-library.js" } require发现参数字符串指向一个目录以后,会自动查看该目录的package.json文件,然后加载main字段指定的入口文件。如果package.json文件没有main字段,或者根本就没有package.json文件,则会加载该目录下的index.js文件或index.node文件。
4.4模块的缓存
第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的module.exports属性。
require('./example.js');require('./example.js').message = "hello";require('./example.js').message// "hello"
上面代码中,连续三次使用require命令,加载同一个模块。第二次加载的时候,为输出的对象添加了一个message属性。但是第三次加载的时候,这个message属性依然存在,这就证明require命令并没有重新加载模块文件,而是输出了缓存。
如果想要多次执行某个模块,可以让该模块输出一个函数,然后每次require这个模块的时候,重新执行一下输出的函数。
所有缓存的模块保存在require.cache之中,如果想删除模块的缓存,可以像下面这样写。
// 删除指定模块的缓存delete require.cache[moduleName];// 删除所有模块的缓存Object.keys(require.cache).forEach(function(key) { delete require.cache[key]; })
注意,缓存是根据绝对路径识别模块的,如果同样的模块名,但是保存在不同的路径,require命令还是会重新加载该模块。
4.5环境变量NODE_PATH
Node执行一个脚本时,会先查看环境变量NODE_PATH。它是一组以冒号分隔的绝对路径。在其他位置找不到指定模块时,Node会去这些路径查找。
可以将NODE_PATH添加到.bashrc。 export NODE_PATH="/usr/local/lib/node"
所以,如果遇到复杂的相对路径,比如下面这样:
var myModule = require('../../../../lib/myModule');
有两种解决方法,一是将该文件加入node_modules目录,二是修改NODE_PATH环境变量,package.json文件可以采用下面的写法。
{ "name": "node_path", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "NODE_PATH=lib node index.js" }, "author": "", "license": "ISC"}
NODE_PATH是历史遗留下来的一个路径解决方案,通常不应该使用,而应该使用node_modules目录机制。
4.6模块的循环加载
如果发生模块的循环加载,即A加载B,B又加载A,则B将加载A的不完整版本。
// a.jsexports.x = 'a1';console.log('a.js ', require('./b.js').x); exports.x = 'a2';// b.jsexports.x = 'b1';console.log('b.js ', require('./a.js').x); exports.x = 'b2';// main.jsconsole.log('main.js ', require('./a.js').x);console.log('main.js ', require('./b.js').x);
上面代码是三个JavaScript文件。其中,a.js加载了b.js,而b.js又加载a.js。这时,Node返回a.js的不完整版本,所以执行结果如下。(也就是说,虽然这样去require看似会造成a.js和b.js循环引用,但commonJS会在将循环的点剪断循环,并对剪断处所在的a.js终止执行,b得到了第一个x值。)
$ node main.js b.js a1 a.js b2 main.js a2 main.js b2
修改main.js,再次加载a.js和b.js。
// main.jsconsole.log('main.js ', require('./a.js').x);console.log('main.js ', require('./b.js').x);console.log('main.js ', require('./a.js').x);console.log('main.js ', require('./b.js').x);
执行上面代码,结果如下。
$ node main.js b.js a1 a.js b2 main.js a2 main.js b2 main.js a2 main.js b2
上面代码中,第二次加载a.js和b.js时,会直接从缓存读取exports属性,所以a.js和b.js内部的console.log语句都不会执行了。
4.7 require.main
require方法有一个main属性,可以用来判断模块是直接执行,还是被调用执行。
直接执行的时候(node module.js),require.main属性指向模块本身。
require.main === module// true
调用执行的时候(通过require加载该脚本执行),上面的表达式返回false。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
相关阅读:
위 내용은 commonJS 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!