Class 的基本语法
简介
类的由来
JavaScript
语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子。
12345678910function Point(x, y) { this.x = x; this.y = y;}Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')';};var p = new Point(1, 2);
上面这种写法跟传统的面向对象语言(比如 C++ 和
Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
ES6 提供了更接近传统语言的写法,引入了
Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6
的class可以看作只是一个语法糖,它的绝大部分功能,ES5
都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用
ES6 的cl ...
async 函数
含义
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
前文有一个 Generator 函数,依次读取两个文件。
1234567891011121314151617const fs = require('fs');const readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error) return reject(error); resolve(data); }); });};const gen = function* () { const f1 = yield readFile('/etc/fstab'); co ...
Generator 函数的异步应用
异步编程对 JavaScript 语言太重要。JavaScript
语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。本章主要介绍
Generator 函数如何完成异步操作。
传统方法
ES6 诞生以前,异步编程的方法,大概有下面四种。
回调函数
事件监听
发布/订阅
Promise 对象
Generator 函数将 JavaScript 异步编程带入了一个全新的阶段。
基本概念
异步
所谓“异步“,简单说就是一个任务不是连续完成的,可以理解成该任务被人为分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段。
比如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。
相应地,连续的执行就叫做同步。由于是连续执行,不能插入其他任务,所以操作系统从硬盘读取文件的这段时间,程序只能干等着。
回调函数
JavaScript
语言对异步编程的实现,就是回调函数。所谓回调函 ...
Generator 函数的语法
简介
基本概念
Generator 函数是 ES6
提供的一种异步编程解决方案,语法行为与传统函数完全不同。本章详细介绍
Generator 函数的语法和 API,它的异步编程应用请看《Generator
函数的异步应用》一章。
Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator
函数是一个状态机,封装了多个内部状态。
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator
函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历
Generator 函数内部的每一个状态。
形式上,Generator
函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
1234567function* helloWorldGenerator() { yield 'hello'; yield 'world' ...
Iterator 和 for…of 循环
Iterator(遍历器)的概念
JavaScript
原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6
又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署
Iterator
接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator
的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是
ES6 创造了一种新的遍历命令for...of循环,Iterator
接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将 ...
Promise 对象
Promise 的含义
Promise
是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6
将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise
是一个对象,从它可以获取异步操作的消息。Promise 提供统一的
API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pen ...
Reflect
概述
Reflect对象与Proxy对象一样,也是 ES6
为了操作对象而提供的新
API。Reflect对象的设计目的有这样几个。
(1)
将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。
(2)
修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
1234567891011121314// 老写法try { Object.defineProperty(target, property, attributes); // success} catch (e) { // failure ...
Proxy
概述
Proxy
用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta
programming),即对编程语言进行编程。
Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy
这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
12345678910var obj = new Proxy({}, { get: function (target, propKey, receiver) { console.log(`getting ${propKey}!`); return Reflect.get(target, propKey, receiver); }, set: function (target, propKey, value, receiver) { console.log(`setting $ ...
Set 和 Map 数据结构
Set
基本用法
ES6 提供了新的数据结构
Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
12345678const s = new Set();[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));for (let i of s) { console.log(i);}// 2 3 5 4
上面代码通过add()方法向 Set 结构加入成员,结果表明 Set
结构不会添加重复的值。
Set函数可以接受一个数组(或者具有 iterable
接口的其他数据结构)作为参数,用来初始化。
12345678910111213141516171819// 例一const set = new Set([1, 2, 3, 4, 4]);[...set]// [1, 2, 3, 4]// 例二const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);items.size // 5// 例三const ...
Symbol
概述
ES5
的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin
模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是
ES6 引入Symbol的原因。
ES6
引入了一种新的原始数据类型Symbol,表示独一无二的值。它是
JavaScript
语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol
值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的
Symbol 类型。凡是属性名属于 Symbol
类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
1234let s = Symbol();typeof s// "symbol"
上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是 ...