ECMAScript6规范入门(一)新增变量与数据结构

一、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会返回子类

    原文作者:_west
    原文地址: https://segmentfault.com/a/1190000006913816
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞