简要介绍
- 1995 年由 Brendan Eich 开发
- 借鉴 C 语言基本语法
- 借鉴 Java 语言类型和内存管理
- 借鉴 Schema 语言,函数为“第一等公民” ( first class )
- 借鉴 Self 语言,使用基于原型 ( prototype ) 继承机制
- 在精度方面有一些缺陷
- 单线程,JS 与 GUI 线程互斥
重要事件
- 1997 年 6 月,ECMAScript 1 发布
- 2009 年,Ryan 发布 Node.js
- 2010 年,Isaac 使用 Node.js 发布 npm
- 2015 年 6 月,ECMAScript 6 发布
类型
JavaScript 是一种动态(弱类型)语言,这是指在运行时才确定数据类型的语言,变量在使用前无需声明类型。例如,Java 中要求声明变量的类型:
Integer count = 0;
而 JavaScript 没有这种要求:
let count = 0;
我们不能说 JavaScript 是纯的解释类语言,因为在 JavaScript 中也有一些编译内容。
数据类型
基础数据类型
- Number
- String
- Boolean
- BigInt
- Symbol
- Null
- undefined
为什么说基础数据类型不能被改变?
明日更新。
复杂数据类型
- 函数
- 数组
作用域
也就是变量的可访问性和可见性,需要与词法作用域区分开。通过静态作用域可以预测代码在执行过程中如何查找标识符 ( identifier ) 。
PS: ES6 之前只有全局作用域与函数作用域,之后才有的块级作用域。
变量提升
var 定义的变量会在未给变量赋值时给变量先赋值 undefined,而 let 与 const 没有变量提升。举个例子,使用 var 定义的变量可以在被赋值前访问到,程序不会报错。
如下代码块:
var color;
console.log('color', color); // 输出:color undefined
console.log('size', size); // 输出:size undefined
var size; // 注意该变量的使用位置在其定义之前
console.log('age', age); // 输出:Uncaught ReferenceError: Cannot access 'age' before initialization
let age;
控制台会报错,不能在 age 初始化之前访问到 age(对于 const 定义的变量也是这样),而 var 定义的变量不会有这个问题。
对于声明式函数来说,我们也能够在其声明之前调用这类函数。
如下代码块:
let age = 14;
print(age);
function print(text) { console.log(text); } // 输出:14
在 MDN 文档中,这被称为函数声明提示 ( Function declaration hoisting ) ,JS 中函数声明被提升到封闭函数顶部或全局范围顶部。当创建一个词法环境,函数声明会立即变为即用型函数(不同于 let 直到声明处才可见)
但是对于表达式函数 ( function expressions ) 这样做是错误的。
如下代码块:
let age = 14;
display(age); // 在其声明之前使用
let display = function(text) {
console.log(text);
}; // 输出:Uncaught ReferenceError: Cannot access 'display' before initialization
JS 是如何执行的?
源代码会通过词法分析和执行上下文生成 AST,之后生成字节码(节约内存)。字节码会通过逐行解释执行称为机器码,对于多次出现的代码或者热更新代码,字节码会经过编译优化执行成为机器码,这也是我们说 JS 不是纯解释类语言的原因。
执行上下文 ( execution context )
在可执行代码片段(通常是函数)执行时,JS 会做一些准备工作。执行上下文的种类有:全局执行上下文、函数执行上下文以及 eval 执行上下文。
对于全局执行上下文,代码执行时就会被创建,将其压入执行栈的栈底,每个生命周期内只有一份。
对于函数执行上下文,在执行一个函数时,这个函数的代码会被编译,生成变量环境,词法环境等。当函数执行结束时,该执行环境从栈底弹出。
这里是省略 eval 执行上下文。
创建执行上下文时,JS 干了什么?
- 绑定 This
- 创建词法环境
- 创建环境变量
词法环境和变量环境
词法环境 ( lexical environment )
基于 ECMAScript 代码的词法嵌套结构来定义标识符和具体变量的函数关联。一个词法环境由环境记录 ( Environment Record ) 和一个可能的引用外部词法环境的空值组成。
Outer 是指向外部变量环境的一个指针。
变量环境
变量环境和词法环境不同在后者被用来存储函数声明和变量声明 ( let, const ) 绑定,而前者只用来保存 var 变量绑定。
闭包
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。-- 维基百科
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。 -- MDN
你可以在这些链接中学习闭包内容:
