• CommonJS


    概述

    Node应用由模块组成,采用CommonJS模块规范。

    根据这个规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

    // example.js
    var x = 5;
    var addX = function (value) {
      return value + x;
    };

    上面代码中,变量x和函数addX,是当前文件example.js私有的,其他文件不可见。

    如果想在多个文件分享变量,必须定义为global对象的属性。

    global.warning = true;

    上面代码的warning变量,可以被所有文件读取。当然,这样写法是不推荐的。

    CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

    var x = 5;
    var addX = function (value) {
      return value + x;
    };
    module.exports.x = x;
    module.exports.addX = addX;

    上面代码通过module.exports输出变量x和函数addX

    require方法用于加载模块。

    var example = require('./example.js');
    
    console.log(example.x); // 5
    console.log(example.addX(1)); // 6

    CommonJS模块的特点如下。

    • 所有代码都运行在模块作用域,不会污染全局作用域。
    • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
    • 模块加载的顺序,按照其在代码中出现的顺序

    module对象

    Node内部提供一个Module构造函数,所有的模块都是Module的实例。

    function Module(id,parent){
    
    this.id=id;
    
    this.exports={};
    
    this.parent=parent;
    
    }

    每个模块内部,都有一个module对象,代表当前模块,它有以下属性。

    module.id 模块的识别符,通常是带有绝对路径的模块文件名。

    module.filename 模块的文件名,带有绝对路径

    module.loaded 返回一个布尔值,表示模块是否已经完成加载

    module.parent 返回一个对象,表示调用该模块的模块

    module.children 返回一个数组,表示该模块要用到的其他模块

    module.exports 表示模块对外输出的值

    下面是一个示例文件,最后一行输出module变量。

    // example.js
    var jquery = require('jquery');
    exports.$ = jquery;
    console.log(module);

    执行这个文件,命令行会输出如下信息。

    { id: '.',
      exports: { '$': [Function] },
      parent: null,
      filename: '/path/to/example.js',
      loaded: false,
      children:
       [ { id: '/path/to/node_modules/jquery/dist/jquery.js',
           exports: [Function],
           parent: [Circular],
           filename: '/path/to/node_modules/jquery/dist/jquery.js',
           loaded: true,
           children: [],
           paths: [Object] } ],
      paths:
       [ '/home/user/deleted/node_modules',
         '/home/user/node_modules',
         '/home/node_modules',
         '/node_modules' ]
    }

    如果在命令行下调用某个模块,比如node something.js,那么module.parent就是undefined。如果是在脚本之中调用,比如require('./something.js'),那么module.parent就是调用它的模块。利用这一点,可以判断当前模块是否为入口脚本。

    if (!module.parent) {
        // ran with `node something.js`
        app.listen(8088, function() {
            console.log('app listening on port 8088');
        })
    } else {
        // used with `require('/.something.js')`
        module.exports = app;
    }

    module.exports属性

    module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。

    var EventEmitter = require('events').EventEmitter;
    module.exports = new EventEmitter();
    
    setTimeout(function() {
      module.exports.emit('ready');
    }, 1000);

    上面模块会在加载后1秒后,发出ready事件。其他文件监听该事件,可以写成下面这样。

    var a = require('./a');
    a.on('ready', function() {
      console.log('module a is ready');
    });

    exports变量

    为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令。

    var exports = module.exports;

    造成的结果是,在对外输出模块接口时,可以向exports对象添加方法。

    exports.area = function (r) {
      return Math.PI * r * r;
    };
    
    exports.circumference = function (r) {
      return 2 * Math.PI * r;
    };

    注意,不能直接将exports变量指向一个值,因为这样等于切断了exportsmodule.exports的联系。

    exports = function(x) {console.log(x)};

    上面这样的写法是无效的,因为exports不再指向module.exports了。

    下面的写法也是无效的。

    exports.hello = function() {
      return 'hello';
    };
    
    module.exports = 'Hello world';

    上面代码中,hello函数是无法对外输出的,因为module.exports被重新赋值了。

    这意味着,如果一个模块的对外接口,就是一个单一的值,不能使用exports输出,只能使用module.exports输出。

    module.exports = function (x){ console.log(x);};

    如果你觉得,exportsmodule.exports之间的区别很难分清,一个简单的处理方法,就是放弃使用exports,只使用module.exports

    来自:http://javascript.ruanyifeng.com/nodejs/module.html

  • 相关阅读:
    Jzoj5408 Dark
    Jzoj5407 Deep
    Jzoj5407 Deep
    Jzoj5456【NOIP2017提高A组冲刺11.6】奇怪的队列
    Jzoj5456【NOIP2017提高A组冲刺11.6】奇怪的队列
    Jzoj5455【NOIP2017提高A组冲刺11.6】拆网线
    Codeforces Round #621 (Div. 1 + Div. 2)C
    Codeforces Round #621 (Div. 1 + Div. 2)B Cow and Friend
    PAT甲级——A1031 Hello World for U
    PAT甲级——A1029 Median
  • 原文地址:https://www.cnblogs.com/xiaofenguo/p/6697516.html
Copyright © 2020-2023  润新知