zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    SQL Azure (17) SQL Azure V12
    Microsoft Azure News(5) Azure新DV2系列虚拟机上线
    Azure Redis Cache (3) 在Windows 环境下使用Redis Benchmark
    Azure PowerShell (11) 使用自定义虚拟机镜像模板,创建Azure虚拟机并绑定公网IP(VIP)和内网IP(DIP)
    Windows Azure Virtual Machine (31) 迁移Azure虚拟机
    Windows Azure Web Site (16) Azure Web Site HTTPS
    Azure China (12) 域名备案问题
    一分钟快速入门openstack
    管理员必备的Linux系统监控工具
    Keepalived+Nginx实现高可用和双主节点负载均衡
  • 原文地址:https://www.cnblogs.com/xiaofenguo/p/6697516.html
Copyright © 2011-2022 走看看