• Node.js模块系统入门


    在编程领域中,模块是自包含的功能单元,可以跨项目共享和重用。它们使开发人员的生活更加轻松,因为我们可以使用它来增加应用程序的功能,而不必亲自编写这些功能,它还让我们可以组织和解耦代码,从而使应用程序更加容易理解、调试和维护。

    那么如何使用Node.js中的模块呢,下面主要介绍如何导出和导入

    不同的模块格式

    由于JavaScript最初没有模块的概念,随着时间的推移出现了各种相互竞争的格式。以下是主流的几种格式:

    • Asynchronous Module Definition (AMD) 格式, 用于浏览器端,使用 define 函数定义模块。
    • CommonJS (CJS) 格式,用于 Node.js,使用 require 和 module.exports 定义依赖和模块。
    • ES Module (ESM) 格式。从 ES6 (ES2015)开始,JavaScript 支持原生模块格式。它使用 export 关键字导出模块的公开 API,并用 import 关键字导入。
    • System.register 格式被设计用于在ES5 中 支持 ES6 模块。
    • Universal Module Definition (UMD) 格式,在浏览器和 Node.js 中都可以使用。当模块需要被多种模块加载程序导入时,这个很有用。

    本文只讨论 CommonJS 格式 ,因为它是Node.js 中的标准格式。如果想深入了解其它格式,推荐阅读 这篇文章

    加载模块

    Node.js 有一系列的 内置模块 ,我们在代码中无需安装便可使用。为此,需要使用 require 关键字加载这个模块,并把它赋值给一个变量。这样就可以调用模块暴露的任何方法了。

    例如,要列出目录的内容,你可以使用 文件系统模块 的 readdir 方法:

    'use strict';
    
    const fs = require('fs');
    
    const floderPath = "E:\CSharp\ClassesAndStructs";
    
    fs.readdir(folderPath, (err, files) => {
        if (err) {
            return console.error(err);
        } 
        
        files.forEach(file => console.log(file));
    });
    

    注意,在CommonJS里,模块是按照出现的顺序同步加载和处理的

    创建和导出模块

    如何创建模块并导出,以便在程序的其它地方使用。创建user.js文件,并添加如下内容

    // user.js
    const getName = () => return 'Unity';
    
    module.exports.getName = getName;
    

    然后在同一目录中创建一个index.js文件,并添加以下内容:

    // index.js
    const user = require('./user');
    
    console.log(`User: ${user.getName()}`);
    

    在命令行中使用node index.js运行程序, 可以在控制台中看到以下内容

    User: Unity
    

    这里发生了什么呢? 在user.js 文件中,定义了一个 getName 函数,然后使用 exports 关键字使其可以在其它地方导入。然后是在 index.js 文件中,导入这个方法并执行它。还要注意的是在 require 语句中,模块名字加了前缀 ./ ,因为它是本地文件。另外就是不需要加文件扩展名。

    导出多个方法和值

    可以用同样的方式导出多个方法和值

    // user.js
    const getName = () => return 'Unity';
    
    const getLocation = () => return 'China';
    
    const dateOfBirth = '12.01.1992';
    
    module.exports.getName = getName;
    module.exports.getLocation = getLocation;
    module.exports.dateOfBirth = dateOfBirth;
    
    // index.js
    const user = require('./user');
    
    console.log(`${user.getName()} lives in ${user.getLocation} and was born on ${user.dateOfBirth}`);
    

    上面代码运行的结果如下

    Unity lives in China was born on 12.01.1992.
    

    注意,导出的 dateOfBirth 变量可以指定任何想要的名称(如value )。它不必与原来的变量名相同。

    多种语法形式

    可以在中途导出方法和值,并不一定要在文件末尾

    例如:

    module.exports.getName = () => return 'Unity';
    
    module.exports.getLocation = () => return 'China';
    
    const dateOfBirth = '12.01.1992';
    
    module.exports.dateOfBirth = dateOfBirth;
    

    解构赋值 可以根据需要选择性导入如

    const { getName, dateOfBirth } = require('./user');
    
    console.log(`${getName()} was born on ${dateOfBirth}`);
    

    如你所料,这将会输出以下内容:

    Unity was born on 12.01.1992
    

    导出默认值

    在上面的例子中,分别导出了函数和值。这对于整个应用程序都需要的辅助函数来说是很方便的,但是当模块只导出单个对象时,通常使用module.exports

    // user.js
    class User {
        constructor(name, age, email) {
            this.name = name;
            this.age = age;
            this.email = email;
        }
        getUserStats() {
            return `
    			Name: ${this.name}
    			Age: ${this.age}
    			Email: ${this.email}
    		`;
        }
    }
    
    module.exports = User;
    
    // index.js
    const User = require('./user');
    
    const unity = new User('Unity', 28, 'Unity@example.com');
    
    console.log(unity.getUserStats());
    

    上面的代码输出以下内容:

    Name: Unity
    Age: 28
    Email: Unity@example.com
    

    module.exports和exports的区别是什么

    可能会遇到以下的写法:

    module.exports = {
        getName: () => return 'Unity',
        
        getLocation: () => return 'China',
        
        dateOfBirth: '12.01.1992'
    };
    

    这里要把导出的函数和值赋给module的exports属性--这是可以的

    const { getName, dateOfBirth } = require('./user');
    
    console.log(`${getName()} was born on ${dateOfBirth}`);
    

    那么, module.exports 和 exports 之间的区别到底是什么呢?后者只是个别名吗?

    为了验证这个疑问, 更改index.js中代码如下所示:

    console.log(module);
    

    运行程序,输入以下内容:

    Module {
      id: '.',
      path: 'D:\NodejsApp\middleware\Module',
      exports: {},
      parent: null,
      filename: 'D:\NodejsApp\middleware\Module\app.js',
      loaded: false,
      children: [],
      paths: [
        'D:\NodejsApp\middleware\Module\node_modules',
        'D:\NodejsApp\middleware\node_modules',
        'D:\NodejsApp\node_modules',
        'D:\node_modules'
      ]
    }
    

    可以看到, module 有一个 exports 属性。再往index.js文件中加点料:

    // index.js
    exports.foo = 'foo';
    console.log(module);
    

    运行程序将会出现以下内容:

    Module {
      id: '.',
      path: 'D:\NodejsApp\middleware\Module',
      exports: { foo: 'foo' },
      parent: null,
      filename: 'D:\NodejsApp\middleware\Module\app.js',
      loaded: false,
      children: [],
      paths: [
        'D:\NodejsApp\middleware\Module\node_modules',
        'D:\NodejsApp\middleware\node_modules',
        'D:\NodejsApp\node_modules',
        'D:\node_modules'
      ]
    }
    

    给 exports 添加属性,也会添加到 module.exports 。这是因为 exports 是 module.exports 的一个引用。

    那么,究竟应该用哪个呢?

    既然 module.exports 和 exports 都指向同一个对象,使用哪一个通常都是无关紧要。例如:

    exports.foo = 'foo';
    module.exports.bar = 'bar';
    

    这段代码将会使模块的导出对象变成 { foo: 'foo', bar: 'bar' }

    这里有个需要注意的地方, 赋值给 module.exports 的内容将成为模块导出的值

    exports.foo = 'foo';
    module.exports = () => console.log('bar');
    

    **这将只会导出一个匿名函数, foo 变量会被忽略**

    References

    1. Node.js - module object
    2. Node.js - module.exports
    3. Node.js - exports vs module.exports
  • 相关阅读:
    [置顶] windows player,wzplayerV2 for windows
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    ffmpeg for ios 交叉编译 (支持i686 armv7 armv7s) 包含lame支持
    编译cegcc 0.59.1
    wzplayer 近期将会支持BlackBerry和WinPhone8
    wzplayerEx for android(真正硬解接口,支持加密的 player)
    windows player,wzplayerV2 for windows(20140416)更新
    编译cegcc 0.59.1
  • 原文地址:https://www.cnblogs.com/PrimerPlus/p/12974381.html
Copyright © 2020-2023  润新知