ES6

ES6教程

对象字面量

  • 方法属性

      let obj = {
          // before
          foo: function() {
              return 'foo'
          },
    
          // after
          bar() {
          return 'bar'
          }
      }
    
  • proto

      let o = {
          __proto__: new Foo()
      }
    
  • 属性名动态计算

      let arr = [1, 2, 3]
      let outArr = arr.map(n => {
          return {
            [ n ]: n,
            [ `${n}^2` ]: Math.pow(n, 2)
      }
      })
      console.dir(outArr) //=>
        [
          { '1': 1, '1^2': 1 },
          { '2': 2, '2^2': 4 },
          { '3': 3, '3^2': 9 }
      ]
    
  • 同名方法属性省略

          // module.js
          export default {
            someMethod
          }
    
          function someMethod() {
              // ...
          }
    
          // app.js
          import Module from './module'
    
          Module.someMethod()
    

const

let

产生块级作用域

    for (let i = 0; i < buttons.length; i++) {
        // ...
    }

for-of循环

  • ES5中的循环(不能响应break,continue,return)

      myArray.forEach(function (value) {
      console.log(value);
      });
    
  • for-in(遍历属性)

  • 属性遍历

      for (var key of Object.keys(someObject)) {
      console.log(key + ": " + someObject[key]);
      }
    
  • for-of(为各种集合遍历数据如数组,可以响应break,continue,return,不只可以遍历数组)

      //遍历数组
      for (var value of myArray) {
      console.log(value);
      }
      //遍历字串
      for (var chr of "") {
      alert(chr);
      }
      //遍历set对象
      var uniqueWords = new Set(words);
      for (var word of uniqueWords) {
      console.log(word);
      }
      //遍历并解构map对象(map对象是键值对)
      for (var [key, value] of phoneBookMap) {
      console.log(key + "'s phone number is: " + value);
      }
    
  • 迭代器(实现迭代器方法就可以对对象使用for-of)

      // 使jQuery支持for-of
      jQuery.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
    

    for-of循环时会调用集合的[Symbol.iterator](),返回新的迭代器对象

    迭代器对象.next(),next()被反复调用

      var zeroesForeverIterator = {
         [Symbol.iterator]: function () {
            return this;
         },
         next: function () {
              return {done: false, value: 0};//无限循环,只返回0
         },
         return:function(){...}
        
      };
    

    迭代器对象.return(),过早退出会触发return(),异常,break,return会触发过早退出

    for-of执行过程:

      var $iterator = ITERABLE[Symbol.iterator]();
      var $result = $iterator.next();
      while (!$result.done) {
        VAR = $result.value;
        一些语句
        $result = $iterator.next();
      }
    

生成器 Generators

生成器在执行过程中遇到yield时会暂停执行(生成器的堆栈结构包括本地变量,参数,临时值,当前执行位置会被移出堆栈,生成器对象会保留对这个堆栈的引用),在调用next()时重新激活堆栈结构并继续执行
yield不是退出而是切出

    //定义生成器
    function* quips(name) {
            yield "你好 " + name + "!";
            yield "希望你能喜欢这篇介绍ES6的译文";
            if (name.startsWith("X")) {
            yield "你的名字 " + name + "  首字母是X,这很酷!";
            }
            yield "我们下次再见!";
    }
    //执行
    > var iter = quips("jorendorff");
    [object Generator]
    > iter.next()
    { value: "你好 jorendorff!", done: false }
    > iter.next()
    { value: "希望你能喜欢这篇介绍ES6的译文", done: false }
    > iter.next()
    { value: "我们下次再见!", done: false }
    > iter.next()
    { value: undefined, done: true }

生成器就是迭代器,生成器内建next()和[Symbol.iterator]()方法的实现,可以构建出永无止境的序列的生成器。

    //传统迭代器的构建
    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};
                    }
            }
    }
    
    // 返回一个新的迭代器,可以从start到stop计数。
    function range(start, stop) {
        return new RangeIterator(start, stop);
    }
    
    //用生成器来构建迭代器
    function* range(start, stop) {
     for (var i = start; i < stop; i++)
       yield i;
     }

    //生成器构建filter
    function* filter(test, iterable) {
      for (var item of iterable) {
       if (test(item))
           yield item;
      }
    }

    //生成器用于异步
    // 制造一些噪音的异步代码。
    // 返回一个Promise对象
    // 当我们制造完噪音的时候会变为resolved
    function makeNoise_async() {
    return Q.async(function* () {
    yield shake_async();
    yield rattle_async();
    yield roll_async();
    });
    }

template strings

用``代替'',支持多行

    function authorize(user, action) {
      if (!user.hasPrivilege(action)) {
            throw new Error(
            `用户 ${user.name} 未被授权执行 ${action} 操作。`);// ${action}模板占位符
       }
    }

标签模板(tagged templates)

    var message =SaferHTML`<p>${bonk.sender} 向你示好。</p>`;
    //等同于
    var message =SaferHTML(templateData, bonk.sender);
    function SaferHTML(templateData) {//templateData   Object.freeze(["<p>", " has sent you a bonk.</p>"] 不可变数组
      var s = templateData[0];
      for (var i = 1; i < arguments.length; i++) {
        var arg = String(arguments[i]);

        // 转义占位符中的特殊字符。
        s += arg.replace(/&/g, "&")
                .replace(/</g, "<")
                .replace(/</g, ">");

        // 不转义模板中的特殊字符。
        s += templateData[i];
      }
      return s;
    }
    
    
    // 基于纯粹虚构的模板语言
    // ES6标签模板。
    var libraryHtml = hashTemplate`
      <ul>
        #for book in ${myBooks}
          <li><i>#{book.title}</i> by #{book.author}</li>
        #end
      </ul>
    `;

不定参数,默认参数

  • 不定参数

    //传统方法
    

    function containsAll(haystack) {
    for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
    return false;
    }
    }
    return true;
    }
    //ES6实现方法
    //...needles为不定参数,必须在最后一位,参数传入时会赋一个数组,类似["b", "nan"],没有参数时[]
    function containsAll(haystack, ...needles) {
    for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
    return false;
    }
    }
    return true;
    }
    //调用
    containsAll("banana", "b", "nan")

  • 默认参数

    //参数自左向右求值,可以使用赋好值的其他参数 
    function animalSentenceFancy(animals2="tigers",animals3=(animals2 == "bears") ? "sealions" : "bears")
    {
            return `Lions and ${animals2} and ${animals3}! Oh my!`;
    }
    
    animalSentenceFancy("bears") //“Lions and bears and sealions. Oh my!”
    
    //undefined相当于不传值
    animalSentence(undefined, "unicorns") //“Lions and tigers and unicorns! Oh my!
    

解构Destrucuring

  • 数组的结构([ variable1, variable2, ..., variableN ] = array;)

      var first = someArray[0];
      var second = someArray[1];
      var third = someArray[2];
      //解构
      var [first, second, third] = someArray;
      //嵌套结构
      var [foo, [[bar], baz]] = [1, [[2], 3]];
      //跳过其他元素
      var [,,third] = ["foo", "bar", "baz"];
      //不定参数结构
      var [head, ...tail] = [1, 2, 3, 4];
      console.log(tail);
      // [2, 3, 4]
      
      // undefined
      var [missing] = [];
      console.log(missing);
      
      
      
      function* fibs() {
      var a = 0;
      var b = 1;
      while (true) {
      yield a;
      [a, b] = [b, a + b];
      }
      }
      var [first, second, third, fourth, fifth, sixth] = fibs();
      console.log(sixth);
      // 5
    
  • 对象的解构

      var robotA = { name: "Bender" };
      var robotB = { name: "Flexo" };
      var { name: nameA } = robotA;
      var { name: nameB } = robotB;
      console.log(nameA);
      // "Bender"
      console.log(nameB);
      // "Flexo"
    
      //属性名与变量名一致时
      var { foo, bar } = { foo: "lorem", bar: "ipsum" };
      console.log(foo);
      // "lorem"
      console.log(bar);
      // "ipsum"
    
      //嵌套解构
      var complicatedObj = {
      arrayProp: [
              "Zapp",
              { second: "Brannigan" }
      ]
      };
      var { arrayProp: [first, { second }] } = complicatedObj;
      console.log(first);
      // "Zapp"
      console.log(second);
      // "Brannigan"
    
  • 解构的默认值

      var [missing = true] = [];
      console.log(missing);
      // true
      var { message: msg = "Something went wrong" } = {};
      console.log(msg);
      // "Something went wrong"
      var { x = 3 } = {};
      console.log(x);
      // 3
    
  • 解构用法

      //作为参数
      function removeBreakpoint({ url, line, column }) {
      // ...
      }
    
      //用于迭代
      var map = new Map();
      map.set(window, "the global");
      map.set(document, "the document");
      for (var [key, value] of map) {
      console.log(key + " is " + value);
      }
      // "[object Window] is the global"
      // "[object HTMLDocument] is the document"
    
    
      for (var [,value] of map) {
      // ...
      }
    
      //多值返回
      function returnMultipleValues() {
      return {
              foo: 1,
              bar: 2
      };
      }
      var { foo, bar } = returnMultipleValues();
    

Arrow Functions(lambda表达式)

在HTML中-->之前的字符是注释的一部分,而在JS中-->之后的部分才是注释(行首时会注释单行,行中时是趋向于运算符)
lambda中没有arguments

    // ES5
    var total = values.reduce(function (a, b) {
      return a + b;
    }, 0);
    // ES6
    var total = values.reduce((a, b) => a + b, 0);

    // ES6
    $("#confetti-btn").click(event => {
      playTrumpet();
      fireConfettiCannon();
    });
    
    var chewToys = puppies.map(puppy => {});   // 这样写会报Bug!
    var chewToys = puppies.map(puppy => ({})); //

    puppy => {}//返回undefined,大括号代表方法体

this

    {
       ...
            addAll: function addAll(pieces) {
                    var self = this;//this指向调用者,方法是调用者的一个属性
                    _.each(pieces, function (piece) {//内层函数里,this会是window或undefined,只能通过以下方法传递this
                      self.add(piece);//把调用者传给内层函数或.bind(this)
                    });
            },
       ...
    }      
      
      
    // ES6
    {
        ...
            addAll: function addAll(pieces) {
               _.each(pieces, piece => this.add(piece));//lambda中的this可以继承外部函数中的this
            },
        ...
    }      

Symbols

js中的6种原始类型undefined,null,boolean,number,string,object
symbols是第7种类型,可以用做属性键避免冲突,它的值与其他任何值都不相等,不能被类似obj.name的点号法访问,被创建后不可改变,当前作用域

    var mySymbol = Symbol();
    obj[mySymbol] = "ok!";  // 保证不会冲突
    console.log(obj[mySymbol]);  // ok!

    // 创建一个独一无二的symbol
    var isMoving = Symbol("isMoving");
    ...
    if (element[isMoving]) {
      smoothAnimations(element);
    }
    element[isMoving] = true;

symbols属性的操作

    //属性是否存在
    if (isMoving in element)    
    //删除属性  
    delete element[isMoving]
 
    //会跳过symbols属性
    Object.getOwnPropertyNames(obj)   
    Object.keys(obj)   
    
    //得到symbols属性
    Object.getOwnPropertySymbols(obj)
    
    //不能被隐式转换为string,必须显示转换
    String(sym)
    sym.toString()

创建symbols

    //每次返回新的symbol
    Symbol()
    //共享symbol
    Symbol.for(string)
    //Symbol.iterator
    myArray[Symbol.iterator]

转译器Babel,Broccoli

数据结构

set(不包含相同元素,无索引支持,通过数组构建set可以去重)

    let s = new Set()
    s.add('hello').add('world').add('hello')
    console.log(s.size) //=> 2
    console.log(s.has('hello')) //=> true


    > // 检查"zythum"是不是一个单词
    > arrayOfWords.indexOf("zythum") !== -1  // 慢
            true
    > setOfWords.has("zythum")               // 快
            true

new Set:创建一个新的、空的Set。
new Set(iterable):从任何可遍历数据中提取元素,构造出一个新的集合。
set.size:获取集合的大小,即其中元素的个数。
set.has(value):判定集合中是否含有指定元素,返回一个布尔值。
set.add(value):添加元素。如果与已有重复,则不产生效果。
set.delete(value):删除元素。如果并不存在,则不产生效果。.add()和.delete()都会返回集合自身,所以我们可以用链式语法。
setSymbol.iterator:返回一个新的遍历整个集合的迭代器。一般这个方法不会被直接调用,因为实际上就是它使集合能够被遍历,也就是说,我们可以直接写for (v of set) {...}等等。
set.forEach(f):直接用代码来解释好了,它就像是for (let value of set) { f(value, value, set); }的简写,类似于数组的.forEach()方法。
set.clear():清空集合。
set.keys()、set.values()和set.entries()返回各种迭代器,它们是为了兼容Map而提供的,所以我们待会儿再来看。

WeakSet

只能加入对象,如果对象的其他引用已经删除,则对象会从WeakSet中删除

    let weaks = new WeakSet()
    weaks.add("hello") //=> Error
    weaks.add(3.1415) //=> Error

    let foo = new String("bar")
    let pi = new Number(3.1415)
    weaks.add(foo)
    weaks.add(pi)
    weaks.has(foo) //=> true
    foo = null
    weaks.has(foo) //=> false

map

  • 避免与内置方法冲突

  • 数据不会作为属性暴露出来,obj.key,obj[key]不能再访问数据了,可以用map.get(key)访问数据

  • 对象可以作为属性

    new Map:返回一个新的、空的Map。
    new Map(pairs):根据所含元素形如[key, value]的数组pairs来创建一个新的Map。这里提供的pairs可以是一个已有的Map 对象,可以是一个由二元数组组成的数组,也可以是逐个生成二元数组的一个生成器,等等。
    map.size:返回Map中项目的个数。
    map.has(key):测试一个键名是否存在,类似key in obj。
    map.get(key):返回一个键名对应的值,若键名不存在则返回undefined,类似obj[key]。
    map.set(key, value):添加一对新的键值对,如果键名已存在就覆盖。
    map.delete(key):按键名删除一项,类似delete obj[key]。
    map.clear():清空Map。
    mapSymbol.iterator:返回遍历所有项的迭代器,每项用一个键和值组成的二元数组表示。
    map.forEach(f) 类似for (let [key, value] of map) { f(value, key, map); }。这里诡异的参数顺序,和Set中一样,是对应着Array.prototype.forEach()。
    map.keys():返回遍历所有键的迭代器。
    map.values():返回遍历所有值的迭代器。
    map.entries():返回遍历所有项的迭代器,就像mapSymbol.iterator。实际上,它们就是同一个方法,不同名字。

WeakMap

会检查key,value只有其一的引用被删除,就会从WeakMap中删除

WeakMap,WeakSet(方便垃圾收集)

    //set是强引用,element作为key,如果element被从dom中移除了,无法回收他的内存,除非在set中也删除
    //WeakSet并不对其中对象保持强引用。当WeakSet中的一个对象被回收时,它会简单地被从WeakSet中移除
    if (movingSet.has(element)) {
      smoothAnimations(element);
    }
      movingSet.add(element);

WeakMap只支持new、has、get、set 和delete。
WeakSet只支持new、has、add和delete。
WeakSet的值和WeakMap的键必须是对象。

Class

    class Person {
    constructor(name, gender, age) {
    this.name = name
    this.gender = gender
    this.age = age
    }
    
    isAdult() {
    return this.age >= 18
    }
    }
    
    let me = new Person('iwillwen', 'man', 19)
    console.log(me.isAdult()) //=> true

继承

    class Animal {
      yell() {
        console.log('yell')
      }
    }
    
    class Person extends Animal {
      constructor(name, gender, age) {
        super() // must call `super` before using `this` if this class has a superclass

        this.name = name
        this.gender = gender
        this.age = age
      }

      isAdult() {
        return this.age >= 18
      }
    }
    
    class Man extends Person {
      constructor(name, age) {
        super(name, 'man', age)
      }
    }
    
    let me = new Man('iwillwen', 19)
    console.log(me.isAdult()) //=> true
    me.yell()

静态方法

    class Man {
      // ...

      static isMan(obj) {
        return obj instanceof Man
      }
    }
    
    let me = new Man()
    console.log(Man.isMan(me)) //=> true

模块

全局引用

    mport name from 'module-name'
    import * as name from 'module-name'

局部引用

    import { A, B, C } from 'module-name'
    
    A()
    B()
    C()

暴露接口

    // module.js
    export function method() { /* ... */ }
    
    // main.js
    import M from './module'
    M.method()

    //覆盖暴露
    // module.js
    export default {
      method1,
      method2
    }
    
    // main.js
    import M from './module'
    M.method1()

Promise

    function fetchData() {
      return new Promise((resolve, reject) => {
        api.call('fetch_data', (err, data) => {
          if (err) return reject(err)
  
          resolve(data)
        })
      })
    }

    fetchData()
      .then(data => {
        // ...

        return storeInFileSystem(data)
      })
      .then(data => {
        return renderUIAnimated(data)
      })
      .catch(err => console.error(err))

Proxy

不修改目标的前提下,拦截逻辑进行处理

    let apiProxy = new Proxy(api, {
      get(receiver, name) {
        return (function(...args) {
          min.sadd(`log:${name}`, args)
          return receiver[name].apply(receiver, args)
        }).bind(receiver)
      }
    })
    
    api.getComments(artical.id)
      .then(comments => {
        // ...
      })

深入浅出ES6
给 JavaScript 初心者的 ES2015 实战

原文地址:https://www.cnblogs.com/yfann/p/4848547.html