我们都知道 js 在诞生时,都只是为了操作一些 dom,所以也就是被随意的写在一个 js 文件里,放上几个 function,绑定上 document.ready,或者是某个 button 的 click 事件。
但恰恰历史选择了 js,这门语言被无限制的放大使用场景。以前的种种简单都变成了束缚。如何在大型应用中使用 js 成了一个重大话题。
模块化
现代软件的构成基石就是模块化,
- 模块定义
模块可以有很多种形式,一个完成可用功能的函数,类语言中的一个类文件,
- 引用机制
模块还需要一种引用机制。让模块可被其它模块所使用。除了定义。
物理模块,引用模块。
如果从这个角度来看,就是你要引用的模块,是不是在同一个文件中。如果是,那就是一个引用型模块。如果不是,还需要找到对应的模块。
JS 的模块化之路
Object
这种方式,把所有的变量,函数封装在一个 Object 里,来实现模块化,缺点是,里面的变量都能被直接读取,所有的函数都被暴露。
1 | const study = { |
它是 new Object 形式的缩写:
1 | var module1 = new Object({ |
funcation
使用立即执行函数,可以将内部的变量的访问被锁住。
1 | var module = (function() { |
这样,只能访问到 return 函数中提供的方法 method,里面的变量是不可见的。即使有其它方法,如果不在 return 中绑定,也是不可见的。
Class
ES 2015 中提出了 Class,这是个好东西,因为它符合了当下主流主言的语法,贴近人类思想,而且对继承等进行了修正。
1 | class Foo { |
Class 解决了变量作用域的问题。
这样,之前两种的模块方式,都可以用 Class 代替掉。
之前,object 的 prototype 可以用 static method 来代替。
class 是个语法糖
把上面的类定义,转成之前的 ES5 语法,是可以对应上的。
1 | function Foo() { |
使用:
1 | var foo = new Foo(); |
原型链方法函数是读写不对称,默认它是在prototype 的,但如果往这个上面写值的话,就会被复制一份到对象上去。
像一些变量,不可能在每个实例间共享的,所以它一定是实例级的,实例方法变量,会加在每一个实例上,而原型方法变量,则是共享的,但一量为原型方法变量进行赋值,其实是在实例上放上一个同名的方法,依据 JS 原型链查找顺序,只会用最近的方法变量。
除了模块的定义之外,模块的引用也有多条路在走。
- CommonJS(require)
- AMD
- ES Module(import)
CommonJS
module.export()
1 | module.exports = function (x){ console.log(x);}; |
require
1 | var foo = require('foo'); |
ES Module
export & import
因为ES6模块是静态加载,而CommonJS模块只有运行时才知道输出哪些接口。
因为它是 static ,所以可以编译优化。
- https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export
- https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import
ES Module 的现状
- Edge 第一个开启
- WebKit 已开启
- Firefox 已开启
- Chrome 61 即将开启
- Node.js …
可以看到在 2017 年,除了 Node,其它浏览器均已支持 ES Module。代码编译的时代即将属于历史。