Maison >interface Web >js tutoriel >Explication détaillée de CommonJS
Cette fois, je vous apporte une explication détaillée de commonJS. Quelles sont les précautions lors de l'utilisation de commonJS. Voici des cas pratiques, jetons un coup d'œil.
Présentation de CommonJS
Tout le code s'exécute dans la portée du module et ne polluera pas la portée globale.
Le module peut être chargé plusieurs fois, mais il ne sera exécuté qu'une seule fois lors de son premier chargement, puis les résultats en cours d'exécution seront mis en cache. Lors d'un chargement ultérieur, les résultats mis en cache seront lus directement. Pour que le module fonctionne à nouveau, le cache doit être vidé.
Les modules sont chargés dans l'ordre dans lequel ils apparaissent dans le code.
2. Objet module
À l'intérieur de chaque module, il y a un objet module, représentant le module actuel. Il possède les propriétés suivantes.
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 Attribut module.exports
L'attribut module.exports représente l'interface de sortie externe du module actuel Lorsque d'autres fichiers chargent le module, ils lisent en fait la variable module.exports. .
2.2 variable d'exportation
Pour plus de commodité, Node fournit une variable d'exportation pour chaque module, pointant vers module.exports. Cela équivaut à avoir une ligne de commandes en tête de chaque module :
var exports = module.exports;(commonJS隐式做了这个赋值)
L'avantage de ceci est que lors de l'export de l'interface du module, vous pouvez ajouter des méthodes à l'objet exports et les exposer.
Donc, si vous modifiez module.exports, mais que vous souhaitez toujours utiliser export.xxx pour exposer quelque chose, alors nous devons écrire exports = module.exports nous-mêmes
Li :
module.exports = songthing;//接下来把exports指回来exports = module.exports;//常见写法是:exports = module.exports = something;
3 ; .Compatibilité de la spécification AMD et de la spécification CommonJS
Le module de chargement de la spécification CommonJS est synchrone et ce n'est qu'une fois le chargement terminé que les opérations suivantes peuvent être effectuées. La spécification AMD est un module de chargement asynchrone qui permet de spécifier une fonction de rappel . Étant donné que Node.js est principalement utilisé pour la programmation du serveur, les fichiers de module existent généralement déjà sur le disque dur local, ils peuvent donc être chargés rapidement. Il n'est pas nécessaire d'envisager un chargement asynchrone, la spécification CommonJS est donc plus applicable. Cependant, s'il s'agit d'un environnement de navigateur et que le module doit être chargé côté serveur, le mode asynchrone doit être utilisé, donc le côté navigateur utilise généralement la spécification AMD.
define(['package/lib'], function(lib){ function foo(){ lib.log('hello world!'); } return { foo: foo }; });
La spécification AMD permet au module de sortie d'être compatible avec la spécification CommonJS. Dans ce cas, la méthode de définition doit être écrite comme suit :
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 Utilisation de base Node utilise la spécification du module CommonJS et la commande require intégrée est utilisée pour charger les fichiers du module. La fonction de base de la commanderequire est de lire et d'exécuter un fichier
JavaScript, puis de renvoyer l'objet exports du module. Si le module spécifié n'est pas trouvé, une erreur sera signalée. (Pour parler franchement, les valeurs exposées dans un autre fichier sont référencées dans ce fichier.)
// example.jsvar invisible = function () { console.log("invisible"); } exports.message = "hi"; exports.say = function () { console.log(message); }Exécutez la commande suivante pour générer l'objet d'exportation.
//someelse.jsvar example = require('./example.js');console.log(example);// {// message: "hi",// say: [Function]// }Si le module génère une fonction, elle ne peut pas être définie sur l'objet exports, mais doit être définie sur la variable module.exports.
//example2.jsmodule.exports = function () { console.log("hello world") }require('./example2.js')()Dans le code ci-dessus, la commande require s'appelle elle-même, ce qui équivaut à exécuter module.exports, donc hello world sera affiché. 4.2 Règles de chargement La commande require est utilisée pour charger des fichiers et le suffixe par défaut est .js.
var foo = require('foo');// 等同于var foo = require('foo.js');Selon différents formats de paramètres, la commande require recherche les fichiers du module dans différents chemins : (1) Si le paramètre
chaîne commence par "/ ", puis indique qu'un fichier de module situé à un chemin absolu est chargé. Par exemple, require('/home/marco/foo.js') chargera /home/marco/foo.js. (2) Si la chaîne du paramètre commence par "./", cela signifie qu'un fichier de module situé dans un chemin relatif (par rapport à l'emplacement actuel de l'exécution du script) est chargé. Par exemple, require('./circle') chargera circle.js dans le même répertoire que le script actuel.
(3) Si la chaîne du paramètre ne commence pas par "./" ou "/", cela signifie qu'un module principal fourni par défaut (situé dans le répertoire d'installation système de Node) est chargé, ou qu'un module situé dans le répertoire node_modules à tous les niveaux des modules installés (globalement ou localement).
/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.jsLe but de cette conception est de permettre à différents modules de localiser les modules dont ils dépendent.
(4) Si la chaîne de paramètres ne commence pas par "./" ou "/" et est un chemin, tel que require('example-module/path/to/file'), un exemple-module sera trouvé première position, puis utilisez-le comme paramètre pour trouver le chemin suivant.
(5) Si le fichier de module spécifié n'est pas trouvé, Node essaiera d'ajouter .js, .json et .node au nom du fichier avant de rechercher. Les fichiers .js seront analysés comme des fichiers de script JavaScript au format texte, les fichiers .json seront analysés comme des fichiers texte au format JSON et les fichiers .node seront analysés comme des fichiers binaires compilés.
(6) Si vous souhaitez obtenir le nom exact du fichier chargé par la commande require, utilisez la méthode require.resolve().
通常,我们会把相关的文件会放在一个目录里面,便于组织。这时,最好为该目录设置一个入口文件,让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中文网其它相关文章!
相关阅读:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!