[
  {
    "path": "README.md",
    "content": "# es6-cheatsheet\n\nA cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code\nsnippet examples for your day to day workflow. Contributions are welcome!\n\n## Table of Contents\n\n- [var versus let / const](#var-versus-let--const)\n- [Replacing IIFEs with Blocks](#replacing-iifes-with-blocks)\n- [Arrow Functions](#arrow-functions)\n- [Strings](#strings)\n- [Destructuring](#destructuring)\n- [Modules](#modules)\n- [Parameters](#parameters)\n- [Classes](#classes)\n- [Symbols](#symbols)\n- [Maps](#maps)\n- [WeakMaps](#weakmaps)\n- [Promises](#promises)\n- [Generators](#generators)\n- [Async Await](#async-await)\n- [Getter/Setter functions](#getter-and-setter-functions)\n- [License](#license)\n\n## var versus let / const\n\n> Besides `var`, we now have access to two new identifiers for storing values\n—`let` and `const`. Unlike `var`, `let` and `const` statements are not hoisted\nto the top of their enclosing scope.\n\nAn example of using `var`:\n\n```javascript\nvar snack = 'Meow Mix';\n\nfunction getFood(food) {\n    if (food) {\n        var snack = 'Friskies';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // undefined\n```\n\nHowever, observe what happens when we replace `var` using `let`:\n\n```javascript\nlet snack = 'Meow Mix';\n\nfunction getFood(food) {\n    if (food) {\n        let snack = 'Friskies';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // 'Meow Mix'\n```\n\nThis change in behavior highlights that we need to be careful when refactoring\nlegacy code which uses `var`. Blindly replacing instances of `var` with `let`\nmay lead to unexpected behavior.\n\n> **Note**: `let` and `const` are block scoped. Therefore, referencing\nblock-scoped identifiers before they are defined will produce\na `ReferenceError`.\n\n```javascript\nconsole.log(x); // ReferenceError: x is not defined\n\nlet x = 'hi';\n```\n\n> **Best Practice**: Leave `var` declarations inside of legacy code to denote\nthat it needs to be carefully refactored. When working on a new codebase, use\n`let` for variables that will change their value over time, and `const` for\nvariables which cannot be reassigned.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Replacing IIFEs with Blocks\n\n> A common use of **Immediately Invoked Function Expressions** is to enclose\nvalues within its scope. In ES6, we now have the ability to create block-based\nscopes and therefore are not limited purely to function-based scope.\n\n```javascript\n(function () {\n    var food = 'Meow Mix';\n}());\n\nconsole.log(food); // Reference Error\n```\n\nUsing ES6 Blocks:\n\n```javascript\n{\n    let food = 'Meow Mix';\n};\n\nconsole.log(food); // Reference Error\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Arrow Functions\n\nOften times we have nested functions in which we would like to preserve the\ncontext of `this` from its lexical scope. An example is shown below:\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character; // Cannot read property 'name' of undefined\n    });\n};\n```\n\nOne common solution to this problem is to store the context of `this` using\na variable:\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    var that = this; // Store the context of this\n    return arr.map(function (character) {\n        return that.name + character;\n    });\n};\n```\n\nWe can also pass in the proper context of `this`:\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }, this);\n};\n```\n\nAs well as bind the context:\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }.bind(this));\n};\n```\n\nUsing **Arrow Functions**, the lexical value of `this` isn't shadowed and we\ncan re-write the above as shown:\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(character => this.name + character);\n};\n```\n\n> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the\nlexical value of `this`.\n\nArrow Functions are also more concise when used in function expressions which\nsimply return a value:\n\n```javascript\nvar squares = arr.map(function (x) { return x * x }); // Function Expression\n```\n\n```javascript\nconst arr = [1, 2, 3, 4, 5];\nconst squares = arr.map(x => x * x); // Arrow Function for terser implementation\n```\n\n> **Best Practice**: Use **Arrow Functions** in place of function expressions\nwhen possible.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Strings\n\nWith ES6, the standard library has grown immensely. Along with these changes\nare new methods which can be used on strings, such as `.includes()` and\n`.repeat()`.\n\n### .includes( )\n\n```javascript\nvar string = 'food';\nvar substring = 'foo';\n\nconsole.log(string.indexOf(substring) > -1);\n```\n\nInstead of checking for a return value `> -1` to denote string containment,\nwe can simply use `.includes()` which will return a boolean:\n\n```javascript\nconst string = 'food';\nconst substring = 'foo';\n\nconsole.log(string.includes(substring)); // true\n```\n\n### .repeat( )\n\n```javascript\nfunction repeat(string, count) {\n    var strings = [];\n    while(strings.length < count) {\n        strings.push(string);\n    }\n    return strings.join('');\n}\n```\n\nIn ES6, we now have access to a terser implementation:\n\n```javascript\n// String.repeat(numberOfRepetitions)\n'meow'.repeat(3); // 'meowmeowmeow'\n```\n\n### Template Literals\n\nUsing **Template Literals**, we can now construct strings that have special\ncharacters in them without needing to escape them explicitly.\n\n```javascript\nvar text = \"This string contains \\\"double quotes\\\" which are escaped.\";\n```\n\n```javascript\nlet text = `This string contains \"double quotes\" which don't need to be escaped anymore.`;\n```\n\n**Template Literals** also support interpolation, which makes the task of\nconcatenating strings and values:\n\n```javascript\nvar name = 'Tiger';\nvar age = 13;\n\nconsole.log('My cat is named ' + name + ' and is ' + age + ' years old.');\n```\n\nMuch simpler:\n\n```javascript\nconst name = 'Tiger';\nconst age = 13;\n\nconsole.log(`My cat is named ${name} and is ${age} years old.`);\n```\n\nIn ES5, we handled new lines as follows:\n\n```javascript\nvar text = (\n    'cat\\n' +\n    'dog\\n' +\n    'nickelodeon'\n);\n```\n\nOr:\n\n```javascript\nvar text = [\n    'cat',\n    'dog',\n    'nickelodeon'\n].join('\\n');\n```\n\n**Template Literals** will preserve new lines for us without having to\nexplicitly place them in:\n\n```javascript\nlet text = ( `cat\ndog\nnickelodeon`\n);\n```\n\n**Template Literals** can accept expressions, as well:\n\n```javascript\nlet today = new Date();\nlet text = `The time and date is ${today.toLocaleString()}`;\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Destructuring\n\nDestructuring allows us to extract values from arrays and objects (even deeply\nnested) and store them in variables with a more convenient syntax.\n\n### Destructuring Arrays\n\n```javascript\nvar arr = [1, 2, 3, 4];\nvar a = arr[0];\nvar b = arr[1];\nvar c = arr[2];\nvar d = arr[3];\n```\n\n```javascript\nlet [a, b, c, d] = [1, 2, 3, 4];\n\nconsole.log(a); // 1\nconsole.log(b); // 2\n```\n\n### Destructuring Objects\n\n```javascript\nvar luke = { occupation: 'jedi', father: 'anakin' };\nvar occupation = luke.occupation; // 'jedi'\nvar father = luke.father; // 'anakin'\n```\n\n```javascript\nlet luke = { occupation: 'jedi', father: 'anakin' };\nlet {occupation, father} = luke;\n\nconsole.log(occupation); // 'jedi'\nconsole.log(father); // 'anakin'\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Modules\n\nPrior to ES6, we used libraries such as [Browserify](http://browserify.org/)\nto create modules on the client-side, and [require](https://nodejs.org/api/modules.html#modules_module_require_id)\nin **Node.js**. With ES6, we can now directly use modules of all types\n(AMD and CommonJS).\n\n### Exporting in CommonJS\n\n```javascript\nmodule.exports = 1;\nmodule.exports = { foo: 'bar' };\nmodule.exports = ['foo', 'bar'];\nmodule.exports = function bar () {};\n```\n\n### Exporting in ES6\n\nWith ES6, we have various flavors of exporting. We can perform\n**Named Exports**:\n\n```javascript\nexport let name = 'David';\nexport let age  = 25;​​\n```\n\nAs well as **exporting a list** of objects:\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nexport { sumTwo, sumThree };\n```\n\nWe can also export functions, objects and values (etc.) simply by using the `export` keyword:\n\n```javascript\nexport function sumTwo(a, b) {\n    return a + b;\n}\n\nexport function sumThree(a, b, c) {\n    return a + b + c;\n}\n```\n\nAnd lastly, we can **export default bindings**:\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nlet api = {\n    sumTwo,\n    sumThree\n};\n\nexport default api;\n\n/* Which is the same as\n * export { api as default };\n */\n```\n\n> **Best Practices**: Always use the `export default` method at **the end** of\nthe module. It makes it clear what is being exported, and saves time by having\nto figure out what name a value was exported as. More so, the common practice\nin CommonJS modules is to export a single value or object. By sticking to this\nparadigm, we make our code easily readable and allow ourselves to interpolate\nbetween CommonJS and ES6 modules.\n\n### Importing in ES6\n\nES6 provides us with various flavors of importing. We can import an entire file:\n\n```javascript\nimport 'underscore';\n```\n\n> It is important to note that simply **importing an entire file will execute\nall code at the top level of that file**.\n\nSimilar to Python, we have named imports:\n\n```javascript\nimport { sumTwo, sumThree } from 'math/addition';\n```\n\nWe can also rename the named imports:\n\n```javascript\nimport {\n    sumTwo as addTwoNumbers,\n    sumThree as sumThreeNumbers\n} from 'math/addition';\n```\n\nIn addition, we can **import all the things** (also called namespace import):\n\n```javascript\nimport * as util from 'math/addition';\n```\n\nLastly, we can import a list of values from a module:\n\n```javascript\nimport * as additionUtil from 'math/addition';\nconst { sumTwo, sumThree } = additionUtil;\n```\nImporting from the default binding like this:\n\n```javascript\nimport api from 'math/addition';\n// Same as: import { default as api } from 'math/addition';\n```\n\nWhile it is better to keep the exports simple, but we can sometimes mix default import and mixed import if needed.\nWhen we are exporting like this:\n\n```javascript\n// foos.js\nexport { foo as default, foo1, foo2 };\n```\n\nWe can import them like the following:\n\n```javascript\nimport foo, { foo1, foo2 } from 'foos';\n```\n\nWhen importing a module exported using commonjs syntax (such as React) we can do:\n\n```javascript\nimport React from 'react';\nconst { Component, PropTypes } = React;\n```\n\nThis can also be simplified further, using:\n\n```javascript\nimport React, { Component, PropTypes } from 'react';\n```\n\n> **Note**: Values that are exported are **bindings**, not references.\nTherefore, changing the binding of a variable in one module will affect the\nvalue within the exported module. Avoid changing the public interface of these\nexported values.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Parameters\n\nIn ES5, we had varying ways to handle functions which needed **default values**,\n**indefinite arguments**, and **named parameters**. With ES6, we can accomplish\nall of this and more using more concise syntax.\n\n### Default Parameters\n\n```javascript\nfunction addTwoNumbers(x, y) {\n    x = x || 0;\n    y = y || 0;\n    return x + y;\n}\n```\n\nIn ES6, we can simply supply default values for parameters in a function:\n\n```javascript\nfunction addTwoNumbers(x=0, y=0) {\n    return x + y;\n}\n```\n\n```javascript\naddTwoNumbers(2, 4); // 6\naddTwoNumbers(2); // 2\naddTwoNumbers(); // 0\n```\n\n### Rest Parameters\n\nIn ES5, we handled an indefinite number of arguments like so:\n\n```javascript\nfunction logArguments() {\n    for (var i=0; i < arguments.length; i++) {\n        console.log(arguments[i]);\n    }\n}\n```\n\nUsing the **rest** operator, we can pass in an indefinite amount of arguments:\n\n```javascript\nfunction logArguments(...args) {\n    for (let arg of args) {\n        console.log(arg);\n    }\n}\n```\n\n### Named Parameters\n\nOne of the patterns in ES5 to handle named parameters was to use the **options\nobject** pattern, adopted from jQuery.\n\n```javascript\nfunction initializeCanvas(options) {\n    var height = options.height || 600;\n    var width  = options.width  || 400;\n    var lineStroke = options.lineStroke || 'black';\n}\n```\n\nWe can achieve the same functionality using destructuring as a formal parameter\nto a function:\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'}) {\n        // Use variables height, width, lineStroke here\n    }\n```\n\nIf we want to make the entire value optional, we can do so by destructuring an\nempty object:\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'} = {}) {\n        // ...\n    }\n```\n\n### Spread Operator\n\nIn ES5, we could find the max of values in an array by using the `apply` method on `Math.max` like this:\n```javascript\nMath.max.apply(null, [-1, 100, 9001, -32]); // 9001\n```\n\nIn ES6, we can now use the spread operator to pass an array of values to be used as\nparameters to a function:\n\n```javascript\nMath.max(...[-1, 100, 9001, -32]); // 9001\n```\n\nWe can concat array literals easily with this intuitive syntax:\n\n```javascript\nlet cities = ['San Francisco', 'Los Angeles'];\nlet places = ['Miami', ...cities, 'Chicago']; // ['Miami', 'San Francisco', 'Los Angeles', 'Chicago']\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Classes\n\nPrior to ES6, we implemented Classes by creating a constructor function and\nadding properties by extending the prototype:\n\n```javascript\nfunction Person(name, age, gender) {\n    this.name   = name;\n    this.age    = age;\n    this.gender = gender;\n}\n\nPerson.prototype.incrementAge = function () {\n    return this.age += 1;\n};\n```\n\nAnd created extended classes by the following:\n\n```javascript\nfunction Personal(name, age, gender, occupation, hobby) {\n    Person.call(this, name, age, gender);\n    this.occupation = occupation;\n    this.hobby = hobby;\n}\n\nPersonal.prototype = Object.create(Person.prototype);\nPersonal.prototype.constructor = Personal;\nPersonal.prototype.incrementAge = function () {\n    Person.prototype.incrementAge.call(this);\n    this.age += 20;\n    console.log(this.age);\n};\n```\n\nES6 provides much needed syntactic sugar for doing this under the hood. We can\ncreate Classes directly:\n\n```javascript\nclass Person {\n    constructor(name, age, gender) {\n        this.name   = name;\n        this.age    = age;\n        this.gender = gender;\n    }\n\n    incrementAge() {\n      this.age += 1;\n    }\n}\n```\n\nAnd extend them using the `extends` keyword:\n\n```javascript\nclass Personal extends Person {\n    constructor(name, age, gender, occupation, hobby) {\n        super(name, age, gender);\n        this.occupation = occupation;\n        this.hobby = hobby;\n    }\n\n    incrementAge() {\n        super.incrementAge();\n        this.age += 20;\n        console.log(this.age);\n    }\n}\n```\n\n> **Best Practice**: While the syntax for creating classes in ES6 obscures how\nimplementation and prototypes work under the hood, it is a good feature for\nbeginners and allows us to write cleaner code.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Symbols\n\nSymbols have existed prior to ES6, but now we have a public interface to using\nthem directly. Symbols are immutable and unique and can be used as keys in any hash.\n\n### Symbol( )\n\nCalling `Symbol()` or `Symbol(description)` will create a unique symbol that cannot be looked up\nglobally. A Use case for `Symbol()` is to patch objects or namespaces from third parties with your own\nlogic, but be confident that you won't collide with updates to that library. For example,\nif you wanted to add a method `refreshComponent` to the `React.Component` class, and be certain that\nyou didn't trample a method they add in a later update:\n\n```javascript\nconst refreshComponent = Symbol();\n\nReact.Component.prototype[refreshComponent] = () => {\n    // do something\n}\n```\n\n\n### Symbol.for(key)\n\n`Symbol.for(key)` will create a Symbol that is still immutable and unique, but can be looked up globally.\nTwo identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for\n`Symbol(description)`:\n\n```javascript\nSymbol('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol.for('foo') // true\n```\n\nA common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be\nachieved by having your code look for a Symbol member on object arguments from third parties that contain some\nknown interface. For example:\n\n```javascript\nfunction reader(obj) {\n    const specialRead = Symbol.for('specialRead');\n    if (obj[specialRead]) {\n        const reader = obj[specialRead]();\n        // do something with reader\n    } else {\n        throw new TypeError('object cannot be read');\n    }\n}\n```\n\nAnd then in another library:\n\n```javascript\nconst specialRead = Symbol.for('specialRead');\n\nclass SomeReadableType {\n    [specialRead]() {\n        const reader = createSomeReaderFrom(this);\n        return reader;\n    }\n}\n```\n\n> A notable example of Symbol use for interoperability is `Symbol.iterator` which exists on all iterable\ntypes in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator\ninterface.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Maps\n\n**Maps** is a much needed data structure in JavaScript. Prior to ES6, we created\n**hash** maps through objects:\n\n```javascript\nvar map = new Object();\nmap[key1] = 'value1';\nmap[key2] = 'value2';\n```\n\nHowever, this does not protect us from accidentally overriding functions with\nspecific property names:\n\n```javascript\n> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');\n> TypeError: Property 'hasOwnProperty' is not a function\n```\n\nActual **Maps** allow us to `set`, `get` and `search` for values (and much more).\n\n```javascript\nlet map = new Map();\n> map.set('name', 'david');\n> map.get('name'); // david\n> map.has('name'); // true\n```\n\nThe most amazing part of Maps is that we are no longer limited to just using\nstrings. We can now use any type as a key, and it will not be type-cast to\na string.\n\n```javascript\nlet map = new Map([\n    ['name', 'david'],\n    [true, 'false'],\n    [1, 'one'],\n    [{}, 'object'],\n    [function () {}, 'function']\n]);\n\nfor (let key of map.keys()) {\n    console.log(typeof key);\n    // > string, boolean, number, object, function\n}\n```\n\n> **Note**: Using non-primitive values such as functions or objects won't work\nwhen testing equality using methods such as `map.get()`. As such, stick to\nprimitive values such as Strings, Booleans and Numbers.\n\nWe can also iterate over maps using `.entries()`:\n\n```javascript\nfor (let [key, value] of map.entries()) {\n    console.log(key, value);\n}\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## WeakMaps\n\nIn order to store private data versions < ES6, we had various ways of doing this.\nOne such method was using naming conventions:\n\n```javascript\nclass Person {\n    constructor(age) {\n        this._age = age;\n    }\n\n    _incrementAge() {\n        this._age += 1;\n    }\n}\n```\n\nBut naming conventions can cause confusion in a codebase and are not always\ngoing to be upheld. Instead, we can use WeakMaps to store our values:\n\n```javascript\nlet _age = new WeakMap();\nclass Person {\n    constructor(age) {\n        _age.set(this, age);\n    }\n\n    incrementAge() {\n        let age = _age.get(this) + 1;\n        _age.set(this, age);\n        if (age > 50) {\n            console.log('Midlife crisis');\n        }\n    }\n}\n```\n\nThe cool thing about using WeakMaps to store our private data is that their\nkeys do not give away the property names, which can be seen by using\n`Reflect.ownKeys()`:\n\n```javascript\n> const person = new Person(50);\n> person.incrementAge(); // 'Midlife crisis'\n> Reflect.ownKeys(person); // []\n```\n\nA more practical example of using WeakMaps is to store data which is associated\nto a DOM element without having to pollute the DOM itself:\n\n```javascript\nlet map = new WeakMap();\nlet el  = document.getElementById('someElement');\n\n// Store a weak reference to the element with a key\nmap.set(el, 'reference');\n\n// Access the value of the element\nlet value = map.get(el); // 'reference'\n\n// Remove the reference\nel.parentNode.removeChild(el);\nel = null;\n\n// map is empty, since the element is destroyed\n```\n\nAs shown above, once the object is destroyed by the garbage collector,\nthe WeakMap will automatically remove the key-value pair which was identified\nby that object.\n\n> **Note**: To further illustrate the usefulness of this example, consider how\njQuery stores a cache of objects corresponding to DOM elements which have\nreferences. Using WeakMaps, jQuery can automatically free up any memory that\nwas associated with a particular DOM element once it has been removed from the\ndocument. In general, WeakMaps are very useful for any library that wraps DOM\nelements.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Promises\n\nPromises allow us to turn our horizontal code (callback hell):\n\n```javascript\nfunc1(function (value1) {\n    func2(value1, function (value2) {\n        func3(value2, function (value3) {\n            func4(value3, function (value4) {\n                func5(value4, function (value5) {\n                    // Do something with value 5\n                });\n            });\n        });\n    });\n});\n```\n\nInto vertical code:\n\n```javascript\nfunc1(value1)\n    .then(func2)\n    .then(func3)\n    .then(func4)\n    .then(func5, value5 => {\n        // Do something with value 5\n    });\n```\n\nPrior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or\n[Q](https://github.com/kriskowal/q). Now we have Promises natively:\n\n```javascript\nnew Promise((resolve, reject) =>\n    reject(new Error('Failed to fulfill Promise')))\n        .catch(reason => console.log(reason));\n```\n\nWhere we have two handlers, **resolve** (a function called when the Promise is\n**fulfilled**) and **reject** (a function called when the Promise is **rejected**).\n\n> **Benefits of Promises**: Error Handling using a bunch of nested callbacks\ncan get chaotic. Using Promises, we have a clear path to bubbling errors up\nand handling them appropriately. Moreover, the value of a Promise after it has\nbeen resolved/rejected is immutable - it will never change.\n\nHere is a practical example of using Promises:\n\n```javascript\nvar request = require('request');\n\nreturn new Promise((resolve, reject) => {\n  request.get(url, (error, response, body) => {\n    if (body) {\n        resolve(JSON.parse(body));\n      } else {\n        resolve({});\n      }\n  });\n});\n```\n\nWe can also **parallelize** Promises to handle an array of asynchronous\noperations by using `Promise.all()`:\n\n```javascript\nlet urls = [\n  '/api/commits',\n  '/api/issues/opened',\n  '/api/issues/assigned',\n  '/api/issues/completed',\n  '/api/issues/comments',\n  '/api/pullrequests'\n];\n\nlet promises = urls.map((url) => {\n  return new Promise((resolve, reject) => {\n    $.ajax({ url: url })\n      .done((data) => {\n        resolve(data);\n      });\n  });\n});\n\nPromise.all(promises)\n  .then((results) => {\n    // Do something with results of all our promises\n });\n```\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Generators\n\nSimilar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid\n[callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our\nasynchronous code a synchronous feel. Generators are essentially functions which we can\n[pause their execution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield)\nand subsequently return the value of an expression.\n\nA simple example of using generators is shown below:\n\n```javascript\nfunction* sillyGenerator() {\n    yield 1;\n    yield 2;\n    yield 3;\n    yield 4;\n}\n\nvar generator = sillyGenerator();\n> console.log(generator.next()); // { value: 1, done: false }\n> console.log(generator.next()); // { value: 2, done: false }\n> console.log(generator.next()); // { value: 3, done: false }\n> console.log(generator.next()); // { value: 4, done: false }\n```\n\nWhere [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)\nwill allow us to push our generator forward and evaluate a new expression. While the above example is extremely\ncontrived, we can utilize Generators to write asynchronous code in a synchronous manner:\n\n```javascript\n// Hiding asynchronousity with Generators\n\nfunction request(url) {\n    getJSON(url, function(response) {\n        generator.next(response);\n    });\n}\n```\n\nAnd here we write a generator function that will return our data:\n\n```javascript\nfunction* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n}\n```\n\nBy the power of `yield`, we are guaranteed that `entry1` will have the data needed to be parsed and stored\nin `data1`.\n\nWhile generators allow us to write asynchronous code in a synchronous manner, there is no clear\nand easy path for error propagation. As such, as we can augment our generator with Promises:\n\n```javascript\nfunction request(url) {\n    return new Promise((resolve, reject) => {\n        getJSON(url, resolve);\n    });\n}\n```\n\nAnd we write a function which will step through our generator using `next` which in turn will utilize our\n`request` method above to yield a Promise:\n\n```javascript\nfunction iterateGenerator(gen) {\n    var generator = gen();\n    (function iterate(val) {\n        var ret = generator.next();\n        if(!ret.done) {\n            ret.value.then(iterate);\n        }\n    })();\n}\n```\n\nBy augmenting our Generator with Promises, we have a clear way of propagating errors through the use of our\nPromise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before:\n\n```javascript\niterateGenerator(function* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n});\n```\n\nWe were able to reuse our implementation to use our Generator as before, which shows their power. While Generators\nand Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propagate\nerrors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits:\n[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await).\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## Async Await\n\nWhile this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished\nusing Generators and Promises with less effort:\n\n```javascript\nvar request = require('request');\n\nfunction getJSON(url) {\n  return new Promise(function(resolve, reject) {\n    request(url, function(error, response, body) {\n      resolve(body);\n    });\n  });\n}\n\nasync function main() {\n  var data = await getJSON();\n  console.log(data); // NOT undefined!\n}\n\nmain();\n```\n\nUnder the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource\nfor getting up and running with ES7 and Babel can be found [here](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html).\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n## Getter and setter functions\n\nES6 has started supporting getter and setter functions within classes. Using the following example:\n\n```javascript\nclass Employee {\n\n    constructor(name) {\n        this._name = name;\n    }\n\n    get name() {\n      if(this._name) {\n        return 'Mr. ' + this._name.toUpperCase();  \n      } else {\n        return undefined;\n      }  \n    }\n\n    set name(newName) {\n      if (newName == this._name) {\n        console.log('I already have this name.');\n      } else if (newName) {\n        this._name = newName;\n      } else {\n        return false;\n      }\n    }\n}\n\nvar emp = new Employee(\"James Bond\");\n\n// uses the get method in the background\nif (emp.name) {\n  console.log(emp.name);  // Mr. JAMES BOND\n}\n\n// uses the setter in the background\nemp.name = \"Bond 007\";\nconsole.log(emp.name);  // Mr. BOND 007  \n```\n\nLatest browsers are also supporting getter/setter functions in Objects and we can use them for computed properties, adding listeners and preprocessing before setting/getting:\n\n```javascript\nvar person = {\n  firstName: 'James',\n  lastName: 'Bond',\n  get fullName() {\n      console.log('Getting FullName');\n      return this.firstName + ' ' + this.lastName;\n  },\n  set fullName (name) {\n      console.log('Setting FullName');\n      var words = name.toString().split(' ');\n      this.firstName = words[0] || '';\n      this.lastName = words[1] || '';\n  }\n}\n\nperson.fullName; // James Bond\nperson.fullName = 'Bond 007';\nperson.fullName; // Bond 007\n```\n<sup>[(back to table of contents)](#table-of-contents)</sup>\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 David Leonard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n<sup>[(back to table of contents)](#table-of-contents)</sup>"
  },
  {
    "path": "README_ko.md",
    "content": "# es6-cheatsheet\n\nES2015(ES6)의 Tip & Tricks, 좋은 활용사례들과 코드 예제들이 포함된 cheatsheet입니다.\n이 문서는 한국어 번역 버전입니다. 오역 제보와 더 좋은 번역을 기다리고 있습니다!\n\n## 목차\n\n- [var VS let / const](#var-vs-let--const)\n- [IIFE를 블록으로 교체하기](#iife를-블록으로-교체하기)\n- [애로우 펑션](#애로우-펑션)\n- [문자열](#문자열)\n- [Destructuring](#destructuring)\n- [모듈](#모듈)\n- [파라미터(Parameter)](#파라미터parameter)\n- [클래스](#클래스)\n- [심볼(Symbol)](#심볼symbol)\n- [맵(Map)](#맵map)\n- [위크맵(WeakMap)](#위크맵weakmap)\n- [Promise](#promise)\n- [제너레이터(Generator)](#제너레이터generator)\n- [Async Await](#async-await)\n- [Getter/Setter 함수](#getter와-setter-함수)\n- [License](#license)\n\n## var VS let / const\n\n> 기존의 `var`에 더해 `let`과 `const`라는 값을 저장하기 위한 두 개의 새로운 식별자가 추가되었습니다. `var`와는 다르게, `let`과 `const` 상태는 스코프 내 최상단으로 호이스팅되지 않습니다.\n\n다음은 `var`를 활용한 예제입니다.\n\n```javascript\nvar snack = '허니버터칩';\n\nfunction getFood(food) {\n    if (food) {\n        var snack = '스윙칩';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // undefined\n```\n\n그러나, `var` 대신 `let`을 사용하면 다음과 같이 동작합니다.\n\n```javascript\nlet snack = '허니버터칩';\n\nfunction getFood(food) {\n    if (food) {\n        let snack = '스윙칩';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // '허니버터칩'\n```\n\n이런 변경점으로 인해 `var`를 사용했던 레거시 코드를 리팩토링할 때 더욱 조심해야 합니다. 무턱대고 `var` 대신 `let`을 사용하면 예상치 못한 동작을 할 수도 있습니다.\n\n> **Note**: `let`과 `const`는 블록 스코프 식별자입니다. 따라서, 블록 스코프 식별자로 정의하기 전에 참조하게 되면 `ReferenceError`를 발생시킵니다.\n\n```javascript\nconsole.log(x);\n\nlet x = 'hi'; // ReferenceError: x is not defined\n```\n\n> **Best Practice**: 더 조심스럽게 리팩토링하기 위해서 레거시 코드 내에 `var`선언을 남겨두세요. 새로운 코드베이스에서 작업하게 될 때, 변수 사용을 위해서 `let`을 사용하고, 상수 사용을 위해서 `const`를 사용하세요.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## IIFE를 블록으로 교체하기\n\n> **Immediately Invoked Function Expressions(IIFE)**는 일반적으로 변수들을 별도의 스코프 안에서만 쓰기 위해서 사용되었습니다. ES6에서는 블록을 기반으로 스코프를 만들 수 있게 되었으므로, 더 이상 함수 기반으로 스코프를 만들지 않아도 됩니다.\n\n```javascript\n(function () {\n    var food = '허니버터칩';\n}());\n\nconsole.log(food); // Reference Error\n```\n\nES6 블록을 사용하는 경우,\n\n```javascript\n{\n    let food = '허니버터칩';\n};\n\nconsole.log(food); // Reference Error\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 애로우 펑션\n\n종종 다음과 같이 중첩된 함수 안에서 `this`의 문맥(context)를 보존해야 할 일이 있습니다.\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character; // Cannot read property 'name' of undefined\n    });\n};\n```\n\n보통 이 문제를 해결하기 위해 다음과 같이 별도의 변수를 사용해서 `this`의 문맥을 저장합니다.\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    var that = this; // this의 문맥을 저장합니다.\n    return arr.map(function (character) {\n        return that.name + character;\n    });\n};\n```\n\n또는, 다음과 같은 방법으로 `this` 문맥을 통과시킬 수도 있습니다.\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }, this);\n};\n```\n\n이 뿐만 아니라 문맥을 bind 할 수도 있습니다.\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }.bind(this));\n};\n```\n\n**애로우 펑션**을 사용하면, `this`의 문맥 값이 사라지지 않기 때문에 위의 코드는 다음과 같이 다시 쓸 수 있습니다.\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(character => this.name + character);\n};\n```\n\n> **Best Practice**: `this`의 문맥 값을 보존해야할 때마다 **애로우 펑션**을 사용하세요.\n\n또한 애로우 펑션은 간단한 값을 리턴하는 함수(함수 표현식)가 필요할 때 사용하면 더욱 간결합니다.\n\n```javascript\nvar squares = arr.map(function (x) { return x * x }); // 함수 표현식\n```\n\n```javascript\nconst arr = [1, 2, 3, 4, 5];\nconst squares = arr.map(x => x * x); // 간결한 구현을 위한 애로우 펑션\n```\n\n> **Best Practice**: 가능하다면 함수 표현식 대신 **애로우 펑션**을 활용하세요.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 문자열\n\nES6에서는 표준 라이브러리가 크게 확장되었습니다. 이러한 변경에 맞춰 문자열에도 `.includes()`와 `.repeat()` 같은 새로운 메소드가 추가되었습니다.\n\n### .includes( )\n\n```javascript\nvar string = 'food';\nvar substring = 'foo';\n\nconsole.log(string.indexOf(substring) > -1);\n```\n\n문자열 포함 여부를 구현하기 위해서 리턴 값이 `-1`보다 큰 지 체크하는 것 대신, 간단하게 불린 값을 리턴하는 `.includes()` 메소드를 사용할 수 있습니다.\n\n```javascript\nconst string = 'food';\nconst substring = 'foo';\n\nconsole.log(string.includes(substring)); // true\n```\n\n### .repeat( )\n\n```javascript\nfunction repeat(string, count) {\n    var strings = [];\n    while(strings.length < count) {\n        strings.push(string);\n    }\n    return strings.join('');\n}\n```\n\nES6에서는 이제 간결하게 구현할 수 있습니다.\n\n```javascript\n// String.repeat(numberOfRepetitions)\n'야옹'.repeat(3); // '야옹야옹야옹'\n```\n\n### 템플릿 리터럴\n\n**템플릿 리터럴**을 사용하면 명시적인 문자열 이스케이프를 사용하지 않아도 특수문자를 포함한 문자열을 구축할 수 있습니다.\n\n```javascript\nvar text = \"이 문자열은 이스케이프 된 \\\"큰 따옴표\\\"를 포함합니다.\";\n```\n\n```javascript\nlet text = `이 문자열은 이스케이프 된 \"큰 따옴표\"를 포함합니다.`;\n```\n\n**템플릿 리터럴**은 문자열과 값을 연결시키는 문자열 Interpolation도 지원합니다.\n\n```javascript\nvar name = '나비';\nvar age = 13;\n\nconsole.log('제 고양이의 이름은 ' + name + '이고, 나이는 ' + age + '살 입니다.');\n```\n\n더 간단하게 구현하면,\n\n```javascript\nconst name = '나비';\nconst age = 13;\n\nconsole.log(`제 고양이의 이름은 ${name}이고, 나이는 ${age}살 입니다.`);\n```\n\nES5에서는 개행을 구현하기 위해서 다음과 같이 했습니다.\n\n```javascript\nvar text = (\n    '고양이\\n' +\n    '강아지\\n' +\n    '투니버스'\n);\n```\n\n혹은 이렇게,\n\n```javascript\nvar text = [\n    '고양이',\n    '강아지',\n    '투니버스'\n].join('\\n');\n```\n\n**템플릿 리터럴**은 명시적으로 표시하지 않아도 개행을 보존합니다.\n\n```javascript\nlet text = ( `고양이\n강아지\n투니버스`\n);\n```\n\n뿐만 아니라, **템플릿 리터럴**은 표현식에도 접근할 수 있습니다.\n\n```javascript\nlet today = new Date();\nlet text = `현재 시각은 ${today.toLocaleString()}입니다.`;\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## Destructuring\n\nDestructuring은 배열 혹은 객체(깊게 중첩된 것도 포함하여)에서 편리한 문법을 이용해 값을 추출하고 저장하는데에 활용됩니다.\n\n### 배열 Destructuring\n\n```javascript\nvar arr = [1, 2, 3, 4];\nvar a = arr[0];\nvar b = arr[1];\nvar c = arr[2];\nvar d = arr[3];\n```\n\n```javascript\nlet [a, b, c, d] = [1, 2, 3, 4];\n\nconsole.log(a); // 1\nconsole.log(b); // 2\n```\n\n### 객체 Destructuring\n\n```javascript\nvar luke = { occupation: 'jedi', father: 'anakin' };\nvar occupation = luke.occupation; // 'jedi'\nvar father = luke.father; // 'anakin'\n```\n\n```javascript\nlet luke = { occupation: 'jedi', father: 'anakin' };\nlet {occupation, father} = luke;\n\nconsole.log(occupation); // 'jedi'\nconsole.log(father); // 'anakin'\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 모듈\n\nES6 이전엔, 클라이언트 단은 [Browserify](http://browserify.org/), **Node.js**에서는 [require](https://nodejs.org/api/modules.html#modules_module_require_id)같은 라이브러리를 사용했습니다. 이제 ES6에서는 모든 종류(AMD와 CommonJS)의 모듈을 직접적으로 사용할 수 있습니다.\n\n### CommonJS의 모듈 내보내기(Export)\n\n```javascript\nmodule.exports = 1;\nmodule.exports = { foo: 'bar' };\nmodule.exports = ['foo', 'bar'];\nmodule.exports = function bar () {};\n```\n\n### ES6의 모듈 내보내기\n\nES6에서는, 다양한 방식으로 모듈을 내보낼 수 있습니다. 그 중 **지정 내보내기(named export)**방식은 다음과 같습니다.\n\n```javascript\nexport let name = 'David';\nexport let age  = 25;​​\n```\n\n또한 객체를 이용한 **리스트 내보내기(exporting a list)**방식도 있습니다.\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nexport { sumTwo, sumThree };\n```\n\n간단하게 `export` 키워드만 활용하면 함수, 객체, 값 등을 내보낼 수 있습니다.\n\n```javascript\nexport function sumTwo(a, b) {\n    return a + b;\n}\n\nexport function sumThree(a, b, c) {\n    return a + b + c;\n}\n```\n\n마지막으로, **디폴트 모듈로 내보내기(default binding export)**도 가능합니다.\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nlet api = {\n    sumTwo,\n    sumThree\n};\n\nexport default api;\n\n/* 위 코드는 아래와 같습니다.\n * export { api as default };\n */\n```\n\n> **Best Practice**: `export default`메소드는 항상 모듈 코드의 **마지막**에 위치해야 합니다. 그래야 내보내는 것이 무엇인지 분명해지며, 내보내는 값의 이름을 확인하는 시간을 절약할 수 있습니다. 그 이상으로, CommonJS의 일반적인 관행은 단일 값이나 객체를 내보내는 것입니다. 이런 컨벤션을 따름으로서, 코드의 가독성을 좋게 만들 수 있고 CommonJS와 ES6 모듈을 모두 사용할 수 있게 됩니다.\n\n\n### ES6의 모듈 불러오기(import)\n\nES6에서는 다양한 방식으로 모듈을 불러올 수 있습니다. 다음과 같이 파일 전체를 불러올 수 있습니다.\n\n```javascript\nimport 'underscore';\n```\n\n> 이렇게 단순히 파일 전체를 불러오면 그 파일의 최상단에서 불러온 모든 코드가 실행된다는 점에 유의하시기 바랍니다.\n\n파이썬하고 유사한 지정 불러오기(named import)를 사용할 수 있습니다.\n\n```javascript\nimport { sumTwo, sumThree } from 'math/addition';\n```\n\n다음과 같이 불러온 모듈의 이름을 새로 작성할 수도 있습니다.\n\n```javascript\nimport {\n    sumTwo as addTwoNumbers,\n    sumThree as sumThreeNumbers\n} from 'math/addition';\n```\n\n거기에 더해서, **모두 불러오기**(네임스페이스 불러오기)도 가능합니다.\n\n```javascript\nimport * as util from 'math/addition';\n```\n\n마지막으로, 모듈에서 값들의 리스트를 불러올 수도 있습니다.\n\n```javascript\nimport * as additionUtil from 'math/addition';\nconst { sumTwo, sumThree } = additionUtil;\n```\n\n디폴트 모듈은 다음과 같이 불러올 수 있습니다.\n\n```javascript\nimport api from 'math/addition';\n// 위 코드는 이렇게 표현할 수도 있습니다: import { default as api } from 'math/addition';\n```\n\n가급적 간단한 형태로 모듈을 내보내는 것이 좋지만, 필요하다면 때때로 디폴트 모듈을 포함해 여러 이름을 섞어서 내보낼 수도 있습니다.\n\n```javascript\n// foos.js\nexport { foo as default, foo1, foo2 };\n```\n\n이 모듈은 아래와 같이 불러올 수 있습니다.\n\n```javascript\nimport foo, { foo1, foo2 } from 'foos';\n```\n\nReact처럼 CommonJS 문법을 사용해 내보낸 모듈을 불러올 때는 다음과 같이 쓰면 됩니다.\n\n```javascript\nimport React from 'react';\nconst { Component, PropTypes } = React;\n```\n\n다음과 같이 더욱 간결해질 수도 있습니다.\n\n```javascript\nimport React, { Component, PropTypes } from 'react';\n```\n\n> **Note**: 내보내지는 값은 참조되는 것이 아니라 **바인딩**되는 것입니다. 그러므로, 어떤 모듈의 변수 바인딩을 바꾸게 되면 내보낸 모듈 내에서만 바뀌게 됩니다. 이렇게 내보낸 모듈의 값의 인터페이스를 바꾸는 것은 피하세요.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 파라미터(Parameter)\n\nES5에서는 **디폴트 값(default values)**이나 **정의되지 않은 인자(indefinite arguments)** 혹은 **네임드 파라미터(named parameters)**를 다루는 함수를 구현하는 방법이 너무 많았습니다. ES6에서는 더욱 간결한 문법을 통해 이것들을 모두 다룰 수 있습니다.\n\n### 디폴트 파라미터(Default Parameter)\n\n```javascript\nfunction addTwoNumbers(x, y) {\n    x = x || 0;\n    y = y || 0;\n    return x + y;\n}\n```\n\nES6에서는 함수 내 파라미터의 디폴트 값을 간단하게 설정할 수 있습니다.\n\n```javascript\nfunction addTwoNumbers(x=0, y=0) {\n    return x + y;\n}\n```\n\n```javascript\naddTwoNumbers(2, 4); // 6\naddTwoNumbers(2); // 2\naddTwoNumbers(); // 0\n```\n\n### 레스트 파라미터(Rest Parameter)\n\nES5에서는 인수의 숫자가 가변적인 경우 다음과 같이 처리했습니다.\n\n```javascript\nfunction logArguments() {\n    for (var i=0; i < arguments.length; i++) {\n        console.log(arguments[i]);\n    }\n}\n```\n\n**레스트(rest)**연산자를 사용하면, 다음과 같이 가변적인 숫자의 인수를 넘길 수 있습니다.\n\n```javascript\nfunction logArguments(...args) {\n    for (let arg of args) {\n        console.log(arg);\n    }\n}\n```\n\n### 네임드 파라미터(Named Parameter)\n\nES5의 네임드 파라미터를 처리하는 방법 중 하나는 jQuery에서 차용된 **options object** 패턴을 사용하는 것입니다.\n\n```javascript\nfunction initializeCanvas(options) {\n    var height = options.height || 600;\n    var width  = options.width  || 400;\n    var lineStroke = options.lineStroke || 'black';\n}\n```\n\n파라미터에 destructuring을 사용하면 같은 기능을 구현할 수 있습니다.\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'}) {\n        // 여기에서 height, width, lineStroke 변수를 사용합니다.\n    }\n```\n\n만약 모든 파라미터를 선택적으로 넘기고 싶다면, 다음과 같이 빈 객체로 destructuring 하면 됩니다.\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'} = {}) {\n        // ...\n    }\n```\n\n### 전개 연산자(Spread Operator)\n\nES5에서는 배열 내 숫자들의 최대 값을 찾기 위해서 `Math.max`에 `apply` 메소드를 사용했습니다.\n\n```javascript\nMath.max.apply(null, [-1, 100, 9001, -32]); // 9001\n```\n\nES6에서는 이제 전개 연산자를 이용해서 함수에 파라미터로 배열을 넘길 수 있습니다.\n\n```javascript\nMath.max(...[-1, 100, 9001, -32]); // 9001\n```\n\n다음과 같이 직관적인 문법을 통해 쉽게 배열 리터럴을 합칠 수도 있습니다.\n\n```javascript\nlet cities = ['서울', '부산'];\nlet places = ['여수', ...cities, '제주']; // ['여수', '서울', '부산', '제주']\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 클래스\n\nES6 이전에는, 생성자 함수(constructor)를 만들고 프로토타입을 확장해서 프로퍼티를 추가하여 클래스를 구현했습니다.\n\n```javascript\nfunction Person(name, age, gender) {\n    this.name   = name;\n    this.age    = age;\n    this.gender = gender;\n}\n\nPerson.prototype.incrementAge = function () {\n    return this.age += 1;\n};\n```\n\n그리고 다음과 같이 클래스를 상속했습니다.\n\n```javascript\nfunction Personal(name, age, gender, occupation, hobby) {\n    Person.call(this, name, age, gender);\n    this.occupation = occupation;\n    this.hobby = hobby;\n}\n\nPersonal.prototype = Object.create(Person.prototype);\nPersonal.prototype.constructor = Personal;\nPersonal.prototype.incrementAge = function () {\n    Person.prototype.incrementAge.call(this);\n    this.age += 20;\n    console.log(this.age);\n};\n```\n\nES6는 이런 간단한 구현을 위해 편리한 문법을 제공합니다. 이제 클래스를 직접 만들 수 있습니다.\n\n```javascript\nclass Person {\n    constructor(name, age, gender) {\n        this.name   = name;\n        this.age    = age;\n        this.gender = gender;\n    }\n\n    incrementAge() {\n      this.age += 1;\n    }\n}\n```\n\n그리고 `extends` 키워드를 사용해서 상속할 수 있습니다.\n\n```javascript\nclass Personal extends Person {\n    constructor(name, age, gender, occupation, hobby) {\n        super(name, age, gender);\n        this.occupation = occupation;\n        this.hobby = hobby;\n    }\n\n    incrementAge() {\n        super.incrementAge();\n        this.age += 20;\n        console.log(this.age);\n    }\n}\n```\n\n> **Best Practice**: 클래스를 만들기 위한 ES6의 문법은 내부적으로 어떻게 프로토타입으로 구현되는지 모호하지만, 초보자들에게 좋은 기능이고 더 깨끗한 코드를 작성하도록 도와줍니다.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 심볼(Symbol)\n\n심볼은 ES6 이전에도 존재했지만, 이제 직접적으로 심볼을 사용할 수 있는 공식 인터페이스가 제공됩니다. 심볼은 고유하고 수정 불가능한 데이터 타입이고 모든 객체의 식별자로 활용할 수 있습니다.\n\n### Symbol()\n\n`Symbol()` 혹은 `Symbol(description)` 메소드를 호출하면 전역적으로 사용할 수 없는 고유한 심볼이 생성될 것입니다. `Symbol()`은 써드 파티 라이브러리의 객체 혹은 네임스페이스에 충돌할 염려가 없는 새로운 코드를 덧입히는데 종종 쓰입니다. 예를 들어, 나중에 라이브러리가 업데이트 되더라도 겹칠 우려가 없이 `React.Component` 클래스에 `refreshComponent` 메소드를 추가하고 싶다면 다음과 같이 할 수 있습니다.\n\n```javascript\nconst refreshComponent = Symbol();\n\nReact.Component.prototype[refreshComponent] = () => {\n    // do something\n}\n```\n\n\n### Symbol.for(key)\n\n`Symbol.for(key)`는 여전히 고유하고 수정 불가능한 심볼을 생성하지만, 전역적으로 사용 가능합니다. `Symbol.for(key)`를 두 번 호출하면 두 번 다 같은 심볼 인스턴스를 반환합니다. 주의하세요. `Symbol(description)`에서는 그렇지 않습니다.\n\n```javascript\nSymbol('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol.for('foo') // true\n```\n\n일반적으로 심볼, 특히 `Symbol.for(key)`은 상호 운용성을 위해 사용합니다. 상호 운용성은 몇 가지 알려진 인터페이스를 포함하는 서드 파티 라이브러리의 객체에 인자로 심볼 멤버 형태의 코드를 사용함으로서 만족될 수 있습니다. 예를 들면,\n\n```javascript\nfunction reader(obj) {\n    const specialRead = Symbol.for('specialRead');\n    if (obj[specialRead]) {\n        const reader = obj[specialRead]();\n        // do something with reader\n    } else {\n        throw new TypeError('객체를 읽을 수 없습니다.');\n    }\n}\n```\n\n또 다른 라이브러리에선 이렇게 할 수 있습니다.\n\n```javascript\nconst specialRead = Symbol.for('specialRead');\n\nclass SomeReadableType {\n    [specialRead]() {\n        const reader = createSomeReaderFrom(this);\n        return reader;\n    }\n}\n```\n\n> 상호 운용성을 위해 심볼을 사용하는 주목할 만한 예는 모든 반복 가능한(iterable) 타입 혹은 반복자(iterator)에 존재하는 `Symbol.iterator`입니다. 배열, 문자열, 생성자, 등 반복 가능한 타입은 이 메소드를 통해 호출되면 반복자 인터페이스를 포함한 객체 형태로 리턴됩니다.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 맵(Map)\n**맵**은 자바스크립트에서 자주 필요한 데이터 구조입니다. ES6 이전엔 객체를 이용해서 **해시** 맵을 생성했습니다.\n\n```javascript\nvar map = new Object();\nmap[key1] = 'value1';\nmap[key2] = 'value2';\n```\n\n하지만, 이 방법은 특정 프로퍼티 이름으로 인한 예상치 못한 함수 오버라이드(override)로부터 안전하지 않습니다.\n\n```javascript\n> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');\n> TypeError: Property 'hasOwnProperty' is not a function\n```\n\n실제로 **맵**은 값을 위해 `get`, `set` 그리고 `search` 등의 메소드를 제공합니다.\n\n```javascript\nlet map = new Map();\n> map.set('name', '현섭');\n> map.get('name'); // 현섭\n> map.has('name'); // true\n```\n\n맵의 가장 놀라운 점은 더 이상 키 값으로 문자열만 쓰지 않아도 된다는 것입니다. 이제 키 값으로 어떤 타입을 전달해도 문자열로 형변환되지 않습니다.\n\n```javascript\nlet map = new Map([\n    ['이름', '현섭'],\n    [true, 'false'],\n    [1, '하나'],\n    [{}, '객체'],\n    [function () {}, '함수']\n]);\n\nfor (let key of map.keys()) {\n    console.log(typeof key);\n    // > string, boolean, number, object, function\n}\n```\n\n> **Note**: 함수나 객체처럼 기본형 데이터 타입이 아닌 타입을 사용하면 `map.get()`같은 메소드를 사용할 때 비교 연산자가 제대로 동작하지 않습니다. 따라서, 문자열, 불린, 숫자 같은 기본형 데이터 타입을 계속 쓰는 것이 좋습니다.\n\n또한 `.entries()`를 사용하면 맵을 순회할 수 있습니다.\n\n```javascript\nfor (let [key, value] of map.entries()) {\n    console.log(key, value);\n}\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 위크맵(WeakMap)\n\nES6 이전에는 private 데이터를 저장하기 위해서 많은 방법을 사용했습니다. 그 중 한가지가 네이밍 컨벤션을 이용한 방법이죠.\n\n```javascript\nclass Person {\n    constructor(age) {\n        this._age = age;\n    }\n\n    _incrementAge() {\n        this._age += 1;\n    }\n}\n```\n\n그러나 네이밍 컨벤션은 코드베이스에 대해 혼란을 일으킬 수 있고, 항상 유지된다는 보장을 할 수 없었습니다. 이제 위크맵으로 이런 값을 저장할 수 있습니다.\n\n```javascript\nlet _age = new WeakMap();\nclass Person {\n    constructor(age) {\n        _age.set(this, age);\n    }\n\n    incrementAge() {\n        let age = _age.get(this) + 1;\n        _age.set(this, age);\n        if (age > 50) {\n            console.log('중년의 위기');\n        }\n    }\n}\n```\n\nPrivate 데이터를 저장하기 위해 위크맵을 사용해서 좋은 점은 `Reflect.ownKeys()`를 사용해도 프로퍼티 이름을 드러내지 않는다는 것입니다.\n\n```javascript\n> const person = new Person(50);\n> person.incrementAge(); // '중년의 위기'\n> Reflect.ownKeys(person); // []\n```\n\n위크맵을 사용하는 더욱 실질적인 예는 DOM 요소 자체를 훼손시키지 않고도 DOM 요소에 관련된 데이터를 저장하는 것입니다.\n\n```javascript\nlet map = new WeakMap();\nlet el  = document.getElementById('someElement');\n\n// 요소에 대한 약한 참조(weak reference)를 저장\nmap.set(el, '참조');\n\n// 요소의 값에 접근\nlet value = map.get(el); // '참조'\n\n// 참조 제거\nel.parentNode.removeChild(el);\nel = null;\n\nvalue = map.get(el); // undefined\n```\n\n위에서 보여준 대로, 객체가 가비지 콜렉터에 의해 한 번 제거된 다음에는 위크맵이 자동적으로 해당 객체에 의해 식별되는 key-value 쌍을 제거합니다.\n\n> **Note**: 더 나아가, 이 예제의 유용함을 보여주기 위해 jQuery가 참조를 가진 DOM 요소에 대응되는 객체의 캐시를 저장하는 방법을 생각해보세요. 위크맵을 사용하면, jQuery는 문서에서 지워진 특정 DOM 요소에 관련된 모든 메모리를 자동적으로 절약할 수 있습니다. 전반적으로, 위크맵은 DOM 요소를 감싸는 모든 라이브러리에 매우 유용합니다.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## Promise\n\nPromise는 다음과 같이 수평적인 코드(콜백 지옥)의 형태를 바꿀 수 있게 해줍니다.\n\n```javascript\nfunc1(function (value1) {\n    func2(value1, function (value2) {\n        func3(value2, function (value3) {\n            func4(value3, function (value4) {\n                func5(value4, function (value5) {\n                    // Do something with value 5\n                });\n            });\n        });\n    });\n});\n```\n\n수직적인 코드로 바꾸면,\n\n```javascript\nfunc1(value1)\n    .then(func2)\n    .then(func3)\n    .then(func4)\n    .then(func5, value5 => {\n        // Do something with value 5\n    });\n```\n\nES6 이전엔, [bluebird](https://github.com/petkaantonov/bluebird) 혹은 [Q](https://github.com/kriskowal/q)같은 라이브러리를 사용했었습니다. 이제는 Promise가 네이티브로 지원됩니다.\n\n```javascript\nnew Promise((resolve, reject) =>\n    reject(new Error('Promise가 제대로 동작하지 않았습니다!')))\n        .catch(reason => console.log(reason));\n```\n\nPromise가 제대로 동작(**fulfill**)했을 때 호출되는 **resolve** 메소드와 Promise가 제대로 동작하지 않(**rejected**)았을 때 호출되는 **reject** 메소드를 이용해 Promise를 다룰 수 있습니다.\n\n> **Promise의 장점**: 중첩된 콜백 코드에서는 에러 핸들링하기가 혼란스럽습니다. Promise를 사용하면 에러를 적절히 위로 깨끗하게 전파할 수 있습니다. 게다가, resolve/reject된 후의 Promise의 값은 불변입니다.\n\n아래는 Promise를 사용하는 실질적인 예제입니다.\n\n```javascript\nvar request = require('request');\n\nreturn new Promise((resolve, reject) => {\n  request.get(url, (error, response, body) => {\n    if (body) {\n        resolve(JSON.parse(body));\n      } else {\n        resolve({});\n      }\n  });\n});\n```\n\n또한 `Promise.all()`을 사용해서 비동기 동작들의 배열을 다루는 Promise를 **병렬화**할 수 있습니다.\n\n```javascript\nlet urls = [\n  '/api/commits',\n  '/api/issues/opened',\n  '/api/issues/assigned',\n  '/api/issues/completed',\n  '/api/issues/comments',\n  '/api/pullrequests'\n];\n\nlet promises = urls.map((url) => {\n  return new Promise((resolve, reject) => {\n    $.ajax({ url: url })\n      .done((data) => {\n        resolve(data);\n      });\n  });\n});\n\nPromise.all(promises)\n  .then((results) => {\n    // Do something with results of all our promises\n });\n```\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## 제너레이터(Generator)\n\n[Promise](https://github.com/DrkSephy/es6-cheatsheet/blob/master/README_ko.md#promise)를 이용해 [콜백 지옥](http://callbackhell.com/)을 피하는 것과 비슷하게, 제너레이터도 비동기적인 동작을 동기적인 느낌으로 만들어서 코드를 평평(flat)하게 만들 수 있도록 해줍니다. 제너레이터는 근본적으로 코드의 [실행을 중지](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield)하고 나중에 표현식의 값을 돌려주는 함수입니다.\n\n다음은 제너레이터를 사용하는 간단한 예입니다.\n\n```javascript\nfunction* sillyGenerator() {\n    yield 1;\n    yield 2;\n    yield 3;\n    yield 4;\n}\n\nvar generator = sillyGenerator();\n> console.log(generator.next()); // { value: 1, done: false }\n> console.log(generator.next()); // { value: 2, done: false }\n> console.log(generator.next()); // { value: 3, done: false }\n> console.log(generator.next()); // { value: 4, done: false }\n```\n[next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)를 사용하면 제너레이터를 전진시키고 새로운 표현식을 계산합니다. 위의 예제는 극히 부자연스럽지만, 다음과 같이 제너레이터는 비동기적인 코드를 동기적인 방식으로 작성하는데에 활용할 수 있습니다.\n\n```javascript\n// 제너레이터를 이용해 비동기 동작을 숨김\n\nfunction request(url) {\n    getJSON(url, function(response) {\n        generator.next(response);\n    });\n}\n```\n\n그리고 데이터를 돌려줄 제너레이터 함수를 작성합니다.\n\n```javascript\nfunction* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n}\n```\n\n`yield` 덕분에, `data1`에 데이터가 파싱될 필요가 있을 때에만 `entry1`이 데이터를 가질 것임을 보장할 수 있습니다.\n\n제너레이터는 비동기적인 코드를 동기적인 방식으로 작성하는데 도움을 주지만, 에러 전파는 깨끗하지 않고 쉽지 않은 경로를 통해 해야 합니다. 그렇기 때문에, Promise를 통해 제너레이터를 보완할 수 있습니다.\n\n```javascript\nfunction request(url) {\n    return new Promise((resolve, reject) => {\n        getJSON(url, resolve);\n    });\n}\n```\n\n그리고 `next`를 사용하는 제너레이터를 통해 단계별로 진행하는 함수를 작성합니다. `next`는 `request` 메소드를 사용하여 위의 Promise를 돌려줍니다.\n\n```javascript\nfunction iterateGenerator(gen) {\n    var generator = gen();\n    (function iterate(val) {\n        var ret = generator.next();\n        if(!ret.done) {\n            ret.value.then(iterate);\n        }\n    })();\n}\n```\n\nPromise를 통해 제너레이터를 보완함으로서, Promise의 `.catch`와 `reject`를 활용해 에러 전파를 깨끗하게 할 수 있게 되었습니다. 다음과 같이 새롭게 개선된 제너레이터를 사용하면 전보다 더 간단합니다.\n\n```javascript\niterateGenerator(function* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n});\n```\n\n구현했던 코드는 전처럼 제너레이터를 사용하기 위해서 재활용할 수 있습니다. 제너레이터와 Promise가 비동기적인 코드를 동기적인 방식으로 작성하면서도 에러 전파를 좋은 방법으로 하도록 유지시킬 수 있도록 도와줬지만, 사실, [async-await](https://github.com/DrkSephy/es6-cheatsheet/blob/master/README_ko.md#async-await)는 같은 이점을 더 간단한 형태로 활용할 수 있도록 제공합니다.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## Async Await\n\n사실 `async await`는 곧 나올 ES2016의 기능이지만, 제너레이터와 Promise를 같이써야 할 수 있었던 것들을 더 적은 노력으로 가능하게 합니다.\n\n```javascript\nvar request = require('request');\n\nfunction getJSON(url) {\n  return new Promise(function(resolve, reject) {\n    request(url, function(error, response, body) {\n      resolve(body);\n    });\n  });\n}\n\nasync function main() {\n  var data = await getJSON();\n  console.log(data); // undefined 값이 아님!\n}\n\nmain();\n```\n\n간단한 구현이지만, 제너레이터와 비슷하게 동작하는 코드입니다. 저는 제너레이터 + Promise보다는 `async-await`를 사용하는 것을 강력하게 추천드립니다. [여기](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html)에서 ES7과 Babel을 통해 실행할 수 있는 좋은 예제를 얻을 수 있습니다.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## Getter와 Setter 함수\n\nES6는 getter와 setter 함수를 지원하기 시작했습니다. 다음 예제를 보세요.\n\n```javascript\nclass Employee {\n\n    constructor(name) {\n        this._name = name;\n    }\n\n    get name() {\n      if(this._name) {\n        return this._name.toUpperCase() + ' 양';\n      } else {\n        return undefined;\n      }\n    }\n\n    set name(newName) {\n      if (newName == this._name) {\n        console.log('이미 같은 이름을 쓰고 있습니다.');\n      } else if (newName) {\n        this._name = newName;\n      } else {\n        return false;\n      }\n    }\n}\n\nvar emp = new Employee(\"솔지\");\n\n// 내부적으로 get 메소드를 활용\nif (emp.name) {\n  console.log(emp.name);  // 솔지 양\n}\n\n// 내부적으로 setter를 활용\nemp.name = \"EXID 솔지\";\nconsole.log(emp.name);  // EXID 솔지 양\n```\n\n가장 최근의 브라우저들은 객체의 getter와 setter 함수를 지원합니다. set/get 전에 리스너와 전처리작업을 추가하여 계산된 프로퍼티를 위해 getter와 settter를 활용할 수 있습니다.\n\n```javascript\nvar person = {\n  firstName: '솔지',\n  lastName: '허',\n  get fullName() {\n      console.log('이름 Get');\n      return this.lastName + ' ' + this.firstName;\n  },\n  set fullName (name) {\n      console.log('이름 Set');\n      var words = name.toString().split(' ');\n      this.lastName = words[0] || '';\n      this.firstName = words[1] || '';\n  }\n}\n\nperson.fullName; // 허 솔지\nperson.fullName = 'EXID 솔지';\nperson.fullName; // EXID 솔지\n```\n<sup>[(목차로 돌아가기)](#목차)</sup>\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 David Leonard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n<sup>[(목차로 돌아가기)](#목차)</sup>"
  },
  {
    "path": "README_zhCn.md",
    "content": "# es6-cheatsheet\n\n这是一个 ES2015(ES6) 的Cheatsheet，其中包括提示、小技巧、最佳实践和一些代码片段，帮助你\n完成日复一日的开发工作。\n\n## Table of Contents\n\n- [var 与 let / const 声明](#var-versus-let--const)\n- [代码执行块替换立即执行函数](#replacing-iifes-with-blocks)\n- [箭头函数](#arrow-functions)\n- [字符串](#strings)\n- [解构](#destructuring)\n- [模块](#modules)\n- [参数](#parameters)\n- [类](#classes)\n- [Symbols](#symbols)\n- [Maps](#maps)\n- [WeakMaps](#weakmaps)\n- [Promises](#promises)\n- [Generators](#generators)\n- [Async Await](#async-await)\n- [License](#license)\n\n## var versus let / const\n\n> 除了 `var` 以外，我们现在多了两个新的标识符来声明变量的存储，它们就是 `let` 和 `const`。\n不同于 `var` ，`let` 和 `const` 语句不会造成声明提升。\n\n一个 `var` 的例子:\n\n```javascript\nvar snack = 'Meow Mix';\n\nfunction getFood(food) {\n    if (food) {\n        var snack = 'Friskies';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // undefined\n```\n\n让我们再观察下面语句中，使用 `let` 替换了 `var` 后的表现：\n\n```javascript\nlet snack = 'Meow Mix';\n\nfunction getFood(food) {\n    if (food) {\n        let snack = 'Friskies';\n        return snack;\n    }\n    return snack;\n}\n\ngetFood(false); // 'Meow Mix'\n```\n\n当我们重构使用 `var` 的老代码时，一定要注意这种变化。盲目使用 `let` 替换 `var` 后可能会导致预期意外的结果。\n\n> **注意**：`let` 和 `const` 是块级作用域语句。所以在语句块以外引用这些变量时，会造成引用错误 `ReferenceError`。\n\n```javascript\nconsole.log(x);\n\nlet x = 'hi'; // ReferenceError: x is not defined\n```\n\n> **最佳实践**: 在重构老代码时，`var` 声明需要格外的注意。在创建一个新项目时，使用 `let` 声明一个变量，使用 `const` 来声明一个不可改变的常量。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Replacing IIFEs with Blocks\n\n我们以往创建一个 **立即执行函数** 时，一般是在函数最外层包裹一层括号。\nES6支持块级作用域（更贴近其他语言），我们现在可以通过创建一个代码块（Block）来实现，不必通过创建一个函数来实现，\n\n```javascript\n(function () {\n    var food = 'Meow Mix';\n}());\n\nconsole.log(food); // Reference Error\n```\n\n使用支持块级作用域的ES6的版本：\n\n```javascript\n{\n    let food = 'Meow Mix';\n};\n\nconsole.log(food); // Reference Error\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Arrow Functions\n\n一些时候，我们在函数嵌套中需要访问上下文中的 `this`。比如下面的例子：\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character; // Cannot read property 'name' of undefined\n    });\n};\n```\n\n一种通用的方式是把上下文中的 `this` 保存在一个变量里：\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    var that = this; // Store the context of this\n    return arr.map(function (character) {\n        return that.name + character;\n    });\n};\n```\n\n我们也可以把 `this` 通过属性传进去：\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }, this);\n};\n```\n\n还可以直接使用 `bind`：\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(function (character) {\n        return this.name + character;\n    }.bind(this));\n};\n```\n\n使用 **箭头函数**，`this` 的值不用我们再做如上几段代码的特殊处理，直接使用即可。\n上面的代码可以重写为下面这样：\n\n```javascript\nfunction Person(name) {\n    this.name = name;\n}\n\nPerson.prototype.prefixName = function (arr) {\n    return arr.map(character => this.name + character);\n};\n```\n\n> **最佳实践**：使用箭头函数，再也不用考虑 `this` 的问题了。\n\n当我们编写只返回一个表达式值的简单函数时，也可以使用箭头函数，如下：\n\n```javascript\nvar squares = arr.map(function (x) { return x * x }); // Function Expression\n```\n\n```javascript\nconst arr = [1, 2, 3, 4, 5];\nconst squares = arr.map(x => x * x); // Arrow Function for terser implementation\n```\n\n> **最佳实践**：尽可能地多使用 **箭头函数**。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Strings\n\n在ES6中，标准库也被同样增强了，像字符串对象就新增了 `.includes()` 和 `.repeat()` 方法。\n\n### .includes( )\n\n```javascript\nvar string = 'food';\nvar substring = 'foo';\n\nconsole.log(string.indexOf(substring) > -1);\n```\n\n现在，我们可以使用 `.inclues()` 方法，替代以往判断内容 `> -1` 的方式。\n`.includes()` 方法会极简地返回一个布尔值结果。\n\n```javascript\nconst string = 'food';\nconst substring = 'foo';\n\nconsole.log(string.includes(substring)); // true\n```\n\n### .repeat( )\n\n```javascript\nfunction repeat(string, count) {\n    var strings = [];\n    while(strings.length < count) {\n        strings.push(string);\n    }\n    return strings.join('');\n}\n```\n\n在ES6中，我们可以使用一个极简的方法来实现重复字符：\n\n```javascript\n// String.repeat(numberOfRepetitions)\n'meow'.repeat(3); // 'meowmeowmeow'\n```\n\n### Template Literals\n\n使用 **字符串模板字面量**，我可以在字符串中直接使用特殊字符，而不用转义。\n\n```javascript\nvar text = \"This string contains \\\"double quotes\\\" which are escaped.\";\n```\n\n```javascript\nlet text = `This string contains \"double quotes\" which don't need to be escaped anymore.`;\n```\n\n**字符串模板字面量** 还支持直接插入变量，可以实现字符串与变量的直接连接输出。\n\n```javascript\nvar name = 'Tiger';\nvar age = 13;\n\nconsole.log('My cat is named ' + name + ' and is ' + age + ' years old.');\n```\n\n更简单的版本：\n\n```javascript\nconst name = 'Tiger';\nconst age = 13;\n\nconsole.log(`My cat is named ${name} and is ${age} years old.`);\n```\n\nES5中，我们要这样生成多行文本：\n\n```javascript\nvar text = (\n    'cat\\n' +\n    'dog\\n' +\n    'nickelodeon'\n);\n```\n\n或者：\n\n```javascript\nvar text = [\n    'cat',\n    'dog',\n    'nickelodeon'\n].join('\\n');\n```\n\n**字符串模板字面量** 让我们不必特别关注多行字符串中的换行转义符号，直接换行即可：\n\n```javascript\nlet text = ( `cat\ndog\nnickelodeon`\n);\n```\n\n**字符串模板字面量** 内部可以使用表达式，像这样：\n\n```javascript\nlet today = new Date();\nlet text = `The time and date is ${today.toLocaleString()}`;\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Destructuring\n\n解构让我们可以使用非常便捷的语法，直接将数组或者对象中的值直接分别导出到多个变量中，\n\n### Destructuring Arrays\n\n**解构数组**\n\n```javascript\nvar arr = [1, 2, 3, 4];\nvar a = arr[0];\nvar b = arr[1];\nvar c = arr[2];\nvar d = arr[3];\n```\n\n```javascript\nlet [a, b, c, d] = [1, 2, 3, 4];\n\nconsole.log(a); // 1\nconsole.log(b); // 2\n```\n\n### Destructuring Objects\n\n**解构对象**\n\n```javascript\nvar luke = { occupation: 'jedi', father: 'anakin' };\nvar occupation = luke.occupation; // 'jedi'\nvar father = luke.father; // 'anakin'\n```\n\n```javascript\nlet luke = { occupation: 'jedi', father: 'anakin' };\nlet {occupation, father} = luke;\n\nconsole.log(occupation); // 'jedi'\nconsole.log(father); // 'anakin'\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Modules\n\nES6之前，浏览器端的模块化代码，我们使用像[Browserify](http://browserify.org/)这样的库，\n在 **Node.js** 中，我们则使用 [require](https://nodejs.org/api/modules.html#modules_module_require_id)。\n在ES6中，我们现在可以直接使用AMD 和 CommonJS这些模块了。\n\n### Exporting in CommonJS\n\n```javascript\nmodule.exports = 1;\nmodule.exports = { foo: 'bar' };\nmodule.exports = ['foo', 'bar'];\nmodule.exports = function bar () {};\n```\n\n### Exporting in ES6\n\n在ES6中，提供了多种设置模块出口的方式，比如我们要导出一个变量，那么使用 **变量名** ：\n\n```javascript\nexport let name = 'David';\nexport let age  = 25;​​\n```\n\n还可以为对象 **导出一个列表**：\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nexport { sumTwo, sumThree };\n```\n\n我们也可以使用简单的一个 `export` 关键字来导出一个结果值：\n\n```javascript\nexport function sumTwo(a, b) {\n    return a + b;\n}\n\nexport function sumThree(a, b, c) {\n    return a + b + c;\n}\n```\n\n最后，我们可以 **导出一个默认出口**：\n\n```javascript\nfunction sumTwo(a, b) {\n    return a + b;\n}\n\nfunction sumThree(a, b, c) {\n    return a + b + c;\n}\n\nlet api = {\n    sumTwo,\n    sumThree\n};\n\nexport default api;\n\n/*\n * 与以下的语句是对等的:\n * export { api as default };\n */\n```\n\n> **最佳实践**：总是在模块的 **最后** 使用 `export default` 方法。\n它让模块的出口更清晰明了，节省了阅读整个模块来寻找出口的时间。\n更多的是，在大量CommonJS模块中，通用的习惯是设置一个出口值或者出口对象。\n坚持这个规则，可以让我们的代码更易读，且更方便的联合使用CommonJS和ES6模块。\n\n### Importing in ES6\n\nES6提供了好几种模块的导入方式。我们可以单独引入一个文件：\n\n```javascript\nimport 'underscore';\n```\n\n> 这里需要注意的是， **整个文件的引入方式会执行该文件内的最上层代码**。\n\n就像Python一样，我们还可以命名引用：\n\n```javascript\nimport { sumTwo, sumThree } from 'math/addition';\n```\n\n我们甚至可以使用 `as` 给这些模块重命名：\n\n```javascript\nimport {\n    sumTwo as addTwoNumbers,\n    sumThree as sumThreeNumbers\n} from 'math/addition';\n```\n\n另外，我们能 **引入所有的东西（原文：import all the things）** （也称为命名空间引入）\n\n```javascript\nimport * as util from 'math/addition';\n```\n\n最后，我们能可以从一个模块的众多值中引入一个列表：\n\n```javascript\nimport * as additionUtil from 'math/addtion';\nconst { sumTwo, sumThree } = additionUtil;\n```\n像这样引用默认对象：\n\n```javascript\nimport api from 'math/addition';\n// Same as: import { default as api } from 'math/addition';\n```\n\n我们建议一个模块导出的值应该越简洁越好，不过有时候有必要的话命名引用和默认引用可以混着用。如果一个模块是这样导出的：\n\n```javascript\n// foos.js\nexport { foo as default, foo1, foo2 };\n```\n那我们可以如此导入这个模块的值：\n\n```javaqscript\nimport foo, { foo1, foo2 } from 'foos';\n```\n\n我们还可以导入commonjs模块，例如React：\n\n```javascript\nimport React from 'react';\nconst { Component, PropTypes } = React;\n```\n\n更简化版本：\n\n```javascript\nimport React, { Component, PropTypes } from 'react';\n```\n\n> **注意**：被导出的值是被 **绑定的（原文：bingdings）**，而不是引用。\n所以，改变一个模块中的值的话，会影响其他引用本模块的代码，一定要避免此种改动发生。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Parameters\n\n在ES5中，许多种方法来处理函数的 **参数默认值（default values）**，**参数数量（indefinite arguments）**，**参数命名（named parameters）**。\nES6中，我们可以使用非常简洁的语法来处理上面提到的集中情况。\n\n### Default Parameters\n\n```javascript\nfunction addTwoNumbers(x, y) {\n    x = x || 0;\n    y = y || 0;\n    return x + y;\n}\n```\n\nES6中，我们可以简单为函数参数启用默认值：\n\n```javascript\nfunction addTwoNumbers(x=0, y=0) {\n    return x + y;\n}\n```\n\n```javascript\naddTwoNumbers(2, 4); // 6\naddTwoNumbers(2); // 2\naddTwoNumbers(); // 0\n```\n\n### Rest Parameters\n\nES5中，遇到参数数量不确定时，我们只能如此处理：\n\n```javascript\nfunction logArguments() {\n    for (var i=0; i < arguments.length; i++) {\n        console.log(arguments[i]);\n    }\n}\n```\n\n使用 **rest** 操作符，我们可以给函数传入一个不确定数量的参数列表：\n\n```javascript\nfunction logArguments(...args) {\n    for (let arg of args) {\n        console.log(arg);\n    }\n}\n```\n\n### Named Parameters\n\n命名函数\nES5中，当我们要处理多个 **命名参数** 时，通常会传入一个 **选项对象** 的方式，这种方式被jQuery采用。\n\n```javascript\nfunction initializeCanvas(options) {\n    var height = options.height || 600;\n    var width  = options.width  || 400;\n    var lineStroke = options.lineStroke || 'black';\n}\n```\n\n我们可以利用上面提到的新特性 **解构** ，来完成与上面同样功能的函数：\nWe can achieve the same functionality using destructuring as a formal parameter\nto a function:\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'}) {\n        // ...\n    }\n    // Use variables height, width, lineStroke here\n```\n\n如果我们需要把这个参数变为可选的，那么只要把该参数解构为一个空对象就好了：\n\n```javascript\nfunction initializeCanvas(\n    { height=600, width=400, lineStroke='black'} = {}) {\n        // ...\n    }\n```\n\n### Spread Operator\n\n我们可以利用展开操作符（Spread Operator）来把一组数组的值，当作参数传入：\n\n```javascript\nMath.max(...[-1, 100, 9001, -32]); // 9001\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Classes\n\n在ES6以前，我们实现一个类的功能的话，需要首先创建一个构造函数，然后扩展这个函数的原型方法，就像这样：\n\n```javascript\nfunction Person(name, age, gender) {\n    this.name   = name;\n    this.age    = age;\n    this.gender = gender;\n}\n\nPerson.prototype.incrementAge = function () {\n    return this.age += 1;\n};\n```\n\n继承父类的子类需要这样：\n\n```javascript\nfunction Personal(name, age, gender, occupation, hobby) {\n    Person.call(this, name, age, gender);\n    this.occupation = occupation;\n    this.hobby = hobby;\n}\n\nPersonal.prototype = Object.create(Person.prototype);\nPersonal.prototype.constructor = Personal;\nPersonal.prototype.incrementAge = function () {\n    return Person.prototype.incrementAge.call(this) += 20;\n};\n```\n\nES6提供了一些语法糖来实现上面的功能，我们可以直接创建一个类：\n\n```javascript\nclass Person {\n    constructor(name, age, gender) {\n        this.name   = name;\n        this.age    = age;\n        this.gender = gender;\n    }\n\n    incrementAge() {\n      this.age += 1;\n    }\n}\n```\n\n继承父类的子类只要简单的使用 `extends` 关键字就可以了：\n\n```javascript\nclass Personal extends Person {\n    constructor(name, age, gender, occupation, hobby) {\n        super(name, age, gender);\n        this.occupation = occupation;\n        this.hobby = hobby;\n    }\n\n    incrementAge() {\n        super.incrementAge();\n        this.age += 20;\n        console.log(this.age);\n    }\n}\n```\n\n> **最佳实践**：ES6新的类语法把我们从晦涩难懂的实现和原型操作中解救出来，这是个非常适合初学者的功能，而且能让我们写出更干净整洁的代码。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Symbols\n\nSymbols在ES6版本之前就已经存在了，但现在我们拥有一个公共的接口来直接使用它们。\nSymbols是不可更改的（immutable）并且唯一的（unique），它可用作任何hash数据类型中的键。\n\n### Symbol( )\n调用 `Symbol()` 或者 `Symbol(描述文本)` 会创建一个唯一的、在全局中不可以访问的Symbol对象。\n一个 `Symbol()` 的应用场景是：在自己的项目中使用第三方代码库，且你需要给他们的对象或者命名空间打补丁代码，又不想改动或升级第三方原有代码的时候。\n例如，如果你想给 `React.Component` 这个类添加一个 `refreshComponent` 方法，但又确定不了这个方法会不会在下个版本中加入，你可以这么做：\n\n```javascript\nconst refreshComponent = Symbol();\n\nReact.Component.prototype[refreshComponent] = () => {\n    // do something\n}\n```\n\n### Symbol.for(key)\n\n使用 `Symbol.for(key)` 也是会创建一个不可改变的Symbol对象，但区别于上面的创建方法，这个对象是在全局中可以被访问到的。\n两次相同的 `Symbol.for(key)` 调用会返回相同的Symbol实例。\n\n**提示**：这并不同于 `Symbol(description)`。\n\n```javascript\nSymbol('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol('foo') // false\nSymbol.for('foo') === Symbol.for('foo') // true\n```\n\nSymbols常用的一个使用场景，尤其是使用 `Symbol.for(key)` 方法，是用于实现代码间的互操作。\n在你的代码中，通过在包含一些已知接口的第三方库的对象参数中查找Symbol成员，你可以实现这种互操作。\n例如：\n\n```javascript\nfunction reader(obj) {\n    const specialRead = Symbol.for('specialRead');\n    if (obj[specialRead]) {\n        const reader = obj[specialRead]();\n        // do something with reader\n    } else {\n        throw new TypeError('object cannot be read');\n    }\n}\n```\n\n之后在另一个库中：\n\n```javascript\nconst specialRead = Symbol.for('specialRead');\n\nclass SomeReadableType {\n    [specialRead]() {\n        const reader = createSomeReaderFrom(this);\n        return reader;\n    }\n}\n```\n\n> **注意**：关于Symbol互操作的使用，一个值得一提的例子是`Symbol.iterable` 。`Symbol.iterable`存在ES6的所有可枚举对象中：数组（Arrays）、\n> 字符串（strings）、生成器（Generators）等等。当它作为一个方法被调用时，它将会返回一个带有枚举接口的对象。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Maps\n\n**Maps** 是一个JavaScript中很重要（迫切需要）的数据结构。\n在ES6之前，我们创建一个 **hash** 通常是使用一个对象：\n\n```javascript\nvar map = new Object();\nmap[key1] = 'value1';\nmap[key2] = 'value2';\n```\n\n但是，这样的代码无法避免函数被特别的属性名覆盖的意外情况：\n\n```javascript\n> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');\n> TypeError: Property 'hasOwnProperty' is not a function\n```\n\n**Maps** 让我们使用 `set`，`get` 和 `search` 操作数据。\n\n```javascript\nlet map = new Map();\n> map.set('name', 'david');\n> map.get('name'); // david\n> map.has('name'); // true\n```\n\nMaps最强大的地方在于我们不必只能使用字符串来做key了，现在可以使用任何类型来当作key，而且key不会被强制类型转换为字符串。\n\n```javascript\nlet map = new Map([\n    ['name', 'david'],\n    [true, 'false'],\n    [1, 'one'],\n    [{}, 'object'],\n    [function () {}, 'function']\n]);\n\nfor (let key of map.keys()) {\n    console.log(typeof key);\n    // > string, boolean, number, object, function\n}\n```\n\n> **提示**：当使用 `map.get()` 判断值是否相等时，非基础类型比如一个函数或者对象，将不会正常工作。\n有鉴于此，还是建议使用字符串，布尔和数字类型的数据类型。\n\n我们还可以使用 `.entries()` 方法来遍历整个map对象：\n\n```javascript\nfor (let [key, value] of map.entries()) {\n    console.log(key, value);\n}\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## WeakMaps\n\n在ES5之前的版本，我们为了存储私有数据，有好几种方法。像使用这种下划线命名约定：\n\n```javascript\nclass Person {\n    constructor(age) {\n        this._age = age;\n    }\n\n    _incrementAge() {\n        this._age += 1;\n    }\n}\n```\n\n在一个开源项目中，命名规则很难维持得一直很好，这样经常会造成一些困扰。\n此时，我们可以选择使用WeakMaps来替代Maps来存储我们的数据：\n\n```javascript\nlet _age = new WeakMap();\nclass Person {\n    constructor(age) {\n        _age.set(this, age);\n    }\n\n    incrementAge() {\n        let age = _age.get(this) + 1;\n        _age.set(this, age);\n        if (age > 50) {\n            console.log('Midlife crisis');\n        }\n    }\n}\n```\n\n使用WeakMaps来保存我们私有数据的理由之一是不会暴露出属性名，就像下面的例子中的 `Reflect.ownKeys()`：\n\n```javascript\n> const person = new Person(50);\n> person.incrementAge(); // 'Midlife crisis'\n> Reflect.ownKeys(person); // []\n```\n\n一个使用WeakMaps存储数据更实际的例子，是存储与DOM元素相关联的数据，而这不会对DOM元素本身产生污染：\n\n```javascript\nlet map = new WeakMap();\nlet el  = document.getElementById('someElement');\n\n// Store a weak reference to the element with a key\nmap.set(el, 'reference');\n\n// Access the value of the element\nlet value = map.get(el); // 'reference'\n\n// Remove the reference\nel.parentNode.removeChild(el);\nel = null;\n\nvalue = map.get(el); // undefined\n```\n\n上面的例子中，一旦对象被垃圾回收器给销毁了，WeakMaps会自动的把这个对象所对应的键值对数据同时销毁。\n\n> **提示**：结合这个例子，再考虑下jQuery是如何实现缓存带有引用的DOM元素这个功能的。使用WeakMaps的话，当被缓存的DOM元素被移除的时，jQuery可以自动释放相应元素的内存。\n通常情况下，在涉及DOM元素存储和缓存的情况下，使用WeakMaps是非常有效的。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Promises\n\nPromises让我们把多缩进难看的代码（回调地狱）：\n\n```javascript\nfunc1(function (value1) {\n    func2(value1, function (value2) {\n        func3(value2, function (value3) {\n            func4(value3, function (value4) {\n                func5(value4, function (value5) {\n                    // Do something with value 5\n                });\n            });\n        });\n    });\n});\n```\n\n写成这样：\n\n```javascript\nfunc1(value1)\n    .then(func2)\n    .then(func3)\n    .then(func4)\n    .then(func5, value5 => {\n        // Do something with value 5\n    });\n```\n\n在ES6之前，我们使用[bluebird](https://github.com/petkaantonov/bluebird) 或者\n[Q](https://github.com/kriskowal/q)。现在我们有了原生版本的 Promises：\n\n```javascript\nnew Promise((resolve, reject) =>\n    reject(new Error('Failed to fulfill Promise')))\n        .catch(reason => console.log(reason));\n```\n\n这里有两个处理函数，**resolve**（当Promise执行成功完毕时调用的回调函数） 和 **reject** （当Promise执行不接受时调用的回调函数）\n\n> **Promises的好处**：大量嵌套错误处理回调函数会使代码变得难以阅读理解。\n使用Promises，我们可以通过清晰的路径将错误事件让上传递，并且适当地处理它们。\n此外，Promise处理后的值，无论是解决（resolved）还是拒绝（rejected）的结果值，都是不可改变的。\n\n下面是一些使用Promises的实际例子：\n\n```javascript\nvar request = require('request');\n\nreturn new Promise((resolve, reject) => {\n  request.get(url, (error, response, body) => {\n    if (body) {\n        resolve(JSON.parse(body));\n      } else {\n        resolve({});\n      }\n  });\n});\n```\n\n我们还可以使用 `Promise.all()` 来 **并行化** 的处理一组异步的操作。\n\n```javascript\nlet urls = [\n  '/api/commits',\n  '/api/issues/opened',\n  '/api/issues/assigned',\n  '/api/issues/completed',\n  '/api/issues/comments',\n  '/api/pullrequests'\n];\n\nlet promises = urls.map((url) => {\n  return new Promise((resolve, reject) => {\n    $.ajax({ url: url })\n      .done((data) => {\n        resolve(data);\n      });\n  });\n});\n\nPromise.all(promises)\n  .then((results) => {\n    // Do something with results of all our promises\n });\n```\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Generators\n\n就像[Promises](https://github.com/DrkSephy/es6-cheatsheet#promises)如何让我们避免[回调地狱](http://callbackhell.com/)一样，Generators也可以使我们的代码扁平化，同时给予我们开发者像开发同步代码一样的感觉来写异步代码。Generators本质上是一种支持的函数，随后返回表达式的值。\nGenerators实际上是支持[暂停运行](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield)，随后根据上一步的返回值再继续运行的一种函数。\n\n下面代码是一个使用generators函数的简单例子：\n\n```javascript\nfunction* sillyGenerator() {\n    yield 1;\n    yield 2;\n    yield 3;\n    yield 4;\n}\n\nvar generator = sillyGenerator();\n> console.log(generator.next()); // { value: 1, done: false }\n> console.log(generator.next()); // { value: 2, done: false }\n> console.log(generator.next()); // { value: 3, done: false }\n> console.log(generator.next()); // { value: 4, done: false }\n```\n\n就像上面的例子，当[next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)运行时，它会把我们的generator向前“推动”，同时执行新的表达式。\n我们能利用Generators来像书写同步代码一样书写异步代码。\n\n```javascript\n// Hiding asynchronousity with Generators\n\nfunction request(url) {\n    getJSON(url, function(response) {\n        generator.next(response);\n    });\n}\n```\n\n这里我们写个generator函数将要返回我们的数据：\n\n```javascript\nfunction* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n}\n```\n\n借助于 `yield`，我们可以保证 `entry1` 确实拿到数据并转换后再赋值给 `data1`。\n\n当我们使用generators来像书写同步代码一样书写我们的异步代码逻辑时，没有一种清晰简单的方式来处理期间可能会产生的错误或者异常。在这种情况下，我们可以在我们的generator中引入Promises来处理，就像下面这样：\n\n```javascript\nfunction request(url) {\n    return new Promise((resolve, reject) => {\n        getJSON(url, resolve);\n    });\n}\n```\n\n我们再写一个函数，其中使用 `next` 来步进我们的generator的同事，再利用我们上面的 `request` 方法来产生（yield）一个Promise。\n\n```javascript\nfunction iterateGenerator(gen) {\n    var generator = gen();\n    var ret;\n    (function iterate(val) {\n        ret = generator.next();\n        if(!ret.done) {\n            ret.value.then(iterate);\n        }\n    })();\n}\n```\n\n在Generator中引入了Promises后，我们就可以通过Promise的 `.catch` 和 `reject` 来捕捉和处理错误了。\n使用了我们新版的Generator后，新版的调用就像老版本一样简单可读（译者注：有微调）：\n\n```javascript\niterateGenerator(function* getData() {\n    var entry1 = yield request('http://some_api/item1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http://some_api/item2');\n    var data2  = JSON.parse(entry2);\n});\n```\n\n在使用Generator后，我们可以重用我们的老版本代码实现，以此展示了Generator的力量。\n当使用Generators和Promises后，我们可以像书写同步代码一样书写异步代码的同时优雅地解决了错误处理问题。\n此后，我们实际上可以开始利用更简单的一种方式了，它就是[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await)。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## Async Await\n\n`async await` 随着ES2016版本就要发布了，它给我们提供了一种更轻松的、更简单的可以替代的实现上面 Generators 配合 Promises 组合代码的一种编码方式，让我们来看看例子：\n\n```javascript\nvar request = require('request');\n\nfunction getJSON(url) {\n  return new Promise(function(resolve, reject) {\n    request(url, function(error, response, body) {\n      resolve(body);\n    });\n  });\n}\n\nasync function main() {\n  var data = await getJSON();\n  console.log(data); // NOT undefined!\n}\n\nmain();\n```\n\n它们看上去和Generators很像。我（作者）强烈推荐使用 `async await` 来替代Generators + Promises的写法。\n[这里](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html)是个很好的学习资源，让我们学习和使用这项ES7中的新功能。\n\n<sup>[(回到目录)](#table-of-contents)</sup>\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 David Leonard\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n<sup>[(回到目录)](#table-of-contents)</sup>"
  },
  {
    "path": "src/convert.js",
    "content": "console.log('Converting repository to JavaScript');"
  }
]