zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    [Luogu1993] 小K的农场
    [Noip2013] 车站分级
    [Noip2003]加分二叉树
    [Luogu3797] 妖梦斩木棒
    UPC 6616 Small Mulitple
    STL容器之优先队列
    Dijkstra和Floyd算法
    最短路径问题---Dijkstra算法详解
    并查集
    洛谷 P1217
  • 原文地址:https://www.cnblogs.com/PrimerPlus/p/12974381.html
Copyright © 2011-2022 走看看