模块化

模块化

JavaScript用“共享一切”的方法加载代码,这是该语言中最容易出错且容易令人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域,但在ECMAScript6以前,在应用程序的每一个JavaScript中定义的一切都共享一个全局作用域。随着Web应用程序变得更加复杂,JavaScript代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。ECMAScript6的一个目标是解决作用域问题,也为了使JavaScript应用程序显得有序,于是引进了模块。

什么是模块

模块是自动运行在严格模式下并且没有办法退出运行的JavaScript代码。与共享一切架构相反的是,在模块顶部创建的变量不会自动被添加到全局共享作用域,这个变量仅在模块的顶级作用域中存在,而且模块必须导出一些外部代码可以访问的元素,如变量或函数。模块也可以从其他模块导入绑定。

js模块系统简化史

没有模块 -> CMD(CommonJS Moudle Definition-> AMD(Asynchronous Moudle Definition) -> 语言提供模块支持

使用ES6的模块

1.导出
2.导入
3.webpack编译

//mod1.js -定义模块
export let a=12;
export let b=5;
export let c=6;
//index.js -使用模块
let b=8;

import {a,b as name2} from './mod1';

console.log(a,b,name2);
//wenpack.config.js -编译配置
const path=require('path');

module.exports={
  mode: 'development',
  entry: './js/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js'
  }
};

导出(export)

除了export之外,每一个声明都和原来一模一样,因为导出类和函数需要有一个名称,所以代码中的每一个类和函数都要有名称。除非使用default关键字,否则不能用export导出匿名函数和类

//变量
export let a=12;
export const a=12;

//一堆
let a,b,c=...;
export {a, b, c, ...};

//导出函数
export function show(){
    ...
}

//导出class
export class Person{
    ...
}
导入(import)

从模块中导出的功能可以通过import关键字在另一个块中访问

import { x } from "./xxx"           //导入单个绑定
import { x , x } from "./xxx"       //导入多个绑定
import  *  as xxx from './xxx';     //导入整个模块
//这种导入被称作命名空间导入,模块中得值将被当做模块的属性进行访问
import mod1 from 'xxx';             //引入default成员

模块语法的限制
export和import的一个重要的限制是,它们必须在其他语句和函数之外使用。例如,下面代码会给出一个语法错误:

if(flag){
    export flag;
    //语法错误
}

export语句不允许出现在if语句中,不能有条件导出或以任何方式动态导出。模块语法存在的一个原因是要让JavaScript引擎静态地确定哪些可以导出。因此,只能在模块顶部使用export。
同样,不能在一条语句中使用import,只能在顶部使用它。

导入绑定的一个微妙怪异之处
ES6的import语句为变量、函数利类创建的是只读绑定,而不是正常变量一样简单地引用原始绑定。标识符只有在被导出的模块中可以修改,即便是导入绑定的模块也无法更改绑定的值。例如,假设我们想使用这个模块;

//mod.js
export var name  = "yutingbai";
export function setName(newName){
    name = newName;
}

当导入这两个绑定后,setNameO函数可以改变name的值:

import {name ,setName} from './mod'

console.log(name);      //yutingbai
setName('baoxiaohai')
console.log(name)       //baoxiaohai

调用setName(“xxx”)时会回到导出setName()的模块中去执行,并将name设置为“xxx”。请注意,此更改会自动在导入的name绑定上体现。其原因是,name是导出的name标识符的本地名称。本段代码中所使用的name和模块中导入的name不是同一个。

导入和导出时的重命名

导出时指定函数的名称

    function fun1(x,x){
        ...
    }
    export {fun1 as fun2};
import { fun2 } from './xx'

引入时指定函数的名称

import { fun2 as fun3 } from './xx'
模块中的默认值

由于在诸如CommonJS的其他模块系统中,从模块中导出和导入默认值是一个常见的做法,该语法被进行了优
化。模块的默认值指的是通过default关键字指定的单个变量、函数或类,只能为每个模块设置一个默认的导出值,导出时多次使用default关键字是一个语法错误。
导出

//导出一个函数作为模块的默认值
export default function(){
    ...
}


//也可以在default之后添加默认导出的模块
function lala(x,x){
    ...
}
export default lala;

//也可以用重命名的方法为默认导出值指定标识符
function lala(x,x){
    ...
}
export  {lala as default};

引入

import xx from './xx'
无绑定导入

某些模块可能不导出任何东西,相反,它们可能只修改全局作用域中的对象。尽管模块中的顶层变量、函数和类不会自动地出现在全局作用域中,但这并不意味着模块无法访问全局作用域。内建对象(如Array和object)的共享定义可以在模块中访问,对这些对象所做的更改将反映在其他模块中。

加载模块

虽然ECMAScript6定义了模块的语法,但它并没有定义如何加载这些模块。这正是规范复杂性的一个体现,应由不同的实现环境来决定。ECMAScript6没有尝试为所有JavaScript环境创建一套统一的标准,它只规定了语法,并将加载机制抽象到一个未定义的内部方法HostResolveImportedModule中。Web浏览器和Node.js开发者可以通过对各自环境的认知来决定如何实现HostResolveImportedModule。

在web浏览器中使用模块

  • <script>元素中通过src属性指定一个加载代码的地址来加载JavaScript代码文件。
  • 将JavaScript代码内嵌到没有src属性的<script>元素中。
  • 通过Web Worker或Service Worker的方法加载并执行JavaScript代码文件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值