一、ECMAScript6 简介
(1) 与JavaScript的关联
ES是JS的规格,JS是ES的一种完成(别的的ECMAScript方言另有Jscript和ActionScript);
(2) Babel转码器
敕令行环境
装置babel-cli, babel-preset-2015;
直接运转ES6代码:babel-node敕令;
将ES6转换成ES5:babel敕令;
浏览器环境
到场brower.js,ES6代码用type="text/babel"
Node.js环境
装置 babel-core,babel-preset-2015,根目录竖立.babelrc文件:
{
"preset":["es2015"]
}
(1) babel加载为require的一个钩子:设置完.babelrc文件后,在运用进口到场require("babel-core/register")
;
(2) 如有运用Iterator,Generator等全局对象及上要领:装置babel-polyfill模块,并在运用头部require("babel-polyfill")
二、变量
(1) let敕令
基础用法
与var相似,但变量只在let的代码块内有用;
var a = [];
for (let i = 0; i < 10;i++) {
a[i] =function () {
console.log(i);
};
}
a[6]();
// 6,变量i是let声明的,当前的i只在本轮轮回有用,所以每一次轮回的i实在都是一个新的变量,末了输出的是6;若用var i = 0,则将为10
注重:
(1) 无“变量提拔”,用let声明的对象之前需要先声明再运用;
(2) 暂时性死区(Temporal Dead Zone),只需一进入当前作用域,所要运用的变量就已存在了,然则不可猎取,只要比及声明变量的那一行代码涌现,才能够猎取和运用该变量;同时,也意味着:typeof操纵不是相对平安的!
// 2.暂时性死区 例子
var tmp = 123;
if (true) {
tmp = 'abc'; //ReferenceError
let tmp;
}
typeof x; // ReferenceError
let x;
function bar(x = y, y = 2) {
return [x, y];
}
bar(); // 报错
(3) 不允许反复声明,雷同作用域中不能用var,let再次声明let变量(若不是雷同作用域则不妨,即再嵌套一个{},花括号里外就是差异作用域);
(2) 块级作用域
能够在块级作用域中声明函数,且该行动相似于let:
function f() { console.log('I am outside!'); }
(function () {
if(false) {
//反复声明一次函数f
function f() { console.log('I am inside!'); }
}
f();
}());
以上代码在差异的版本下会有差异:
ES5:运转效果“I am inside!”,相当于声明提早;
ES6:运转效果“I am outside!”,相当于内里的是块作用域,f() 用的是闭包里的;
ES6的浏览器:报错“f is not a function”,依据划定规矩:函数声明会提早到全局、函数作用域的头部(相似var),也会提早到块级作用域的头部,相当于在只实行函数头部
var f = undefined
;
(3) const敕令
与let雷同,块级作用域,然则常量需要初始化;
const声明对象时,其地点不可变,但个中内容可变;
(4) 全局对象的属性 与 全局变量
用ES5的敕令var, function声明的变量依然是全局对象的属性,而用ES6敕令声明的变量则不是;
以上划定规矩在Node的REPL中实用,模块环境下,则只能用
global.a
来挪用全局变量;
三、变量的解构赋值
(1) 数组的解构
例子:
var [a, b, c] = [1, 2,3]; // 则abc离别为123
特殊情况
跳过:
let [x, , y] = [1, 2, 3]; // y为3
数组:
let [head, ...tail] = [1, 2, 3, 4]; // tail为[2,3,4]
左侧解构不胜利(左侧多),则变量为
undefined
;右侧不完全解构(左侧少),则疏忽右侧;
右侧为非可遍历,则报错;
默许值 undefined,[]
例子:(右侧必需为=== undefined)
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
注重:
惰性求值:若默以为函数,只要在解构用到默许值时才挪用;
能够用已声明的变量作为默许值,未声明的则报错;
(2) 对象的解构
同名属性赋值,左侧寄义为{形式:变量},完全花样如:
var { foo: foo, bar: bar } = { foo:"aaa", bar: "bbb" };
若形式与变量同名则能够省略形式,不然必需完全
var { foo: baz } = { foo: "aaa", bar:"bbb" };// 变量baz为"aaa"
注重:
“变量”部份的从新声明(代码见后);
嵌套赋值(代码见后);
将已声明的变量用于解构赋值,需要加括号(代码见后);
// --------- 1. 变量部份从新声明 ---------
let foo;
let {foo} = {foo: 1}; // SyntaxError: Duplicate declaration "foo"
({foo} = {foo: 1}); // 胜利
let baz;
let {bar: baz} = {bar: 1}; // SyntaxError: Duplicate declaration "baz"
({bar: baz} = {bar: 1}); // 胜利
// --------- 2. 嵌套赋值 ---------
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123,bar: true });
obj // {prop:123}
arr // [true]
// 以下报错
var {foo: {bar}} = {baz:'baz'}; // 因为foo为undefined,则foo.bar会报错
// --------- 3. 将已声明的变量用于解构赋值,需要注重 ---------
var x;
{x} = {x: 1};
// 准确的写法
({x} = {x: 1});
// 因为“{”在行首,会被理解为一个代码块,故而背面报错;
(3) 字符串、数值、布尔型解构
等式的右侧会转换层包装对象,故而等式左侧能够写成 length:s, toString: s;
(4) 函数参数的解构
例子:
function add([x, y]){
returnx + y;
}
add([1, 2]); // 3
对照 设定参数对象默许值 与 对象解构的默许值 的辨别:
// 对象解构的默许值
function move({x = 0, y = 0} = {}) {
return[x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
// 参数对象的默许值
function move({x, y} = { x: 0, y: 0 }) {
return[x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
(5) 解构中的圆括号
声明中不可运用圆括号,赋值语句中的非形式部份(变量与团体)能够运用圆括号;
四、第七种数据范例——Symbol
(1) 数组的解构
用处:保证对象属性名的唯一性;
天生要领:经由过程Symbol()函数,可传参数作为形貌;
注重:
不能在Symbol()函数前面加new,不然报错,因为Symbol不是对象;
Symbol()函数不能与其他范例的值举行运算,但可转成字符串或布尔值(true);
Symbol(s)中的参数仅仅用于toString()控制台输出作为人工辨别,纵然没有参数也是差异的变量;
var s1 = Symbol(); var s2 = Sy mbol(); s1 === s2 // false
(2) 作为属性名
(a) 体式格局
a[mySymbol] = 'xx';
a = {
[mySymbol] = 'xx' //方括号不能去
};
Object.defineProperty(a, mySymbol, {
value: 'xx'
});
(b) 注重
当Symbol作为属性名时,不能用点运算符,a.mySymbol实在为a[‘mySymbol’];
(c) 遍历
用Object.getOwnPropertySymbols(),返回数组,其成员是一切用作属性名的Symbol值;
Reflect.ownKeys(),返回自身一切范例的键名,包含Symbol值;
(3) Symbol的要领
(a) Symbol.for(s)
从新运用同一个Symbol,搜刮有无s为名字的Symbol,有就返回,无则新建Symbol;这是全局的,纵然差异iframe也用同一个Symbol;
(b) Symbol.keyFor()
返回一个已用Symbol.for()登记的Symbol范例值的key;
(4) 对象中内置Symbol.xx属性
Symbol.hasInstance:指向内部要领,当其他对象运用instanceof运算符时,会挪用这个要领;
Symbol.isConcatSpreadable:布尔值,示意运用concat()时,是展开成元素照样全部数组
Symbol.species:指向一个要领,当该对象作为构函制造实例时,挪用该要领;
Symbol.match:指向一个要领,实行match()时会挪用;
Symbol.replace:指向一个要领,实行replace()时会挪用;
Symbol.search:指向一个要领,实行search()时会挪用;
Symbol.split:指向一个要领,实行split()时会挪用;
Symbol.iterator:指向该对象的默许遍历器;
Symbol.toPrimitive:指向一个要领,该对象被转为原始范例的值时挪用,返回该对象对应的原始范例值;
Symbol.toStringTag:指向一个要领,挪用toString()要领时,返回成
[object xxx]
Symbol.unscopables:指向一个对象,指定了运用with关键字时,哪些属性被with消除;
五、Set与WeakSet
(1) Set
鸠合,相似数组,成员值唯一;采纳===,除了NaN;
(a) 花样
new Set([array])
(b) 属性
Set.prototype.constructor:组织函数,默许就是Set函数;
Set.prototype.size:返回Set实例的成员总数;
(c) 要领
add(value):增加某个值,返回Set构造自身;
delete(value):删除某个值,返回一个布尔值,示意删除是不是胜利;
has(value):返回一个布尔值,示意该值是不是为Set的成员;
clear():消灭一切成员,没有返回值;
以下为遍历要领
keys():返回键名的遍历器,Set键名与键值雷同;
values():返回键值的遍历器,Set键名与键值雷同;
entries():返回键值对的遍历器;
forEach(func):运用回调函数遍历每一个成员;
(2) WeakSet
(a) 与Set的辨别
元素只能是对象;
个中的对象都是弱援用,渣滓接纳机制不斟酌其对象的援用,即若无其他对象援用该对象,则接纳;
因没法援用该对象,故没法遍历;
(b) 要领
WeakSet.prototype.add(value):向WeakSet实例增加一个新成员;
WeakSet.prototype.delete(value):消灭WeakSet实例的指定成员;
WeakSet.prototype.has(value):返回一个布尔值,示意某个值是不是在WeakSet实例当中;
六、Map与WeakMap
(1) Map
相似对象,键值对的鸠合,但其键的局限不限于字符串;参数是数组,其成员是[[key1, value1], [key2, value2]]
;
(a) 注重
同一个键屡次赋值,则会掩盖;
读取未知的键,返回undefined;
对同一个对象的援用作为键,Map才视为同一个键,NaN、正负0离别视为同一个对象;
map.set(['a'], 555); map.get(['a']); //undefined var k1 = ['a']; var k2 = ['a']; map .set(k1, 111) .set(k2, 222); map.get(k1) // 111 map.get(k2) // 222
(b) 属性与操纵要领
size属性:返回成员总数;
set(key, value):设置key所对应的键值,然后返回全部Map构造,若已存在键,则更新值;
get(key):读取对应键值,无则返回undefined;
has(key):返回布尔值,示意是不是在Map中;
delete(key):删除某个键,返回true,失利则false;
clear():消灭一切成员,无返回;
遍历要领:keys(), values(), entries(), forEach();
(2) WeakMap
与Map构造相似,唯一辨别在于只接收对象作为键名(null除外);
WeakMap的专用场所就是,它的键所对应的对象,能够会在未来消逝,WeakMap构造有助于防备内存走漏;
没有遍历操纵,也没有size属性;
没法清空;
七、类class
(1) 基础语法
class范例看成是函数,类自身就是指向组织函数;
类的要领都定义在prototype对象上面,所以类的新要领能够增加在prototype对象上面;
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
} // 这里无分号
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
class表达式
const MyClass = class Me {...}
// 该类的名字是MyClass而不是Me,Me只在Class内部代码可用
(2) constructor要领
new敕令天生对象实例时,挪用该要领;
若无显式的,则默许增加一个空的constructor函数;
注重:无变量提拔;
(3) 继续
(a) 基础用法
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 挪用父类的constructor(x, y), 必需要挪用super()要领,因为子类需要用到父类的this
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 挪用父类的toString()
}
}
(b) 原型属性
子类的__proto__属性,示意组织函数的继续,老是指向父类;
子类prototype属性的__proto__属性,示意要领的继续,老是指向父类的prototype属性;
(c) 继续的特殊情况
子类继续Object
A.proto === Object // true
A.prototype.proto === Object.prototype // true
不存在任何继续
A.proto === Function.prototype // true
A.prototype.proto === Object.prototype // true
子类继续null
A.proto === Function.prototype // true
A.prototype.proto === undefined // true
(d) 实例的__proto__属性
子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性,即子类的原型的原型,是父类的原型;
(4) 继续原生组织函数
ES5中,先建立子类this,父类的属性增加到子类上,因为父类内部属性没法猎取,致使没法继续原生的组织函数;
ES6中,先新建父类this,然后再用子类组织函数润饰this,这使得父类的一切行动都能够继续;
(5) class的存取值函数
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
(6) Generator要领
class Foo {
constructor(...args) {
this.args = args;
}
*Symbol.iterator {
for(let arg of this.args) {
yield arg;
}
}
}
(7) 静态要领
在要领前加上static
关键字,就示意该要领不会被实例继续,而是直接经由过程类来挪用;
父类的静态要领,能够被子类继续,也可用super
对象挪用;
(8)(ES7)静态属性和实例属性
(ES6划定,只要静态要领,无静态属性,ES7草案有静态属性)
实例属性
class MyClass {
myProp = 42;
constructor() {
console.log(this.myProp); // 42
}
}
静态属性
class MyClass {
static myStaticProp = 42;
constructor() {
console.log(MyClass.myProp); // 42
}
}
(9) new.target属性
返回new敕令作用于的谁人组织函数,假如组织函数不是经由过程new敕令挪用的,new.target会返回undefined;
Class内部挪用new.target,返回当前Class;
子类继续父类时,new.target会返回子类;