ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaScript中的(模块化)导入与导出

2022-01-08 23:02:16  阅读:277  来源: 互联网

标签:lib 模块化 JavaScript module js say 导入 value sm


JavaScript是没有作用域(局部)和命名空间这一概念的,而JavaScript又是脚本(解释型)语言,当js引擎在解析它时,将其放在「一起」自上而下开始解释(生成ast,然后生成字节码,最后编译成机器码),这就在解释时会遇到一个显然的问题:符号覆盖(symbol overhead)「在编译型语言中就是符号冲突,符号冲突在编译时就会报错,而符号覆盖并没有任何错误提示,能正常解释执行,显然这是无法接受的」

因此,在工程实践中,JavaScript的模块化就显得十分必要。

在没有模块化的JS世界中:

//index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>demo</title>

		<script src="alex.js" type="text/javascript"></script>
		<script src="lib.js" type="text/javascript"></script>
				
	</head>
	<body>
	</body>
</html>

//lib.js
let value = 'value'
//bob.js
alert(value)

bob.js中显然没有定义过变量value,但是能正常输出变量值value,这是因为在index.html中先加载了alex.js文件后加载的bob.js文件,因为js并没有命名空间这一概念,所以能正常输出(等价于将所有js文件集中到同一个文件中)。

显然,这样是无法展开正常的编码的,各个文件(模块)无法做到有效隔离(全是各种变量污染)

(于是各种骚操作就来了...)

//lib.js
let mod = (function () {
	
	let mod = {}
	mod.value = 'value'
	mod.say_sm = function(){
		alert('say sm')
	}
	return mod
	
})()
//bob.js
alert(mod.value)
mod.say_sm()

正常输出valuesay sm

直接在lib.js中返回一个对象mod,JavaScript中是存在函数作用域的,所以通过立即调用函数,返回一个对象,这样其他js文件就能直接使用这个对象了。(在这个立即调用函数内部可以定义各种变量和函数,直接将其给到这个mod对象即可),这是个一个妥协的方式,本质上并没有避免变量污染(mod这个变量有可能污染其他js文件中的同名变量mod),并且在html文件中存在先后依赖关系(被依赖的文件必须先被加载),这在存在大量js文件的情况下...

JavaScript自诞生起直到2015年都不支持模块化,直到ES6标准时才在语言层面支持模块化,而此前业界通常采用制定「行业规范」的方式来「实现(模拟)」模块化(module)。

  • 模块化规范
  • 语言的支持

业界流行的规范为CommonJS,这份规范被实现得完整通用。

ES6对模块化的支持

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>demo</title>

		<script src="lib.js" type="module"></script>
		
		<script src="bob.js" type="module"></script>
		
	</head>
	<body>
	</body>
</html>

//lib.js
let value = 'value'
function say_sm(){
	
	alert('say sm')
}

export{
	value,
	say_sm
}
//bob.js
import {value,say_sm} from './module/lib04.js'
alert(value)
say_sm()

如上所示,ES6中引入2个关键字来支持模块化,importexport,这是js的关键字而非函数,作用于js 的解释期(AST),而非运行期。(因此不能支持条件导入)

let flag = 1
if(flag == 1){
  import {value,say_sm} from './module/lib04.js'
}
//解释期报错,因为if条件需要等到执行期才能判断,在编译为AST时是无法判断的,而import在编译期就要开始生成代码。故直接parse语法错误

nodejsCommonJS的支持

//lib.js
let value = 'value'
function say_sm(){
    console.log(value)
}

module.exports.value = value
module.exports.say_sm = say_sm
//bob.js
const lib = require('./lib.js')
console.log(lib.value)
lib.say_sm()

以上就是nodejs中的模块化支持(非语言层面的支持),其中,每个js文件就是一个模块,在nodejs中,有一个全局对象module,它是Module类的一个实例,这个实例有一个属性,exports,在也是一个对象,在module实例被创建时默认初始化为{}(一个无属性的对象)(为了「彻底」支持commonjs规范,module实例中还有一个属性exports,这个值被直接赋值为module.exports,即exports = module.exports

函数require直接返回一个对象,这个对象并非一个新对象,而是直接返回lib.js模块中的对象module中的属性(对象)exports

image.png

所以,nodecommonjs的支持本质还是在做「对象共享」这一件事。

一个js文件被加载时,node便实例化了一个module对象,然后创建了一个对象exports对象

let module = new Module()
module.exports = {}

这个module.exports对象位于堆内存的某个地址处address_x

当其他模块引用lib.js时(require),直接返回address_x地址值(对象)

image.png

其他js模块require同一个lib.js时,本质是在共享module.exports对象,因此,任何一个模块对exports对象的修改都会反应到其他js文件中

//bob.js
const lib = require('./lib.js')
lib.value = 'bob'
//在其他js文件中require('./lib.js'),value的值也被修改为bob

ES6中对模块的支持则不存在这一问题,其机制并非通过共享对象来实现的,而是通过Binding Env Block机制来AST期间实现

image.png

以上,就是基本的Js中的导入与导出

标签:lib,模块化,JavaScript,module,js,say,导入,value,sm
来源: https://www.cnblogs.com/frankfankk/p/15779928.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有