es6 阮一峰_ES6---模块加载

ccf4b47c6a58a36519e2bf52275010d1.png

前言

本文主要学习四种模块加载规范:

  • AMD
  • CMD
  • CommonJS
  • ES6 module语法

其中AMD,CMD,CommonJs不会详细学习,只是学习下它们的概念,做一些比较。

想要详细学习的同学可以点击下面的链接:

AMD

CMD

阮一峰CommonJS规范学习

首先AMD和CMD是用于浏览器的模块规范:

AMD和CMD的区别:

1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块

2、CMD推崇就近依赖,只有在用到某个模块的时候再去require

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同:

AMD 是将需要使用的模块先加载完再执行代码,而 CMD 是在 require 的时候才去加载模块文件,加载完再接着执行。

CommonJS 与 AMD

引用阮一峰老师的《JavaScript 标准参考教程(alpha)》:

CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载模块,允许指定回调函数。
由于 Node.js 主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以 CommonJS 规范比较适用。
但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用 AMD 规范。

ES6与CommonJS的差异:

在阮一峰老师的ECMAScript6 教程 中有解释:

它们有三个重大差异。

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
CommonJS 模块的 require()是同步加载模块,ES6 模块的 import命令是异步加载,有一个独立的模块依赖的解析阶段。

第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

下面重点了解的是第一个差异:

CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

example1:

let current = 1;
function addCurrent() {
  current++
}
module.exports = {
  current: current,
  addCurrent: addCurrent
}

//在文件中引入
let num = require('./Democlass.js');
  console.log(num.current) //1
  num.addCurrent();
  console.log(num.current);//1

从上面的例子中我们看到,两次输出的结果是一致的,current的值并未改变,这是为什么呢?

这是因为num.current是一个基本类型的值,会被缓存。

如果按照这种写法我们该怎么获取它改变之后的值呢?

把它写成一个函数,每次返回它的值。

//这里就直接写改变之后的导出对象了
module.exports = {
  get current() {
    return current
  },
  addCurrent: addCurrent
}

那么我们这时就会有一个疑问,如果是引用类型的值呢?是不是还是相同的值,不受影响?

let current = {
  name:'白茶'
};
function addCurrent() {
  current.name='爱喝茶'
}
module.exports = {
  current: current,
  addCurrent: addCurrent
}

let num = require('./Democlass');
  console.log(num.current) //{name: "白茶"}
  num.addCurrent();
  console.log(num.current);//{name: "爱喝茶"}

上面的结果是会发生改变的,这是因为对于基本数据类型而言是 "值的拷贝",只是对于引用类型而言,值指的其实是引用。

下面我们将这个例子改为ES6的引入方式看下:

let current = 1;
let obj = { name: '白茶' };
function addCurrent() {
  current++;
  obj.name = '爱喝茶';
}
export {
  current,
  obj,
  addCurrent
}

import { current, obj, addCurrent } from './data.js';
console.log(current);//1
console.log(obj);//{name: "白茶"}
addCurrent();
console.log(current);//2
console.log(obj);//{name: "爱喝茶"}

可以看出上面的结果都发生了变化,这是为什么呢?

ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令 import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的 import有点像 Unix 系统的“符号连接”,原始值变了, import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

上面讲了下es6和CommonJS模块输出的不同,下面就主要的学习下ES6中的知识:

传送门:阮一峰大大ES6学习指南

严格模式

ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";

严格模式主要有以下限制:

  • 变量必须声明后再使用
  • 函数的参数不能有同名属性,否则报错
  • 不能使用with语句
  • 不能对只读属性赋值,否则报错
  • 不能使用前缀 0 表示八进制数,否则报错
  • 不能删除不可删除的属性,否则报错
  • 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
  • eval不会在它的外层作用域引入变量
  • evalarguments不能被重新赋值
  • arguments不会自动反映函数参数的变化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局对象
  • 不能使用fn.callerfn.arguments获取函数调用的堆栈
  • 增加了保留字(比如protectedstaticinterface

上面这些限制,模块都必须遵守。由于严格模式是 ES5 引入的,不属于 ES6,所以请参阅相关 ES5 书籍,本书不再详细介绍了。

其中,尤其需要注意this的限制。ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this

export命令

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。

几种常见的写法:

//输出多个变量
export let a = 1;
export let b = 2;
//等同于下方
export {a,b};

//输出函数
export function demo(){return 1};
//等同于
function demo(){return 1};
export {demo};

as关键字重命名

function demo(){return 1};
export {demo};

//如果我们想要把对外输出的命名修改下,就可以使用as进行操作
function demo(){return 1};
export {demo as demo2};//demo 是我们的函数名称,demo2是我们修改后的名称

import命令

使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

下面介绍几种常用的写法:

function demo(){return 1};
let a =1;
let b =2;
export {demo,a,b};

import {demo} from './demo.js';

//import中也有as关键字,同样也是修改命名
import {demo as demo2} from './demo.js';

//修改全部命名
import * as num from './demo.js';
console.log(num.a);//1
//这里的num就是导入的全部模块变量,是一个对象

export default 命令

使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载,这里的export default命令,就是为模块指定默认输出。

example1:

//第一种写法
export default function () {
  return 'demo';
};
//第二种写法
function demo(){return 'demo'};
export default demo;
//引入函数引用
import foo from './demo.js';
console.log(foo()) // demo

//这种写法是错误的
export default const a = 1;

从上面的例子中我们看到,我在使用export命令导出的demo函数,在引用的时候,使用的命名是foo但是还是可以执行函数,并且输出正确的值。这是为什么呢?

原因:

export default就是输出一个叫做 default的变量或方法,然后系统允许你为它取任意名字。 export default命令的本质是将后面的值,赋给 default变量

赋给default变量这句话让我们举例子解释下,更清楚一点:

function demo(){return 'demo'};
export default demo;
  • 首先声明了一个函数demo,紧接着使用了export default命令
  • 这里并不是把demo函数输出了,而是进行了赋值,default = demo;

下面是export default 命令的几个注意的地方:

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。
因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句。

参考文章:

ES6 入门教程

https://github.com/mqyqingfeng/Blog/issues/108

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页