The difference between require and import

The modular specifications followed are different

require/exports was born in the wild specification. What is the wild specification? That is to say, these specifications are rules drafted by developers in the JavaScript community and have been recognized by everyone or widely used. Such as CommonJS, AMD, CMD, etc. import/export is a decent one. Included in the new ECMAScript version specified by TC39, ES6 (ES2015). From the specification and implementation definition, require is dynamic loading, and import is static loading. From the perspective of underlying operation, require is parsed when the program is running, while import is parsed when compiling the request package. require is to request the entire Package objects and imports only request the requested parts of the module that are needed. At present, import should only be regarded as the syntax specification of ES6. When packaged with babel, it should be no essentially different from require.

Why can both import and require be used in vue or react?

The reason why you can use the import command in vue or react and start a local server through Node.js without reporting an error is that vue uses babel to compile the ES6 module system and convert it into CommonJS to standardize the latest version
Insert image description here
. Node still uses CommonJS as the module specification, so if you want to use the ES6 module system, you still need babel for the time being.

some specific differences

CommonJS

1. For basic data types, it is a copy. That is, it will be cached by the module. At the same time, the variables output by this module can be reassigned in another module.

// b.js
let count = 1
let plusCount = () => {
    
    
  count++
}
setTimeout(() => {
    
    
  console.log('b.js-1', count)
}, 1000)
module.exports = {
    
    
  count,
  plusCount
}

// a.js
let mod = require('./b.js')
console.log('a.js-1', mod.count)
mod.plusCount()
console.log('a.js-2', mod.count)
setTimeout(() => {
    
    
    mod.count = 3
    console.log('a.js-3', mod.count)
}, 2000)

node a.js
a.js-1 1
a.js-2 1
b.js-1 2  // 1秒后
a.js-3 3  // 2秒后

As can be seen from the above code, the count variable exported by module b is a copying behavior. After the plusCount method is called, the count in the a module is not affected. At the same time, the value in module a can be changed in module b. If you want to synchronize the code, you can export a getter.

// 其他代码相同
module.exports = {
    
    
  get count () {
    
    
    return count
  },
  plusCount
}

node a.js
a.js-1 1
a.js-2 1
b.js-1 2  // 1秒后
a.js-3 2  // 2秒后, 由于没有定义setter,因此无法对值进行设置。所以还是返回2

2. For complex data types, it is a shallow copy. Since the objects referenced by the two modules point to the same memory space, modifications to the value of the module will affect the other module.

// b.js
let obj = {
    
    
  count: 1
}
let plusCount = () => {
    
    
  obj.count++
}
setTimeout(() => {
    
    
  console.log('b.js-1', obj.count)
}, 1000)
setTimeout(() => {
    
    
  console.log('b.js-2', obj.count)
}, 3000)
module.exports = {
    
    
  obj,
  plusCount
}

// a.js
var mod = require('./b.js')
console.log('a.js-1', mod.obj.count)
mod.plusCount()
console.log('a.js-2', mod.obj.count)
setTimeout(() => {
    
    
  mod.obj.count = 3
  console.log('a.js-3', mod.obj.count)
}, 2000)

node a.js
a.js-1 1
a.js-2 2
b.js-1 2
a.js-3 3
b.js-2 3

As can be seen from the above code, it is a shallow copy for the object. When the a module is executed, the value of obj.count is first printed as 1, and then through the plusCount method, it is printed again as 2. Then modify the value of count in module a to 3. At this time, the value in module b is also 3.

3. When a module is loaded using the require command, the code of the entire module will be run.

4. When using the require command to load the same module, the module will not be executed again, but the value in the cache will be obtained. In other words, no matter how many times the CommonJS module is loaded, it will only be run once when it is loaded for the first time. If it is loaded later, the result of the first run will be returned, unless the system cache is manually cleared.

5. When loading in a loop, it is executed during loading. That is, when the script code is require, it will all be executed. Once a module is "loop loaded", only the executed part will be output, and the unexecuted part will not be output.

3, 4, and 5 can be explained using the same example

// b.js
exports.done = false
let a = require('./a.js')
console.log('b.js-1', a.done)
exports.done = true
console.log('b.js-2', '执行完毕')

// a.js
exports.done = false
let b = require('./b.js')
console.log('a.js-1', b.done)
exports.done = true
console.log('a.js-2', '执行完毕')

// c.js
let a = require('./a.js')
let b = require('./b.js')

console.log('c.js-1', '执行完毕', a.done, b.done)

node c.js
b.js-1 false
b.js-2 执行完毕
a.js-1 true
a.js-2 执行完毕
c.js-1 执行完毕 true true

Explain the whole process in detail.

  • Execute c module in Node.js. At this time, the require keyword is encountered and all codes in a.js are executed.
  • After exporting in module a, module b is introduced through require and the code of module b is executed.
  • After exports in module b, module a is introduced via require, and the code of module a is executed at this time.
  • Module a only executes the statement exports.done = false.
  • Go back to module b and print b.js-1, exports, b.js-2. Module b is executed.
  • Go back to module a, and then print a.js-1, exports, b.js-2. module a is executed
  • Go back to the c module, and then execute require. You need to introduce the b module. Since it has been introduced in module a, the value can be output directly.
  • Finish.

It can be seen from the above results and analysis process that when the require command is encountered, the corresponding module code will be executed. When circular references occur, it is possible to output only part of a module's code. When the same module is referenced, it is not loaded again, but cached.

ES6 modules

1. The values ​​in the es6 module belong to [dynamic read-only references]. Just explain the complex data types.
2. For read-only, that is, the value of the imported variable is not allowed to be modified. The imported variable is read-only, whether it is a basic data type or a complex data type. When a module encounters an import command, a read-only reference is generated. When the script is actually executed, the value will be retrieved from the loaded module based on this read-only reference.
3. For dynamics, if the original value changes, the value loaded by import will also change. Whether it is a basic data type or a complex data type.

// b.js
export let counter = {
    
    
  count: 1
}
setTimeout(() => {
    
    
  console.log('b.js-1', counter.count)
}, 1000)

// a.js
import {
    
     counter } from './b.js'
counter = {
    
    }
console.log('a.js-1', counter)

// Syntax Error: "counter" is read-only

Although counter cannot be reassigned to a new object, properties and methods can be added to the object. No error will be reported at this time. This type of behavior is consistent with the usage of the keyword const.

// a.js
import {
    
     counter } from './b.js'
counter.count++
console.log(counter)

// 2

4. When loading in a loop, ES6 modules are dynamically referenced. As long as some reference exists between the two modules, the code will be able to execute.

// b.js
import {
    
    foo} from './a.js';
export function bar() {
    
    
  console.log('bar');
  if (Math.random() > 0.5) {
    
    
    foo();
  }
}

// a.js
import {
    
    bar} from './b.js';
export function foo() {
    
    
  console.log('foo');
  bar();
  console.log('执行完毕');
}
foo();

babel-node a.js
foo
bar
执行完毕

// 执行结果也有可能是
foo
bar
foo
bar
执行完毕
执行完毕

Since there are references between both modules. Therefore it can be executed normally.

Guess you like

Origin blog.csdn.net/xiaoxiannv666/article/details/120952933