4.2 ECMAScript 概述
下面是非正式的 ECMAScript 概述 -- 并未描述语言的所有部分。此概述并非标准的一部分。
ECMAScript 是基于对象的:基本语言和宿主设施都由对象提供,ECMAScript 程序是一组可通信的对象。ECMAScript 对象 (objects) 是 零个或多个属性 (properties) 的集合,每个属性都有特性 (attributes),它决定了该属性会被怎样使用。例如,当设置一个属性的 Writable 特性为 false 时,任何试图更改此属性值的 ECMAScript 代码的都会运行失败。属性是持有其他 对象 (objects), 原始值 (primitive values), 函数 (functions) 的容器。原始值是以下内置类型之一的成员:Undefined,Null,Boolean,Number,String,Symbol;对象是剩下的内置类型 Object 的成员;函数是可调用对象 (callable object)。函数是可调用的对象。方法 (method) 是通过属性与对象关联的函数。
ECMAScript 定义一组内置对象 (built-in objects),勾勒出 ECMAScript 实体的定义。这些内置对象包括 全局对象 (global object) ,运行时语法基础对象如Object 对象 ,Function 对象 ,Boolean 对象,Symbol 对象以及众多Error对象;操作数字的对象比如Number 对象 ,Math 对象 ,Date 对象;文本处理对象如String 对象 ,RegExp 对象;索引式集合如 Array 对象以及九种不同的元素都是特殊定义的数字值的类型数组;键值集合如 Map 对象、Set 对象;格式化数据的JSON 对象、ArrayBuffer、DataView;支持抽象控制的比如 generator 函数和 Promise 对象;以及反射对象如Proxy,Reflect。
ECMAScript 中还定义一组内置运算符 (operators)。ECMAScript 运算符包括 一元运算符 ,乘法运算符 ,加法运算符 ,位移位运算符 ,关系运算符 ,相等运算符 ,二进制位运算符 ,二进制逻辑运算符 ,赋值运算符 ,逗号运算符。
通过Modules已经支持大型ECMAScript程序将代码分割为多个语句和声明的序列了。每个模块都需要明确声明他使用了哪些需要其他模块提供的,以及它提供了哪些是可以被其他模块使用的内容。
ECMAScript 语法有意设计成与 Java 语法类似。ECMAScript 的语法是松散的,使其能够成为一个易于使用的脚本语言。例如,一个变量不需要有类型声明,属性也不需要与类型关联,定义的函数也不需要声明在函数调用词句的前面。
4.2.1 对象
尽管ECMAScript包括了类定义的语法,ECMAScript对象并不是像C++,Smalltalk或者Java那样的基于类来构建。相反,类可以通过多种方式创建,包括使用字面量或者构造器创建对象,然后执行初始化代码给对象的全部或者部分属性赋初始值。每个构造器都是有名为“prototype”属性的函数,prototype属性是用来实现基于原型的继承和属性共享。构造器通过 new 表达式创建对象:例如,new Date(2009,11) 创建一个新 Date 对象。不使用 new 调用一个构造器的结果依赖构造器本身。例如,Date() 产生一个表示当前日期时间的字符串而不是一个对象。
每个对象都有一个对其构造器的“prototype"属性值的隐式引用(称作对象的原型)。而且,原型也可能拥有一个对其自身原型的非NUll的隐式引用。以此类推,这叫做 原型链。当有一个引用指向对象的一个属性,引用会指向原型链中包含此属性名的第一个对象的此属性。换句话说,首先检查直接引用的对象的同名属性,如果对象包含同名的属性,引用即指向此属性,如果该对象不包含同名的属性,则下一步检查对象的原型;以此类推。
图1 对象和原型的关系
一般情况下基于类的面向对象语言的实例拥有状态,类拥有方法,并且只能继承结构和行为。在 ECMAScript 中,对象拥有状态和方法,并且结构,行为,状态全都可继承
不直接包含原型中包含的特定属性的所有对象会共享此属性及属性值。图 1 说明了这一点: CF 是一个构造器(也是一个对象)。五个对象已用 new 表达式创建 : cf1, cf2, cf3, cf4, cf5。每个对象都有名为 q1 和 q2 的属性。虚线表示隐式原型关系;例如:cf3 的原型是 CFp。构造器 CF 自己有名为 P1 和 P2 的两个属性 , 这对 CFp, cf1, cf2, cf3, cf4, cf5 是不可见的。CFp 的名为 CFP1 的属性共享给 cf1, cf2, cf3, cf4, cf5 ( 没有 CF), 以及在 CFp 的隐式原型链中的任何名字不为 q1, q2, 或 CFP1 的属性。 请注意 ,CF 和 CFp 之间没有隐式原型链接。
不同于基于类的对象语言,属性可以通过赋值的方式动态添加给对象。也就是说,构造器并不是非要对构造的对象的全部或任何属性命名或赋值。上图中,可以通过给 CFp 添加新属性值的方式为 cf1, cf2, cf3, cf4,cf5 添加一个新的共享属性。
尽管ECMAScript不是基于类来继承的,但是定义基于构造函数,原型对象和方法的模式,但和类类似的抽象形式会更加方便。ECMAScript内置对象自身已经基于和类类似的模式。从ECMAScript2015开始,ECMAScript语言包括了定义类的语法,允许程序简洁的定义对象就像内置对象所使用的和类类似的抽象模式那样。
4.2.2 ECMAScript的严格模式变体
ECMAScript 语言认可有些本语言的用户希望限制使用语言中某些功能的可能性。他们这样做可能是为了安全考虑,避免他们认为是容易出错的功能,获得增强的错误检查,或其他原因。为了支持这种可能性,ECMAScript 中定义了语言的严格变体。语言的严格变体排除了 ECMAScript 语言的某些特定的语法和语义特征,还修改了某些功能的详细语义。严格变体还增加了必须抛出错误作为异常报告的错误条件,即使在非严格的语言形式下这些条件不属于错误。
ECMAScript 的严格变体通常被称为语言的 严格模式 (strict mode)。严格模式选择以及 ECMAScript 严格模式的语法和语义的使用,明确地适用于单个的 ECMAScript 源代码单元。由于严格模式适用于选择的语法代码单元级别,严格模式仅在这个代码单元内施加有局部效果的限制。严格模式不限制或修改任何必须运行在多个代码单元的 ECMAScript 语义层面。一个 ECMAScript 程序可由严格模式和非严格模式的代码单元组成。在这种情况下,严格的模式只适用于严格模式代码单元内实际执行的代码。
要符合这一规范,一个ECMAScript的实现必须同时实现未限制的ECMAScript语言和按照这个规范定义的ECMAScript的严格模式变体。此外,一个实现还必须支持未限制的和严格模式代码单元的在同一个程序中混用。.