[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-3396":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":16,"starSnapshotCount":16,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},3396,"es6-cheatsheet","DrkSephy\u002Fes6-cheatsheet","DrkSephy","ES2015 [ES6] cheatsheet containing tips, tricks, best practices and code snippets","http:\u002F\u002Fslides.com\u002Fdrksephy\u002Fecmascript-2015",null,"JavaScript",13330,1116,344,5,0,4,44.14,false,"master",true,[23,24,25],"cheatsheet","es6-javascript","javascript","2026-06-12 02:00:49","# 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 \u002F 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\u002FSetter functions](#getter-and-setter-functions)\n- [License](#license)\n\n## var versus let \u002F 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); \u002F\u002F 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); \u002F\u002F '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); \u002F\u002F 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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); \u002F\u002F Reference Error\n```\n\nUsing ES6 Blocks:\n\n```javascript\n{\n    let food = 'Meow Mix';\n};\n\nconsole.log(food); \u002F\u002F Reference Error\n```\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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; \u002F\u002F 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; \u002F\u002F 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 }); \u002F\u002F Function Expression\n```\n\n```javascript\nconst arr = [1, 2, 3, 4, 5];\nconst squares = arr.map(x => x * x); \u002F\u002F Arrow Function for terser implementation\n```\n\n> **Best Practice**: Use **Arrow Functions** in place of function expressions\nwhen possible.\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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)); \u002F\u002F true\n```\n\n### .repeat( )\n\n```javascript\nfunction repeat(string, count) {\n    var strings = [];\n    while(strings.length \u003C 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\u002F\u002F String.repeat(numberOfRepetitions)\n'meow'.repeat(3); \u002F\u002F '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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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); \u002F\u002F 1\nconsole.log(b); \u002F\u002F 2\n```\n\n### Destructuring Objects\n\n```javascript\nvar luke = { occupation: 'jedi', father: 'anakin' };\nvar occupation = luke.occupation; \u002F\u002F 'jedi'\nvar father = luke.father; \u002F\u002F 'anakin'\n```\n\n```javascript\nlet luke = { occupation: 'jedi', father: 'anakin' };\nlet {occupation, father} = luke;\n\nconsole.log(occupation); \u002F\u002F 'jedi'\nconsole.log(father); \u002F\u002F 'anakin'\n```\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\n\n## Modules\n\nPrior to ES6, we used libraries such as [Browserify](http:\u002F\u002Fbrowserify.org\u002F)\nto create modules on the client-side, and [require](https:\u002F\u002Fnodejs.org\u002Fapi\u002Fmodules.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\u002F* Which is the same as\n * export { api as default };\n *\u002F\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\u002Faddition';\n```\n\nWe can also rename the named imports:\n\n```javascript\nimport {\n    sumTwo as addTwoNumbers,\n    sumThree as sumThreeNumbers\n} from 'math\u002Faddition';\n```\n\nIn addition, we can **import all the things** (also called namespace import):\n\n```javascript\nimport * as util from 'math\u002Faddition';\n```\n\nLastly, we can import a list of values from a module:\n\n```javascript\nimport * as additionUtil from 'math\u002Faddition';\nconst { sumTwo, sumThree } = additionUtil;\n```\nImporting from the default binding like this:\n\n```javascript\nimport api from 'math\u002Faddition';\n\u002F\u002F Same as: import { default as api } from 'math\u002Faddition';\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\u002F\u002F 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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); \u002F\u002F 6\naddTwoNumbers(2); \u002F\u002F 2\naddTwoNumbers(); \u002F\u002F 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 \u003C 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        \u002F\u002F 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        \u002F\u002F ...\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]); \u002F\u002F 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]); \u002F\u002F 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']; \u002F\u002F ['Miami', 'San Francisco', 'Los Angeles', 'Chicago']\n```\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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    \u002F\u002F 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') \u002F\u002F false\nSymbol.for('foo') === Symbol('foo') \u002F\u002F false\nSymbol.for('foo') === Symbol.for('foo') \u002F\u002F 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        \u002F\u002F 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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'); \u002F\u002F david\n> map.has('name'); \u002F\u002F 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    \u002F\u002F > 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\n\n## WeakMaps\n\nIn order to store private data versions \u003C 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(); \u002F\u002F 'Midlife crisis'\n> Reflect.ownKeys(person); \u002F\u002F []\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\u002F\u002F Store a weak reference to the element with a key\nmap.set(el, 'reference');\n\n\u002F\u002F Access the value of the element\nlet value = map.get(el); \u002F\u002F 'reference'\n\n\u002F\u002F Remove the reference\nel.parentNode.removeChild(el);\nel = null;\n\n\u002F\u002F 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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                    \u002F\u002F 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        \u002F\u002F Do something with value 5\n    });\n```\n\nPrior to ES6, we used [bluebird](https:\u002F\u002Fgithub.com\u002Fpetkaantonov\u002Fbluebird) or\n[Q](https:\u002F\u002Fgithub.com\u002Fkriskowal\u002Fq). 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\u002Frejected 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  '\u002Fapi\u002Fcommits',\n  '\u002Fapi\u002Fissues\u002Fopened',\n  '\u002Fapi\u002Fissues\u002Fassigned',\n  '\u002Fapi\u002Fissues\u002Fcompleted',\n  '\u002Fapi\u002Fissues\u002Fcomments',\n  '\u002Fapi\u002Fpullrequests'\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    \u002F\u002F Do something with results of all our promises\n });\n```\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\n\n## Generators\n\nSimilar to how [Promises](https:\u002F\u002Fgithub.com\u002FDrkSephy\u002Fes6-cheatsheet#promises) allow us to avoid\n[callback hell](http:\u002F\u002Fcallbackhell.com\u002F), 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:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FOperators\u002Fyield)\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()); \u002F\u002F { value: 1, done: false }\n> console.log(generator.next()); \u002F\u002F { value: 2, done: false }\n> console.log(generator.next()); \u002F\u002F { value: 3, done: false }\n> console.log(generator.next()); \u002F\u002F { value: 4, done: false }\n```\n\nWhere [next](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects\u002FGenerator\u002Fnext)\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\u002F\u002F 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:\u002F\u002Fsome_api\u002Fitem1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http:\u002F\u002Fsome_api\u002Fitem2');\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:\u002F\u002Fsome_api\u002Fitem1');\n    var data1  = JSON.parse(entry1);\n    var entry2 = yield request('http:\u002F\u002Fsome_api\u002Fitem2');\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:\u002F\u002Fgithub.com\u002FDrkSephy\u002Fes6-cheatsheet#async-await).\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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); \u002F\u002F 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:\u002F\u002Fmasnun.com\u002F2015\u002F11\u002F11\u002Fusing-es7-asyncawait-today-with-babel.html).\n\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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\u002F\u002F uses the get method in the background\nif (emp.name) {\n  console.log(emp.name);  \u002F\u002F Mr. JAMES BOND\n}\n\n\u002F\u002F uses the setter in the background\nemp.name = \"Bond 007\";\nconsole.log(emp.name);  \u002F\u002F Mr. BOND 007  \n```\n\nLatest browsers are also supporting getter\u002Fsetter functions in Objects and we can use them for computed properties, adding listeners and preprocessing before setting\u002Fgetting:\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; \u002F\u002F James Bond\nperson.fullName = 'Bond 007';\nperson.fullName; \u002F\u002F Bond 007\n```\n\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>\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\u002For 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\u003Csup>[(back to table of contents)](#table-of-contents)\u003C\u002Fsup>","该项目是一个ES2015（ES6）速查表，提供了大量关于ES6的技巧、最佳实践和代码片段。其核心功能包括对`let`与`const`的使用说明、立即执行函数表达式（IIFE）替换方案、箭头函数等ES6新特性的详细解析和技术示例。项目以简洁清晰的方式呈现内容，便于开发者快速掌握并应用于日常开发中。适合于正在学习或希望深入了解ES6特性的前端工程师，以及需要进行旧代码库向现代JavaScript迁移的团队。",2,"2026-06-11 02:54:02","top_language"]