ECMA6所有知识点大概笔记

ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现

初学者一开始学习JavaScript,其实就是在学3.0版的语法。

Node.js是JavaScript语言的服务器运行环境,对ES6的支持度比浏览器更高。通过Node,可以体验更多ES6的特性。建议使用版

本管理工具nvm,来安装Node,因为可以*切换版本。不过, nvm 不支持Windows系统,如果你使用Windows系统,下面的

操作可以改用nvmw或nvm-windows代替。

Babel是一个广泛使用的ES6转码器,可以将ES6代码转为ES5代码,从而在现有环境执行


ES6新增了 let 命令,用来声明变量。它的用法类似于 var ,但是所声明的变量,只在 let 命令所在的代码块内有效

let 不像 var 那样会发生“变量提升”现象。所以,变量一定要在声明后使用,否则报错。

只要块级作用域内存在 let 命令,它所声明的变量就“绑定”(binding)这个区域,ES6明确规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是

在声明之前就使用这些变量,就会报错。

let不允许在相同作用域内,重复声明同一个变量


为什么需要块级作用域?ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景

第一种场景,内层变量可能会覆盖外层变量

第二种场景,用来计数的循环变量泄露为全局变量。

let 实际上为JavaScript新增了块级作用域

ES5存在函数提升,不管会

不会进入 if 代码块,函数声明都会提升到当前作用域的顶部,得到执行

而ES6支持块级作用域,不管会不会进入if代码

块,其内部声明的函数皆不会影响到作用域的外部。

const 声明一个只读的常量。一旦声明,常量的值就不能改变。

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const的作用域与let命令相同:只在声明所在的块级作用域内有效,也是不提升,存在暂时性死区,不可重复声明

对于复合类型的变量(对象),变量名不指向数据,而是指向数据所在的地址,不可变的只是这个地址,但对象本身是可变的,所以依然可以为其添加新属性

ES5只有两种声明变量的方法: var 命令和 function 命令。ES6除了添加 let 和 const 命令另外

两种声明变量的方法: import 命令和 class 命令。所以,ES6一共有6种声明变量的方法。

全局对象是最顶层的对象,在浏览器环境指的是 window 对象,在Node.js指的是 global 对象

var 命令和 function 命令声明的全局变量,依旧是全局对象的属性;另一方面规定,let 命令、 const 命令、 class 命令声明的全局变量,不属于全局对象的属性。

数组解构的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

解构赋值的规则是,只要等号右边的值不是对象,就先将其转为对象,由于 undefined 和 null 无法转为对象,所以对它们

进行解构赋值,都会报错。

解构赋值对提取JSON对象中的数据,函数参数的默认值,尤其有用。


avaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节,对于那些需要4个字节储存的字符(Unicode码点大于

0xFFFF的字符),JavaScript会认为它们是两个字符。

JavaScript只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中,ES6又提供了三种新方法

includes():返回布尔值,表示是否找到了参数字符串

startsWith():返回布尔值,表示参数字符串是否在源字符串的头部

endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部

这三个方法都支持第二个参数,表示开始搜索的位置

repeat 方法返回一个新字符串,表示将原字符串重复 n 次

padStart 和 padEnd 字符串补全长度的功能,一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的

字符串。

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符

串,或者在字符串中嵌入变量。模板字符串中嵌入变量,需要将变量名写在 ${} 之中。

${}如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的 toString 方

法。大括号内部,就是执行JavaScript代码,因此如果大括号内部是一个字符串,将会原样输出

ES6还为原生的String对象,提供了一个 raw 方法。String.raw 方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对

应于替换变量后的模板字符串。

Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。

Number.isNaN()用来检查一个值是否为NaN。

Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false。

ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面

Number.isInteger()用来判断一个数值是否为整数。

Math.trunc方法用于去除一个数的小数部分,返回整数部分。

Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。

它会返回五种值。

  • ● 参数为正数,返回+1;
  • ● 参数为负数,返回-1;
  • ● 参数为 0,返回0;
  • ● 参数为-0,返回-0;
  • ● 其他值,返回NaN。

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面function Point(x = 0, y = 0)

参数变量是默认声明的,所以不能用let或const再次声明。参数默认值是惰性求值的

undefined,结果触发了默认值,null,就没有触发默认值。

这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域

ES6 引入 rest

参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。函数的length属性,不包括 rest 参数

ES6 允许使用“箭头”(=>)定义函数。箭头函数和普通函数。前者的this绑定定义时所在的作用域,后者的this指向运行时所在的作用域。this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。


ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存。这将大大节省内存。这就是“尾调用优化”的意义。ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。


扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。容易和rest混淆,两个不是一个东西。

function f(v, w, x, y, z) { }
const args = [0, 1];
f(-1, ...args, 2, ...[3]);

1.由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

2.数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。扩展运算符提供了复制数组的简便写法。

const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
3.合并数组
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]

4.扩展运算符可以与解构赋值结合起来,用于生成数组。如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

const [...butLast, last] = [1, 2, 3, 4, 5];

// 报错

5.扩展运算符还可以将字符串转为真正的数组。

[...'hello']

// [ "h", "e", "l", "l", "o" ]

扩展运算符内部调用的是数据结构的 Iterator 接口,因此只要具有 Iterator 接口的对象,都可以使用扩展运算符,如果对没有 Iterator 接口的对象,使用扩展运算符,将会报错。


Array.from方法用于将两类对象转为真正的数组,扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。Array.from方法还支持类似数组的对象。所谓类似数组的对象,本质特征只有一点,即必须有length属性。因此,任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换。

Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。第三个参数,用来绑定this。


Array.of方法用于将一组值,转换为数组。

Array.of(3, 11, 8) // [3,11,8]

Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]

上面代码表示将从 3 号位直到数组结束的成员(4 和 5),复制到从 0 号位开始的位置,结果覆盖了原来的 1 和 2。


数组实例的 find() 和 findIndex()

[1, 4, -5, 10].find((n) => n < 0)
// -5

数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足。

ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组。keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。


数组实例的 includes(),没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判。

ES6 明确将数组的空位转为undefined。


ES5 比较两个值是否相等,只有两个运算符:相等运算符()和严格相等运算符(=)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0 用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。


Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。

注意点(1)浅拷贝(2)同名属性的替换(3)数组的处理(4)取值函数的处理

常见用途(1)为对象添加属性(2)为对象添加方法(3)克隆对象(4)合并多个对象(5)为属性指定默认值

对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。描述对象的enumerable属性,称为”可枚举性“,如果该属性为false,就表示某些操作会忽略当前属性。

“可枚举”(enumerable)这个概念的最初目的,就是让某些属性可以规避掉for...in操作,不然所有内部属性和方法都会被遍历到。比如,对象原型的toString方法,以及数组的length属性,就通过“可枚举性”,从而避免被for...in遍历到。

Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false

从兼容性的角度,都不要使__proto__

用这个属性,而是使用下面的 Object.setPrototypeOf() (写操作)、 Object.getPrototypeOf() (读操

作)、 Object.create() (生成操作)代替。

Object.entries 的基本用途是遍历对象的属性,

Object.entries 方法的一个用处是,将对象转为真正的 Map 结构。var map = new Map(Object.entries(obj));

扩展运算符( ... )用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。等同于使用 Object.assign 方法。

let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、

Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

Symbol值通过 Symbol

函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增

的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

在对象的内部,使用Symbol值定义属性时,Symbol值必须放在方括号之中。

let s = Symbol();
typeof s
// "symbol"

Symbol值可以显式转为字符串。也可以转为布尔值,但是不能转为数值。

Symbol作为属性名,该属性不会出现在 for...in 、 for...of 循环中,也不会

被 Object.keys() 、 Object.getOwnPropertyNames() 返回,它也不是私有属性,有一

个 Object.getOwnPropertySymbols 方法,可以获取指定对象的所有Symbol属性名。这就造成了一种非私有的内部方法的效果。

Symbol.for() 与 Symbol() 这两种写法,都会生成新的Symbol。它们的区别是,前者会被登记在全局环境*搜索,后者

不会。 Symbol.for() 不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是否已经存在,如果不存在才

会新建一个值。

Proxy可以译为“代理器”,ES6原生提供Proxy构造函数,用来生成Proxy实例。

var proxy = new Proxy(target, handler);

Proxy对象的所有用法,都是上面这种形式,不同的只是 handler 参数的写法。其中, new Proxy() 表示生成一个Proxy实

例,target参数表示所要拦截的目标对象, handler 参数也是一个对象,用来定制拦截行为。

Proxy.revocable方法返回一个可取消的Proxy实例

Reflect 对象与 Proxy 对象一样,也是ES6为了操作对象而提供的新API。

将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty ),放到 Reflect 对象上。

ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。通过 add 方法向Set结构加入成员,结果表明Set结构不会添加重复的值,一种去除数组重复成员的方法

// 去除数组的重复成员
[...new Set(array)] 或 Array.from(new Set(array));

操作:add(value),delete(value),has(value),clear()

遍历:keys(),values(),entries(),forEach()


WeakSet结构与Set类似,也是不重复的值的集合。但是,它与Set有两个区别。

首先,WeakSet的成员只能是对象,而不能是其他类型的值。

其次,WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该

对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用

WeakSet的成员,因此WeakSet是不可遍历的。

ES6提供了Map数据结构,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更

完善的Hash结构实现,Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键

Map原生提供三个遍历器生成函数keys(),values(),entries(),forEach()

与其他数据结构的互相转换

  • (1)Map转为数组:就是使用扩展运算符(...)。
  • (2)数组转为Map:将数组转入Map构造函数,就可以转为Map。
  • (3)Map转为对象:Object.create()
  • (4)对象转为Map:Object.keys(obj) strMap.set(k, obj[k]);
  • (5)Map转为JSON,JSON转MAP

任何数据结构只要部署,Iterator接口,就可以完成遍历操作,引入了 for...of 循环,作为遍历所有数据结构的统一的方法。一个数据结构只要部署

了 Symbol.iterator 属性,就被视为具有iterator接口,就可以用 for...of 循环遍历它的成员。也就是说, for...of 循环

内部调用的是数据结构的 Symbol.iterator 方法。

与其他遍历语法的比较:

for循环:写法比较麻烦;

数组提供内置forEach:无法中途跳出

forEach 循环,break命令或return命令都不能奏效;

for...in循环有几个缺点:

数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。

for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。

某些情况下,for...in循环会以任意顺序遍历键名。

总之, for...in 循环主要是为遍历对象而设计的,不适用于遍历数组

for...of

循环相比上面几种做法:

有着同for...in一样的简洁语法,但是没有for...in那些缺点。

不同用于forEach方法,它可以与break、continue和return配合使用。

提供了遍历所有数据结构的统一操作接口。

Promise 是异步编程的一种解决方案,原生提供了Promise对象,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),一旦状态改变,就不会再变,任何时候都可以得到这个结果,Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)

then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。

const p = Promise.all([p1, p2, p3]);

Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例。

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用

Promise.resolve('foo')

// 等价于

new Promise(resolve => resolve('foo'))

async 函数是什么?一句话,它就是 Generator 函数的语法糖。async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

async函数对 Generator 函数的改进,体现在以下四点:

(1)内置执行器。(2)更好的语义。(3)更广的适用性。(4)返回值是 Promise。

只有async函数内部的异步操作执行完,才会执行外面的then方法指定的回调函数

// 函数声明
async function foo() {}
// 函数表达式
const foo = async function () {};
// 箭头函数
const foo = async () => {};

如果希望多个请求并发执行,可以使用Promise.all方法。

async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

next方法必须是同步的,只要调用就必须立刻返回值。也就是说,一旦执行next方法,就必须同步地得到value和done这两个属性。如果遍历指针正好指向同步操作,当然没有问题,但对于异步操作,就不太合适了。目前的解决方法是,Generator 函数里面的异步操作,返回一个 Thunk 函数或者 Promise 对象,即value属性是一个 Thunk 函数或者 Promise 对象,等待以后返回真正的值,而done属性则还是同步产生的


for...of循环用于遍历同步的 Iterator 接口。新引入的for await...of循环,则是用于遍历异步的 Iterator 接口。

异步 Generator 函数出现以后,JavaScript 就有了四种函数形式:普通函数、async 函数、Generator 函数和异步 Generator 函数

Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同,形式上,Generator函数是一个普通函数,但是有两个特征。一是, function 关键字与函数名之间有一个星号;二是,函数体

内部使用 yield 语句,定义不同的内部状态.

Generator函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用Generator函数后并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用 next 方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个 yield 语句(或 return 语句)为止。

Generator函数是分段执行的, yield 语句是暂停执行的标记,而 next 方法可以恢复执行。

next方法返回值的value属性,是Generator函数向外输出数据;next方法还可以接受参数,这是向Generator函数体内输入数据,传入

Generator 函数,作为上个阶段异步任务的返回结果

Generator函数可以返回一系列的值,因为可以有任意多个 yield,yield后面的表达式 123 + 456 ,不会立即求值,只会在 next 方法将指针移到这一句时,才会求值,Generator函数可以不用 yield 语句,这时就变成了一个单纯的暂缓执行函数。

yield 句本身没有返回值,或者说总是返回 undefined 。 next 方法可以带一个参数,该参数就会被当作上一

个 yield 语句的返回值。

for...of 循环可以自动遍历Generator函数,且此时不再需要调用 next 方法。

yield* 语句,用来在一个Generator函数里面执行另一个Generator函数。yield* 不过是 for...of 的一种简写形式,yield 命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。


Generator函数不能用NEW(会报错),又想在函数里面用THIS ?

首先,生成一个空对象,使用 bind 方法绑定Generator函数内部的 this 。这样,构造函数调用以

后,这个空对象就是Generator函数的实例对象了。

Generator函数的一个重要实际意义就是用来处理异步操作,改写回调函数


async函数并不属于ES6,而是被列入了ES7,但是traceur、Babel.js、regenerator等转码器已经支持这个功能,转码后立刻就

能使用。异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可。

ES6诞生以前,异步编程的方法,大概有下面四种。

回调函数

事件监听

发布/订阅

Promise 对象

类的数据类型就是函数,类本身就指向构造函数。

class Point{
// ...
}

typeof Point // "function"

constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法。一个类必须有 constructor 方法,

如果没有显式定义,一个空的 constructor 方法会被默认添加。

实例的属性除非显式定义在其本身(即定义在 this 对象上),否则都是定义在原型上(即定义

在 class 上)。hasOwnProperty方法判断是本身属性还是原型属性。

Class不存在变量提升(hoist),这一点与ES5完全不同。 Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多

子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类没有自己的 this 对象,而是继

承父类的 this 对象,然后对其进行加工。如果不调用 super 方法,子类就得不到 this 对象。只有调用 super 之后,才可以使用 this 关键字

类的继承是按照下面的模式实现的:Object.setPrototypeOf(B.prototype, A.prototype);

Object.getPrototypeOf 方法可以用来从子类上获取父类。因此,可以使用这个方法判断,一个类是否继承了另一个类。

如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

父类的静态方法,可以被子类继承

静态属性指的是Class本身的属性,即 Class.propname ,而不是定义在实例对象( this )上的属性。


修饰器(Decorator)是一个函数,用来修改类的行为。这是ES7的一个提案,目前Babel转码器已经支持。类似和类,方法,属性添加JAVA注解的功能


在ES6之前,社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种。前者用于服务器,后者用于浏览器,ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。

let { stat, exists, readFile } = require('fs') 这种加载称为“运行时加载”

import { stat, exists, readFile } from 'fs' 这种加载称为“编译时加载”

ES6的模块自动采用严格模式

模块功能主要由两个命令构成: export 和 import,export 命令用于规定模块的对外接口, import 命令用于输入其他

模块提供的功能,export 和 import 命令如果处于块级作用域内,就会报错。因为处于条件代码块之中,就没法做静态优化了,违背了ES6模块的设计初衷

模块的整体加载 import * as circle from './circle';

export default 命令,为模块指定默认输出,一个模块只能有一个默认输出,所以, import 命令后面才不用加大括号,因为只可能对应一个方法

ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块


编码规范:

(1)let取代var

(2)全局常量和线程安全:在 let 和 const 之间,建议优先使用 const ,尤其是在全局环境,不应该设置变量,只应设置常量。

..静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。

..使用数组成员对变量赋值时、函数返回多个值,优先使用解构赋值。

..单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。

..对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用 Object.assign 方法

..使用扩展运算符(...)拷贝数组,使用Array.from方法,将类似数组的对象转为数组。

..立即执行函数可以写成箭头函数的形式,那些需要使用函数表达式的场合,尽量用箭头函数代替。因为这样更简洁,而且绑定了this。

..不要在函数体内使用arguments变量,使用rest运算符(...)代替

..总是用Class,取代需要prototype的操作

..Module语法是JavaScript模块的标准写法,坚持使用这种写法。使用 import 取代 require 。

上一篇:html5的websocket


下一篇:[Spring MVC - 2A] - java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)