JS中require与import的区别及说明

作者:异步漫步时间:2026-10-25 21:57:17浏览:411

本文详细解析JavaScript中require与import的核心区别。从历史起源看,require源于Node.js的CommonJS规范,而import属于ES6标准。两者在加载机制上存在本质差异:CommonJS为运行时动态加载,返回对象拷贝;ES6模块采用静态分析,编译时确定依赖,支持只读视图。文章还对比了导出语法、Webpack环境下的行为及动态导入的实现方式,帮助开发者根据场景选择合适方案。

require和import的区别

起源

在ES6诞生之前,JavaScript语言本身缺乏标准的模块系统,甚至连CSS都支持@import指令。这种缺失对于开发复杂的大型项目构成了显著阻碍。

ES6于2015年6月正式发布,因此也被称为ES2015。在官方标准出台之前,社区已经提供了模块解决方案,即Node.js环境下的实现。

至此可以看出两者的起源:ES6标准中用于模块导入的关键字是import,而Node.js提供的解决方案使用的关键字是require。

Node.js由Ryan Dahl于2009年发布。Node.js采用的模块化方案称为CommonJS。虽然Node.js主要面向服务端开发,但随着技术发展,许多前端框架也开始依赖Node.js的相关机制。

导出命令/引入命令

要正确使用require或import,首先需了解对应的导出方式。下文将分别以CommonJS和ES6来区分这两种解决方案。

CommonJS

导出变量、方法及对象。

// testcommonjs.js
exports.a = 123;
exports.b = 'hello';
exports.c = function(){
  console.log('ccc')
}
exports.d = {
  foo: 'bar'
}
//等价=> 
module.exports.a = 123;
module.exports.b = 'hello';
//等价=> 
module.exports = {
  a:123,
  b:'hello',
  c:function(){
    console.log('ccc')
  },
  d:{
    foo:bar
  }
}

建议使用module.exports,单独使用exports在某些情况下可能引发意外错误,这并非本文讨论重点。

引入和使用

//index.js
var test = require('./testcommonjs')
console.log(test.a)
console.log(test.b)
test.c()
console.log(test.d.foo)

ES6

导出变量、方法及对象(此处仅列举常用方法,具体用法请参考阮一峰的ES6入门文档)。

//testesmodule.js
export var a = 123
export var b = 'hello'
export function c(){
  console.log('ccc')
}
export var d = {
  foo: 'bar'
}

引入和使用

import { a,b,c,d } from './testesmodule'
console.log(a)
console.log(b)
c()
console.log(d.foo)
//等价=> 
import * as test form './testesmodule'
console.log(test.a)
console.log(test.b)
test.c()
console.log(test.d.foo)

静态优化

这一概念源自阮一峰的文档,文中以Node核心模块fs为例进行说明。

ES6

// ES6模块
import { stat, exists, readFile } from 'fs';

注意:请勿在未配置Babel的项目中测试上述代码,因为Node.js目前仍不支持ES6的模块化语法(笔者当前Node版本为v10.15.0),尽管它已实现大部分ES6特性。

CommonJS

// CommonJS模块
let { stat, exists, readFile } = require('fs');

看似ES6与CommonJS中fs模块的引入方式仅是语法差异,但实际上,CommonJS的处理方式如下。

let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

也就是说,为了使用fs中的stat、exists、readFile方法,代码执行时必须将整个fs模块加载进来,生成一个对象_fs,再从中读取三个方法。这种加载方式被称为“运行时加载”,因为只有运行时才能获取该对象。

ES6模块的设计思想是尽可能静态化,使得在编译时就能确定模块的依赖关系以及输入输出的变量。从这个角度看,ES6模块化的效率远高于CommonJS。阮一峰的文档中还列举了静态加载的其他优点,但本文作者表示难以完全理解。

新的思考:

fs是Node.js的核心模块,为何ES6模块化语法能生效?通过ws中的文件定位发现,Node.js核心模块代码全由TypeScript编写。由于对TS语法不熟悉,尚无法理解TS如何做到既兼容CommonJS又兼容ES6。

(com)require和import,动态和静态

require和import的区别问题

require用于读取并执行JS文件,并返回该模块的exports对象;若未指定模块,则会报错。CommonJS规范加载模块是同步且动态的,只有加载完成后,才能执行后续操作,且可在代码任意位置引入。

import用于引入外部模块、其他脚本等的函数、对象或基本类型。

import属于ES6命令,与require不同,它会生成外部模块的引用而非直接加载模块,直到真正使用该模块中的值时才会进行加载。

动态引入和静态引入

Webpack支持Node的CommonJS标准,且其require实现与Node极为类似;因此将Node的require与Webpack的require放在一起讲解:

此外,由于Vue使用了Webpack,所以在Vue项目中也可以使用Webpack的require;

require是动态引入,因为是运行时调用,可以放置在代码的任何位置。

使用Webpack的require需注意:

let url = "@/assets/images/carousel/logo.svg"
require(url)    //报错
let url = "logo.svg"
require("@/assets/images/carousel/"+url); //正确

不能直接给require变量,要给require一个初始的地址,具体的文件名给变量,以方便遍历

而import支持静态引入和动态引入两种:

1.静态引入

import { a, b, c } from "./a";

2.动态引入

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}

PS1:区分静态和动态

静态是按照文件的嵌套关系找到文件或者分析代码,不需要运行

动态与执行顺序有关,会在执行的过程中根据变化进行一些操作

PS2:node中两种导出方式的区别

1.置换exports整个对象

module.exports = {}   
const lib = require("xxx")

2.不置换,只是编辑exports,加属性,这个aaa就是key

exports.aaa === module.exports.aaa
exports.aaa = 123
const {aaa} = require("xxx")

无论时哪种,最后返回的都是exports对象,都可以通过键值从里边拿值

PS3:ES6中两种导出方式的区别

1.export

export   func1=()=>{}
export   func2=()=>{}
import { func1, func2 } from 'xxx';

2.export default

export default class Example{}
import Example from "xxx"

以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。

作者最新文章