始于网景
1990 年,蒂姆·伯纳斯-李爵士发明了第一个网页浏览器 WorldWideWeb(后来为了避免与万维网混淆而改名为 Nexus)。
1993 年,马克·安德森发布 NCSA Mosaic。 这是「第一个」可以在文字中嵌入图片,不需要单独打开窗口查看图片的浏览器,引发了90年代的互联网热潮。
国家超级计算机应用中心(英语:National Center for Supercomputing Applications,缩写:NCSA)是美国国家科学基金会按照其超级计算机中心计划最早设立的五个中心之一。
1994 年,安德森从 NCSA 辞职,成立了自己的公司——网景 Netscape,发布了受 Mosaic 影响的 Netscape Navigator 浏览器。
直到 90 年代中期,网景浏览器的市场占有率一度达到 90%。
1995 年,网景决定发明一种与Java搭配使用并且语法上有些类似的辅助脚本语言。刚被招募的布兰登·艾克仅花了十天时间就把原型设计出来了。
1995 年,Sun 与网景联合发表了JavaScript。
1996 年,由于 JavaScript 推出后大获成功,微软在新推出的 IE3 中加入了 JavaScript 的反向工程实现 —— JScript,这两种并不完全兼容的实现,加上有差异的浏览器 DOM 模型,这里就出现了初代目的浏览器兼容问题。
1998 年,网景在与 IE 的浏览器大战中败下阵来,又受当时流行开源的影响,网景开放了自己浏览器的源代码,此项目称为 Mozilla,开发交由非营利团体 Mozilla 组织(Mozilla Organization)进行。
标准化
1999 年,Sun 一开始申请把 Java 标准化,但是之后收回其申请,因为 Sun 不希望丢失 Java 的控制权。
1996 年 11 月,网景正式向 Ecma 国际提交语言标准。
1997 年 6 月,Ecma 以 JavaScript 语言为基础制定了 ECMAScript 标准规范 ECMA-262.
JavaScript 成为了 ECMAScript 最著名的实现之一。除此之外,ActionScript 和 JScript 也都是 ECMAScript 规范的实现语言。
Ecma 国际(英语:Ecma International)是一家国际性会员制度的信息和电信标准组织。
1994 年之前,名为欧洲计算机制造商协会(European Computer Manufacturers Association)。因为计算机的国际化,组织的标准牵涉到很多其他国家,因此组织决定改名表明其国际性。现名称已不属于首字母缩写。
至今为止有八个 ECMA-262 版本发表。
版本 | 发表日期 | 与前版本的差异 |
---|---|---|
1 | 1997年6月 | 首版 |
2 | 1998年6月 | 格式修正,以使得其形式与 ISO/IEC16262 国际标准一致 |
3 | 1999年12月 | 强大的正则表达式,更好的词法作用域链处理,新的控制指令,异常处理,错误定义更加明确,数据输出的格式化及其它改变 |
4 | 放弃 | 由于关于语言的复杂性出现分歧,第4版本被放弃,其中的部分成为了第5版本及Harmony的基础 |
5 | 2009年12月 | 新增“严格模式(strict mode)”,一个子集用作提供更彻底的错误检查,以避免结构出错。澄清了许多第3版本的模糊规范,并适应了与规范不一致的真实世界实现的行为。增加了部分新功能,如getters及setters,支持 JSON 以及在对象属性上更完整的反射。 |
6 | 2015年6月 | ECMAScript 2015(ES2015),第 6 版,最早被称作是 ECMAScript 6(ES6),添加了类和模块的语法,其他特性包括迭代器,Python风格的生成器和生成器表达式,箭头函数,二进制数据,静态类型数组,集合(maps,sets 和 weak maps),promise,reflection 和 proxies。作为最早的 ECMAScript Harmony 版本,也被叫做ES6 Harmony。 |
7 | 2016年6月 | ECMAScript 2016(ES2016),第 7 版,多个新的概念和语言特性[9] |
8 | 2017年6月 | ECMAScript 2017(ES2017),第 8 版,多个新的概念和语言特性[10] |
9 | 2018年6月 | ECMAScript 2018 (ES2018),第 9 版,包含了异步循环,生成器,新的正则表达式特性和 rest/spread 语法。 |
事件循环机制
JavaScript 从诞生起就是单线程。对于一种网页脚本语言来说,多线程太复杂。
JavaScript 运行时,除了一个正在运行的主线程,JavaScript 引擎还提供一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列。为了方便理解,这里假设只存在一个队列。)
首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。
异步任务的写法通常是回调函数。一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。
JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)。
事件循环:是一个程序结构,用于等待和发送消息或者事件(a programming construct that waits for and dispatches events or messages in a program)”。
Node.js
2009 年,瑞安·达尔结合了 Google 的 V8、事件驱动模型和低级 I/O 接口编写出了 Node.js.
V8: Google 开源的 JavaScript 引擎,与传统的浏览器解析代码不同,V8 会把 JS 代码编译成机器代码,从而获得飞快的执行速度。V8 是用 C++ 写的。
libuv: 一个跨平台的,主要用于处理事件驱动的异步I/O模型库。用 C++ 编写。
NPM
NPM(全称 Node Package Manager,即“node包管理器”)是 Node.js 默认的、以 JavaScript 编写的软件包管理系统。
NPM 仓库是世界上最大的软件包仓库。
Module Count: http://www.modulecounts.com
模块化
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。Node.js 使用 CommonJS 规范。
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
声明模块
// ES 6
export const spout = 'the spout'
export const handle = 'the handle'
export const tea = 'hot tea'
// 文件以.mjs结尾
-----------------------------
// CommonJS
module.exports = { spout: 'the spout', handle: 'the handle', tea: 'hot tea' }
导入模块
// ES6
import {handle, spout, tea} from './example.mjs'
console.log(handle) // ==> the handle
console.log(spout) // ==> the spout
console.log(tea) // ==> hot tea
-----------------------
// CommonJS
const example = require('./example.js')
console.log(example.spout) // ==> the spout
在 Node.js 中使用 ES 6 模块要加上--experimental-modules
。
node --experimental-modules my-app.mjs
https://nodejs.org/api/esm.html
Object
一个 JavaScript 对象就是一个键值对集合,每个键值对称为一个属性(property),属性可以是函数,是数组,是对象或者整型、字符串等基础类型。
var human = {
firstName: "Virat",
lastName: "Kohli",
age: 30,
fullName: function(){
return this.firstName + " " + this.lastName
}
}
console.log(human)
function human2 (firstName, lastName){
this.firstName = firstName
this.lastName = lastName
age: 30
this.fullName = function() {
return this.firstName + " " + this.lastName
}
}
console.log(human2)
var human3 = function(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
age: 30
this.fullName = function() {
return this.firstName + " " + this.lastName
}
}
console.log(human3)