ES6 学习笔记

2,024 阅读6分钟
原文链接: hilongjw.github.io

强大的for-of循环

ES6不会破坏你已经写好的JS代码。目前看来,成千上万的Web网站依赖for-in循环,其中一些网站甚至将其用于数组遍历。如果想通过修正for-in循环增加数组遍历支持会让这一切变得更加混乱,因此,标准委员会在ES6中增加了一种新的循环语法来解决目前的问题。 就像这样:

for (var value of myArray) { 
  console.log(value); 
}
  • 这是最简洁、最直接的遍历数组元素的语法

  • 这个方法避开了for-in循环的所有缺陷

  • 与forEach()不同的是,它可以正确响应break、continue和return语句

标识符=>表达式。你无需输入function和return 箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。

    $("#confetti-btn").click(event => { 
      playTrumpet(); 
      fireConfettiCannon(); 
    });
    // ES5 
    var selected = allJobs.filter(function (job) { 
      return job.isSelected(); 
    }); 

    //ES6 
    var selected = allJobs.filter(job => job.isSelected());

Iterator 迭代器

for of 会首先调用Symbol.iterator[1]方法,然后就会返回一个迭代器对象; 迭代器对象可以是任何有.next()方法的对象

下面根据书上的作者认为最简单的迭代器,我重写了一个更最简单的迭代器,哈哈

  let some = {
    [Symbol.iterator]() {
      return this;
    },
    next(){
      return{
        done:false,
        value:1
      }
    }
  };
// 在 for of 中会在next()返回 done:true 之后完成,所以这是个死循环,不要在意这些细节。

来看一个正常一点的


let obj = {
  data: [ 'hello', 'world' ],
  [Symbol.iterator]() {
    const self = this;
    let index = 0;
    return {
      next() {
        if (index < self.data.length) {
          return {
            value: self.data[index++],
            done: false
          };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
};

for(let a of obj){
  console.log(a)
}
//hello
//world

支持字符换行与外部变量 ` 号

var a = 'awe'
console.log(`my name is: ${a}`); //my name is: awe
var b = `<div>
          <h1>${a}</h1>
        </div>`;
console.log(b);
//<div>
//  <h1>${a}</h1>
//</div>

symbol

  • symbol是对象状态的最终的解决方案

  • symbol是程序创建并且可以用作属性键的值,并且它能避免命名冲突的风险。

  • symbol 被创建后就不可变更,你不能为它设置属性(在严格模式下尝试设置属性会得到TypeError的错误)。他们可以用作属性名称,性质与字符串类似。

  • 每一个symbol都独一无二,不与其它symbol等同,即使二者有相同的描述也不相等;

    var mySymbol = Symbol(); 
    //调用Symbol()创建一个新的symbol,它的值与其它任何值皆不相等。 字符串或数字可以作为属性的键,symbol 也可以,它不等同于任何字符串,因而这个以symbol为键的属性可以保证不与任何其它属性产生冲突。 
      obj[mySymbol] = "ok!";  // 保证不会冲突 
      console.log(obj[mySymbol]);  // ok! 
    //想要在上述讨论的场景中使用symbol,你可以这样做: 
      // 创建一个独一无二的symbol 
      var isMoving = Symbol("isMoving"); 
      ... 
      if (element[isMoving]) { 
        smoothAnimations(element); 
      } 
      element[isMoving] = true;
    
JavaScript的6种原始类型
  • Undefined 未定义
  • Null 空值
  • Boolean 布尔类型
  • Number 数字类型
  • String 字符串类型
  • Object 对象类型

symbol成为了JavaScript的第七种原始类型

Class


  'use strict'
class Circle{
    constructor(radius){
      this.radius = radius;
      Circle.circlesMade++;
    }

    draw(circle,canvas){
      console.log('draw something')
    }

    static get circleMade(){
      return !this._count ? 0 : this.count;
    }

    static set circleMade(val){
      return this._count  = val;
    }

    area(){
      console.log(Math.pow(this.radius,2) * Math.PI)
      return Math.pow(this.radius,2) * Math.PI;
    }

    get radius(){
      return this._radius;
    }

    set radius(radius){
      return this._radius = radius;
    }

  }

  var  circle = new  Circle(3);

  circle.draw() // draw something
  circle.area() // 28.274333882308138
  circle.radius = 99;
  circle.area() // 30790.74959783356
  • 在class中 ; 符号是可选的。
  • constructor也是可选的,如果不指定,会默认构造一个空的constructor(){}
  • 不可以用生成器来做构造函数

ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set本身是一个构造函数,用来生成Set数据结构。

一个Set是一群值的集合。它是可变的,能够增删元素。

  • set 它和数组不同是不会包含相同元素。试图再次加入一个已有元素不会产生任何效果。
var s = new Set();

[2,3,5,4,5,2,2].map(x => s.add(x))

for (i of s) {console.log(i)}
// 2 3 5 4

上面代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。

    > arrayOfWords[15000] 
        "anapanapa" 
    > setOfWords[15000]    
        undefined

Set不支持索引


    arr.indexOf('a') !== -1 //慢
    //true
    setOfWords.has('a') //快 
    //true

Set的数据存储结构专门为一种操作作了速度优化:包含性检测。

有一个坏处。 Map和Set都为内部的每个键或值保持了强引用,也就是说,如果一个 DOM 元素被移除了,回收机制无法取回它占用的内存,除非 movingSet中也删除了它。在最理想的情况下,库在善后工作上对使用者都有复杂的要求,所以,这很可能引发内存泄露。

所已有了 WeakSet

WeakSet与Set有两个区别:

  • WeakSet的成员只能是对象,而不能是其他类型的值。
  • WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。
var ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set

上面代码试图向WeakSet添加一个数值和Symbol值,结果报错。

WeakSet结构有以下三个方法。

  • WeakSet.prototype.add(value):向WeakSet实例添加一个新成员。
  • WeakSet.prototype.delete(value):清除WeakSet实例的指定成员。
  • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在WeakSet实例之中。

下面是一个例子。

var ws = new WeakSet();
var obj = {};
var foo = {};

ws.add(window);
ws.add(obj);

ws.has(window); // true
ws.has(foo);    // false

ws.delete(window);
ws.has(window);    // false
WeakSet没有size属性,没有办法遍历它的成员。
ws.size // undefined
ws.forEach // undefined

ws.forEach(function(item){ console.log('WeakSet has ' + item)})
// TypeError: undefined is not a function

上面代码试图获取size和forEach属性,结果都不能成功。 WeakSet不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet的一个用处,是储存DOM节点,而不用担心这些节点从文档移除时,会引发内存泄漏。

const

ES6引入的第三个声明类关键词与let类似:const。 const声明的变量与let声明的变量类似,它们的不同之处在于,const声明的变量只可以在声明时赋值,不可随意修改,否则会导致SyntaxError(语法错误)。


    const MAX_CAT_SIZE_KG = 3000; // 正确 
    MAX_CAT_SIZE_KG = 5000; // 语法错误(SyntaxError) 
    MAX_CAT_SIZE_KG++; // 虽然换了一种方式,但仍然会导致语法错误
   const theFairest;  // 语法错误

用const声明变量后必须要赋值,否则也抛出语法错误。

class RangeIterator { 
  constructor(start, stop) { 
    this.value = start; 
    this.stop = stop; 
  } 
  [Symbol.iterator]() { return this; } 
  next() { 
    var value = this.value; 
    if (value < this.stop) { 
      this.value++; 
      return {done: false, value: value}; 
    } else { 
      return {done: true, value: undefined}; 
    } 
  } 
}

Generator 生成器

这个被作者称为最具魔力的特性,貌似很强大的样子,继续看下去。

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


function* helloWorldGenerator(name) {
  yield 'hello';
  yield 'world';
  if(name){
    yield name;
  }
  return 'ending';
}
var a = helloWorldGenerator('awe');

a.next() //{ value: 'hello', done: false }
a.next() //{ value: 'world', done: false }
a.next() //{ value: 'awe', done: false }
a.next() //{ value: 'ending', done: true }

看完这个代码是不是感觉像迭代器? 还真是。“所有生成器都是内建了.next()和 Symbol.iterator[2]的实现。

感觉生成器内容真是太多了,推荐上这里细看 likebeta.gitbooks.io/es6tutorial…[3]