本文介绍: CommonJS规范中,建议尽量都用 module.exports 导出然后require导入 ES6规则中,大部分风格建议模块中最好在末尾一个export导出所有的接口module.exports / exports: 只有 Node 支持的导出require: Node 和 ES6 都支持引入export / import : 只有ES6 支持的导出引入

目录

export和module.exports

**exports **返回的是模块函数

**module.exports **返回的是模块对象本身,返回的是一个类

关键字

模块规范

CommonJS模块规范

module.exports 和 exports

require

ES6模块规范

export 和 export default

import

Node为何支持export / import

总结


exportmodule.exports

         (注意:前面export没有s”,后面的module.exports 有“s”)

使用两者根本区别

**exports **返回的是模块函数

**module.exports **返回的是模块对象本身,返回的是一个

使用上的区别
exports的方法可以直接调用
module.exports需要new对象之后才可以调用

关键字

js编程中经常会有模块的导出导入,涉及到一些导入导出关键字

因为在实际开发中经常会混淆这些用法,所以想要弄清楚这些的区别,让自己明白自己到底在写什么。本文作为学习笔记输出

模块规范

JS模块化编程分了两种规范:CommonJS模块规范和ES6模块规范

在Node.js编程中,Node模块系统遵循的是CommonJS规范。

CommonJS模块规范

CommonJS规范规定: 每个js文件就是一个模块,有自己作用域
在一个文件里面定义变量函数、类,都是私有的,对其他文件不可见。
如果要暴露给其他程序需要以module.exports导出接口,以require引入模块。

module.exportsexports

module.exports / exports: 只有 Node 支持的导出
模块导出的时候,导出的是module.exports,不是exports
module.exports可以导出所有的类型对象函数字符串数值等。

每一个js文件通过node执行时,都自动创建一个module变量和一个exports变量
module变量代表当前模块。这个变量是一个对象,同时,module对象会创建一个叫exports的属性(即module.exports),该属性初始化的值是 {},是对外的接口。加载某个模块,其实加载该模块的module.exports属性。

//logtes.js
console.log("我是外部js,没有使用export")
console.log(module)

执行node test1.js的打印结果

 path: 'C:\Users\xxwang\Documents\pmms\TS\tsdemo\day01',               
  exports: {},                                                                    
  filename: 'C:\Users\xxwang\Documents\pmms\TS\tsdemo\day01\logtes.js',
  loaded: false,                                                                  
  children: [],                                                                   
  paths: [                                                                        
    'C:\Users\xxwang\Documents\pmms\TS\tsdemo\day01\node_modules',     
    'C:\Users\xxwang\Documents\pmms\TS\tsdemo\node_modules',            
    'C:\Users\xxwang\Documents\pmms\TS\node_modules',                    
    'C:\Users\xxwang\Documents\pmms\node_modules',                        
    'C:\Users\xxwang\Documents\node_modules',                              
    'C:\Users\xxwang\node_modules',                                         
    'C:\Users\node_modules',                                                    
    'C:\node_modules'                                                            
  ]                                                                               
}                                                                                 

Process finished with exit code 0

默认exports变量是对module.exports的引用,即exports和module.exports指向同一个内存块。 这等同在每个模块头部,有一行这样的命令

var exports = module.exports;
  • 当通过exports去改变内存块里内容时,module.exports的值也会改变
  • 当通过module.exports去改变内存块里内容时,exports的值也会改变
  • 当module.exports被改变的时候,exports不会被改变
  • 当exports被改变的时候,module.exports不会被改变

所以,exports属性的出现应该可以直接向exports对象添加方法,从而方便对外输出模块接口。不过当module.exports改变时,exports与module.exports也就断开链接,所以最好不要采用这种方式统一采用module.exports方式

// module_export_demo.js
module.exports.a = 100
console.log("log1: " + exports.a)  // log1: 100

exports.a = 200; 
console.log("log2: " + module.exports.a)  // log2: 200

module.exports = "hello"
console.log("log3: " + JSON.stringify(exports)) // log3: {"a":200}
复制代码

module.exports可以导出所有的类型。对象,函数,字符串数值等。 语法示例

// module_export_demo2.js
var x = 5

var str = "hello"

var addX = function (value) {
  return value + x
};

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

// module.exports.x = x
// module.exports.str = str
// module.exports.addX = addX
// module.exports.Point = Point

module.exports = {
  x: x,
  str: str,
  addX: addX,
  Point: Point
}

// require时对比下两种方式x的值到底取哪个
exports = {
  x: 10,
}
复制代码

require

requirer用于加载模块,是node的一个全局方法,使用非常简单

const xxx = require("模块名")
复制代码

读入并执行一个JavaScript文件返回模块的exports对象。如果没有发现指定模块,会报错

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文件

因为模块导出的实际是module.exports,所以require只能看到通过 module.exports 导出的内容,看不到通过exports导出的内容。它相当于module.exports的传送门,module.exports后面的内容是什么,require的结果就是什么,对象、数字字符串、函数…再把require的结果赋值给某个变量针对上面的 module_export_domo2.js 文件,引入模块示例

// node require_demo2.js
const demo2 = require("./module_export_demo2")

console.log(demo2.x)  // 5 也证明了引入的是module.export的内容
console.log(demo2.str)  // hello
console.log(demo2.addX(15)) // 20  = 5 + 15 

let point = new demo2.Point(3, 4)
console.log(point.toString()) //  (3, 4)
复制代码

require 是运行时的,其参数可以是表达式

let value = 2
const demo2 = require("./module_export" + "_demo" + value)
复制代码

require函数加载模块

  1. require函数加载模块顺序按照其在代码中出现的顺序

  2. require函数加载模块是同步的,只有加载完成,才能执行后面的操作

  3. require函数加载的模块是被输出的值的拷贝,不会受到模块内容变化影响

     // module_export_demo3.js
     var counter = 3;
     function incCounter() {
       counter++;
     }
     module.exports = {
       counter: counter,
       incCounter: incCounter,
     };
    复制代码
    
     const demo3 = require("./module_export_demo3")
     console.log(demo3.counter);  // 3
     demo3.incCounter();
     console.log(demo3.counter); // 3
    复制代码
    

    counter输出结果说明module_export_demo3模块内部的变化就影响不到counter了

  4. 模块第一次被加载时会执行一次,后续被加载时不会再执行,都是从缓存获取

    // module_export_demo3.js
    console.log("hello")
    module.exports = "wrold"
    复制代码
    
    const demo3 = require("./module_export_demo3")
    const demo3_1 = require("./module_export_demo3")
    const demo3_2 = require("./module_export_demo3")
    const demo3_3 = require("./module_export_demo3")
    const demo3_4 = require("./module_export_demo3")
    const demo3_5 = require("./module_export_demo3")
    console.log(demo3)
    console.log(demo3_1)
    
    // hello
    // wrold
    // wrold
    复制代码
    

    hello只会被打印一次说明console.log(“hello”)语句只执行了一次,module_export_demo3.js只被加载了一次

ES6模块规范

ES6发布的module并没有直接采用CommonJS,甚至连require都没有采用,也就是说require仍然只是node的一个私有的全局方法,module.exports也只是node私有的一个全局变量属性,跟标准什么关系没有
ES6模块规范是,在创建JS模块时,export 语句用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们。

export 和 export default

ES6模块导出有两种方式:export(命名导出) 和 export default(默认导出)。 在导出多个值时,命名导出非常有用。在导入时,必须使用相应对象的相同名称。但是,可以使用任何名称导入默认导出。

export语法介绍

// 导出单个特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}

// 导出列表
export { name1, name2, …, nameN };

// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };

// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// 导出"引入模块的导出值"
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export * from …; // 导出"引入模块的所有导出值",不包括模块的默认导出值
export { default } from …; // 导出"引入模块的默认导出值"
复制代码
  • export与export default均可用于导出常量、函数、文件、模块等
  • 通过export方式导出,在导入时要加{ },export default则不需要
  • 在一个文件中,export可以有多个,export default仅有一个
  • 部分风格建议,模块中最好在末尾用一个export导出所有的接口
export 1 // 这种写法错误

// 正确写法
const value = 1
export { value }

// 或者
export const value = 1

// 或者
const value = 1
export default value

// 或者
export default 1
复制代码

export default是别名语法糖,这个语法糖的好处在是

所以如果import的时候,你发现某个变量没有花括号括起来(除了* 号),是因为该变量是通过export default 导出的。

// d.js
// 导出函数
export default function() {}

// 等效于:
// function a() {};
// export {a as default};

复制代码
import a from "d.js" // a 是 {defalut as a}的替代写法。
复制代码

所以使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名

// a.js
let sex = "boy";
export default sex //sex不能加大括号 等价于 export {sex as default}
复制代码

本质上,a.js文件的export default输出一个叫做default的变量,然后系统允许你为它取任意名字。 自然default只能有一个值,所以一个文件内不能有多个export default。

// b.js
import any from "./a.js"
import any12 from "./a.js" 
console.log(any, any12)   // boy,boy
复制代码

import

require 和 import是完全不同的两种概念。require是赋值过程,import是解构过程 const xxx = require(“模块名”) import { xxx } from “模块名”

import {a} from ..
复制代码
import {a as a_a} from ..
复制代码

import介绍语法

import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
var promise = import("module-name"); // 动态模块加载,返回的是一个promise对象
复制代码

Node为何支持export / import

我们经常会看到在node中也会用export / import,这是什么呢? 我们在node中使用babel支持ES6,仅仅是将ES6转码为ES5再执行,import语法会被转码为require。因为目前所有的引擎都还没有实现export / import。
如何让Node.js支持ES6的语法具体参考在node环境中支持ES6代码

// ES6语法
import {a} from "./demo.js"
// 转码ES5后
var _demo = require("./demo.js")
复制代码

这也是为什么在使用module.exports模块导出时,在引入模块时使用import仍然起效,因为本质上,import会被转码为require去执行。

总结

CommonJS规范中,建议尽量都用 module.exports 导出,然后用require导入 ES6规则中,大部分风格建议,模块中最好在末尾用一个export导出所有的接口

  • module.exports / exports: 只有 Node 支持的导出
  • require: Node 和 ES6 都支持的引入
  • export / import : 只有ES6 支持的导出引入

原文地址:https://blog.csdn.net/LlanyW/article/details/130216645

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_37570.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注