JavaScript前世今生
JavaScript的发展史
一、JavaScript发展历程
1. 诞生
JavaScript因互联网而生,紧跟浏览器的发展而发展。
1990年,欧洲核能研究所(CERN)科学家在互联网(Internet)基础上,发明了万维网(World Wide Web),从此可以再网上浏览网页文件。(互联网是线路、协议以及通过TCP、IP协议实现数据电子传输的硬件和软件的集合体。Internet提供的主要服务有万维网WWW、文件传输FTP、电子邮件E-mail、远程登录Telnet等。万维网则存在于互联网之上,是由无数个网络站点和网页集合而成,构成了因特网主要的部分。如果把互联网看成是基础,万维网就可以被看成是对互联网的应用)
1992年,美国国家超级电脑应用中心(NCSA)开发了人类历史上第一个浏览器Mosaic。
1994年,NCSA的程序员联合一个风投家成立Mosaic通信公司,后来更名为Netscape。开发面向普通用户的新一代浏览器Netscape Navigator1.0版,市场份额一举超过90%。
Netscape公司很快发现,浏览器需要一种可以嵌入网页的脚本语言来控制页面行为。因为那时网速很慢而且网费很贵,有些操作不需要在服务端完成,可以把这些操作在浏览器端完成,从而提高效率。他们对这项脚本语言的设想是:功能不需要太强,语法简单,容易学习和部署。
恰逢Sun公司java问世,两家公司强强联合,NetScript公司希望借助Java语言的声势,Sun公司则将自己的影响力扩展到浏览器,1995年,他们雇佣程序员十天时间就设计完成了这种语言的第一版,命名为JavaScript,对外宣称JavaScript是Java的补充。
- 基本语法:借鉴C语言和Java语言
- 数据结构:借鉴Java语言,包括将值分为原始值和对象两大类
- 函数用法:借鉴Schema语言和AWK语言,引入闭包
- 原型继承模型:借鉴Self语言
- 正则表达式:借鉴Perl语言
- 字符串和数组处理:借鉴Python语言
2. JavaScript与Java的关系
JavaScript的基础语法和对象体系,是模仿Java而设计的。
JavaScript语言的函数是一种独立的数据类型以及基于原型对象的继承链,是与java语法最大的两点区别。
JavaScript不需要编译,由解释器直接执行。
3. JavaScript与ECMA的关系
1996年,微软模仿JavaScript开发了一门相近的语言JScript,内置于IE3.0,Netscape公司面临丧失浏览器脚本语言的主导权局面。胳膊拗不过大腿,Netscape又找了个大哥-国际标准化组织ECMA(European Computer Manufacture Association)来抵抗微软。
1997年,ECMA组织发布262号标准文件(ECMA-262),里面规定了浏览器脚本语言的标准,并将这种语言成为ECMAScript。
4. JavaScript的版本
1997年,ECMAScript 1.0发布。
1998年,ECMAScript 2.0发布。
1999年,ECMAScript 3.0发布。
2007-2009年,ECMAScript 4.0草案发布,对3.0版本做了大幅升级,但是草案过于激进,各方发生严重分歧,中止4.0的开发,将其中涉及现有功能改善的一小部分,发布为ECMAScript 3.1,会后不久,改名为ECMAScript 5。
2011年,EMAScript 5.1发布,并成为ISO国际标准,到了2012年,所有主要浏览器都支持ECMAScript 5.1的全部功能。
2013-2015年,讨论发布ECMAScript 6,并于2015年正式发布ECMAScript 6,更名为ECMASCript 2015。
5. 拓展-因特网标准制定(RFC)
- 因特网草案(Internet Draft)
- 建议标准,从这个阶段开始就成为RFC文档(Proposed Standard)
- 草案标准(Draft Standard)
- 因特网标准(Internet Standard)
二、JavaScript模块化发展历程
模块化是指把一个复杂的系统分解到一个一个的模块,优点有:
①代码复用,更方便的进行代码管理,同时方便于后面代码的修改和维护
②一个单独的文件就是一个单独的模块,一个单独的作用域。只向外暴露特定的变量和函数,可以避免污染全局变量。
1. 无模块化
Ajax出现之前,JS更多的用来在网页上进行表单验证,实现简单的动画效果。
2006年,ajax的概念被提出,前端拥有了主动向服务端发送请求并操作返回数据的能力,传统的网页慢慢向“富客户端”发展。前端的业务逻辑越来越多,代码也越来越多,于是一些问题就暴露出来:
- 全局变量的冲突
- 函数命名冲突
- 依赖关系不好管理
总结下要出场的“模块化”这个概念需要解决哪些痛点:
- 如何安全的包装一个模块的代码?不污染模块外的任何代码
- 如何唯一标示一个模块?
- 如何优雅的把模块的API暴露出去?不增加全局变量
- 如何方便的使用所依赖的模块?
2. CommonJS
2009年,nodejs横空出世,开创了一个新纪元,人们可以使用js来编写服务端的代码。
CommonJS模块规范主要分为三部分:模块引用(require)、模块定义(export)、模块标示(module)
- 模块标示应遵循统一的规则
- 定义全局函数require,通过该标示来引入其他模块,执行的结果即为其依赖模块暴露出来的API,如果引入模块中也包含相关依赖,则依次加载这些依赖,如果引入模块失败,则require函数应报一个异常
- 模块通过变量export来定义自身同时向外界暴露自己,export只能是一个对象,暴露的API即为此对象的属性
每个文件就是一个模块,有自己的作用域。每个模块内部,module变量代表当前模块,是一个对象,它的exports属性是对外的接口。module.exports属性表示当前模块对外输出的接口,其它文件加载该模块,实际上就是读取module.exports变量。
require命令用户加载模块文件。
3. AMD
AMD(Asynchronous Module Definition)意思就是“异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的执行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require语句加载模块,但是不同于CommonJS,它要求两个参数:
require([module],callback)
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。
Layui中的JavaScript采用的便是AMD规范。
layui.use(['laydate', 'layer', 'table', 'upload', 'slider'], function(){
})
AMD是RequireJS的产出,可以异步加载JS文件,是一个依赖前置、异步定义的框架。
4. CMD
CMD(Common Module Definition)通用模块定义,其提供了模块定义和按需执行加载模块。该规范明确了模块的基本书写格式和基本的交互规则。
CMD没有依赖前置,通过require加载JQuery插件,依赖就近,在什么地方使用到插件就在什么地方require该插件,即用即返,这是一个同步的概念。
//CMD
define(function(require, exports, module) {
let a = require('./a');
a.doSomething();
···
let b = require('./b'); // 依赖可以就近书写
b.doSomething();
...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) {
// 依赖必须一开始就写好
a.doSomething()
...
b.doSomething()
...
})
5. ES6
CommonJS用于服务器,AMD用于浏览器,ES6在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。
ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
import { stat, exists, readFile} from 'fs';
上面代码的实质是从fs模块加载三个方法,其它方法不加载。这种加载称为“编译时加载”或者静态加载,即ES6在编译时就能完成模块加载,效率比CommonJS模块的加载方式高。
参考文章: