The difference between export and module.exports of JavaScript module export and import

export和module.exports

(Requires that the previous export does not have "s", and the latter module.exports has "s")

The fundamental difference between using the two is

**exports ** returns the module function

**module.exports ** returns the module object itself, and returns a class

The difference in use is that
the exports method can be called directly
after the module.exports needs a new object.


 

In js programming, there are often module export and import, involving some import and export keywords

  • export keywords
    • module.exports
    • exports
    • export
    • export default
  • import keywords
    • require
      • const xxx = require("module name")
    • import
      • import { xxx } from "module name"
      • import xxx from "module name"
      • import xxx1, {xxx2, xxx3,...} from "module name"
      • import * from "module name"

Because these usages are often confused in actual development, I want to figure out the differences and let myself understand what I am writing. This article is output as study notes.

module specification

JS modular programming is divided into two specifications: CommonJS module specification and ES6 module specification.

  • CommonJS module specification - in the CommonJS specification, the interface is exported with module.exports, and the module is imported with require
  • ES6 module specification - in the ES6 standard specification, the interface is exported with the export command, and the module is imported with the import

In Node.js programming, the Node module system follows the CommonJS specification.

CommonJS Module Specification

The CommonJS specification stipulates that each js file is a module and has its own scope.
Variables, functions, and classes defined in a file are all private and invisible to other files.
If you want to expose it to other programs, you need to export the interface with module.exports and import the module with require.

module.exports 和 exports

module.exports / exports: Only export supported by Node
When a module is exported, it exports module.exports instead of exports.
module.exports can export all types. Objects, functions, strings, numbers, etc.

When each js file is executed by node, a module variable and an exports variable are automatically created.
The module variable represents the current module. This variable is an object. At the same time, the module object will create a property called exports (that is, module.exports). The initial value of this property is {}, which is an external interface. Loading a module is actually loading the module.exports property of the module.

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

The print result of executing 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

The default exports variable is a reference to module.exports, that is, exports and module.exports point to the same memory block. This is equivalent to having a line of such commands at the top of each module.

var exports = module.exports;
  • When the content in the memory block is changed through exports, the value of module.exports will also change
  • When the content in the memory block is changed through module.exports, the value of exports will also change
  • exports are not changed when module.exports is changed
  • module.exports will not be changed when exports are changed

Therefore, the appearance of the exports attribute should be able to directly add methods to the exports object, so as to facilitate the external output of the module interface. However, when module.exports changes, the link between exports and module.exports will be disconnected, so it is best not to use this method, and use the module.exports method uniformly.

// 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 can export all types. Objects, functions, strings, numbers, etc. Syntax example:

// 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 is used to load modules and is a global method of node, which is very simple to use

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

Read and execute a JavaScript file, and return the module's exports object. If the specified module is not found, an error will be reported.

The require method accepts the following parameters:

  • Native modules, such as http, fs, path, etc.
  • File modules with relative paths, such as ./mod or ../mod
  • Absolute path to the file module, such as /pathtomodule/mod
  • Third-party modules, such as koa, etc.

There is usually a package.json file in the module directory, and the entry file is written into the main field

    // package.json
    { "name" : "some-library",
      "main" : "./lib/some-library.js" }
复制代码

After require finds that the parameter string points to a directory, it will automatically check the package.json file of the directory, and then load the entry file specified by the main field.
If the package.json file has no main field, or there is no package.json file at all, the index.js file or index.node file in this directory will be loaded

Because what the module exports is actually module.exports, require can only see the content exported through module.exports, but not the content exported through exports. It is equivalent to the portal of module.exports, what is the content behind module.exports, what is the result of require, object, number, string, function... and then assign the result of require to a variable. For the above module_export_domo2.js file, import the module example

// 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 is runtime and its argument can be an expression

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

The require function loads the module

  1. The require function loads modules in the order in which they appear in the code

  2. The require function loads the module synchronously, and only after the loading is complete can the following operations be performed

  3. The module loaded by the require function is a copy of the output value and will not be affected by changes in the module content

     // 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
    复制代码
    

    The counter output results show that the internal changes of the module_export_demo3 module will not affect the counter

  4. The module will be executed once when it is loaded for the first time, and will not be executed when it is loaded later, all of which are obtained from the cache

    // 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 will only be printed once, indicating that the console.log("hello") statement is only executed once, and module_export_demo3.js is only loaded once.

ES6 module specification

The module released by ES6 does not directly adopt CommonJS, not even require, that is to say, require is still only a private global method of node, and module.exports is only a global variable attribute private to node, which has nothing to do with the standard .
The ES6 module specification is that when creating a JS module, the export statement is used to export functions, objects or primitive values ​​from the module so that other programs can use them through the import statement.

export 和 export default

There are two ways to export ES6 modules: export (named export) and export default (default export). Named exports are useful when exporting multiple values. When importing, the same name of the corresponding object must be used. However, the default export can be imported with any name.

Introduction to export syntax

// 导出单个特性
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 …; // 导出"引入模块的默认导出值"
复制代码
  • Both export and export default can be used to export constants, functions, files, modules, etc.
  • Export through export, add { } when importing, export default does not need
  • In a file, there can be multiple exports, and only one export default
  • Most styles suggest that it is best to use an export at the end to export all interfaces in the module
export 1 // 这种写法错误

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

// 或者
export const value = 1

// 或者
const value = 1
export default value

// 或者
export default 1
复制代码

export default is the syntactic sugar of the alias, the advantage of this syntactic sugar is

  • When importing, curly braces {} can be omitted.
  • When importing, you can use any variable name to indicate the imported variable

So if when importing, you find that a variable is not enclosed in curly braces (except the * sign), it is because the variable is exported through export default.

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

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

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

So use the export default command to specify the default output for the module, so that you don't need to know the variable name of the module to be loaded.

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

Essentially, the export default of the a.js file outputs a variable called default, and then the system allows you to give it any name. Natural default can only have one value, so there cannot be multiple export defaults in one file.

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

import

require and import are two completely different concepts. require is the assignment process, import is the deconstruction process const xxx = require("module name") import { xxx } from "module name"

  • import is compiled, and must be placed at the beginning of the file, otherwise an error will be reported
  • The form of import followed by curly braces is the most basic usage, and the variables inside the curly braces correspond to the variables after export one by one.
import {a} from ..
复制代码
  • Support for aliasing variables. Because sometimes two different modules may have the same interface, you can give this variable an alias for easy use in the current file.
import {a as a_a} from ..
复制代码

import introduction syntax

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对象
复制代码

Why Node supports export/import

We often see that export/import is also used in node, what is it? We use babel to support ES6 in node , just transcode ES6 to ES5 and then execute, the import syntax will be transcoded into require. Because currently all engines don't implement export/import yet.
How to make Node.js support ES6 syntax Specific reference Support ES6 code in node environment

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

This is why when using the module.exports module to export, using import when importing the module still works, because in essence, import will be transcoded into require to execute.

Summarize

In the CommonJS specification, it is recommended to use module.exports to export as much as possible, and then use require to import ES6 rules. Most styles suggest that it is best to export all interfaces with an export at the end of the module

  • module.exports/exports: only exports supported by Node
  • require: import supported by both Node and ES6
  • export / import : Only export and import supported by ES6

 

Guess you like

Origin blog.csdn.net/LlanyW/article/details/130216645