From 3a899c022de9f231e36c4602c43aab479202849a Mon Sep 17 00:00:00 2001 From: Jordan Schalm Date: Thu, 21 Jan 2016 23:06:50 -0800 Subject: [PATCH 01/84] Typos & Grammar --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b334e3a..4f18ecd 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ console.log(food); // Reference Error ## Arrow Functions -Often times we have nested functions in which we would like to preserve the context of **this** from it's lexical scope. An example is shown below: +Often times we have nested functions in which we would like to preserve the context of **this** from its lexical scope. An example is shown below: ```javascript function Person(name) { @@ -352,7 +352,7 @@ var api = { export default api ``` -> **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. Moreso, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allows us to interpolate between CommonJS and ES6 modules. +> **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. Moreso, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allow ourselves to interpolate between CommonJS and ES6 modules. ### Importing in ES6 @@ -546,7 +546,7 @@ class Personal extends Person { } ``` -> **Best Practice**: While the syntax for creating classes in ES6 obscure how implementation and prototypes work under the hood, it is a good feature for beginners and allows us to write cleaner code. +> **Best Practice**: While the syntax for creating classes in ES6 obscures how implementation and prototypes work under the hood, it is a good feature for beginners and allows us to write cleaner code. [(back to table of contents)](#table-of-contents) @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From 2ca49ff06846fff43f423a9f43c0951204db3143 Mon Sep 17 00:00:00 2001 From: Kilian Valkhof Date: Fri, 22 Jan 2016 09:58:19 +0100 Subject: [PATCH 02/84] remove duplicate "}from" in named import example there was a double "} from" in the named import example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b334e3a..f189fa2 100644 --- a/README.md +++ b/README.md @@ -375,7 +375,7 @@ Similar to Python, we have named imports: ```javascript import { sumTwo as addTwoNumbers, - sumThree as sumThreeNumbers} from + sumThree as sumThreeNumbers } from 'math/addition' ``` @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From 8866dd05ba64bb3189c074034bcfba642821cc8e Mon Sep 17 00:00:00 2001 From: Carlo Cruz Date: Fri, 22 Jan 2016 21:52:04 +1100 Subject: [PATCH 03/84] Typo Fix a typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b334e3a..1ce83d4 100644 --- a/README.md +++ b/README.md @@ -250,7 +250,7 @@ let text = `The time and date is ${today.toLocaleString()}` ## Destructuring -Destructuring allows us to extract values from arrays and objects (even deeply nested) and store them in variables with a more convient syntax. +Destructuring allows us to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax. ### Destructuring Arrays From c0d1b93b27c45a3d0a428bdffef637b33d662941 Mon Sep 17 00:00:00 2001 From: Canop Date: Fri, 22 Jan 2016 12:43:25 +0100 Subject: [PATCH 04/84] replaced var with let in ES6 code examples --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b334e3a..1d1d3c8 100644 --- a/README.md +++ b/README.md @@ -232,7 +232,7 @@ var text = [ **Template Literals** will preserve new lines for us without having to explicitly place them in: ```javascript -var text = ( +let text = ( `cat dog nickelodeon` @@ -263,7 +263,7 @@ var d = arr[3]; ``` ```javascript -var [a, b, c, d] = [1, 2, 3, 4]; +let [a, b, c, d] = [1, 2, 3, 4]; console.log(a); // 1 console.log(b); // 2 ``` @@ -277,8 +277,8 @@ var father = luke.father; // 'anakin' ``` ```javascript -var luke = { occupation: 'jedi', father: 'anakin' } -var {occupation, father} = luke; +let luke = { occupation: 'jedi', father: 'anakin' } +let {occupation, father} = luke; console.log(occupation); // 'jedi' console.log(father); // 'anakin' ``` @@ -303,8 +303,8 @@ module.exports = function bar () {} With ES6, we have various flavors of exporting. We can perform **Named Exports**: ```javascript -export var name = 'David'; -export var age = 25;​​ +export let name = 'David'; +export let age = 25;​​ ``` As well as **exporting a list** of objects: @@ -344,7 +344,7 @@ function sumThree(a, b) { return a + b + c; } -var api = { +let api = { sumTwo : sumTwo, sumThree: sumThree } @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From 4974e142923d2eb6b95f73f8a78a82f8a9ceab55 Mon Sep 17 00:00:00 2001 From: Simon Wicki Date: Fri, 22 Jan 2016 13:02:52 +0100 Subject: [PATCH 05/84] fix: fulfill typo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b334e3a..27b225b 100644 --- a/README.md +++ b/README.md @@ -700,11 +700,11 @@ Prior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or [Q ```javascript new Promise((resolve, reject) => - reject(new Error('Failed to fufill Promise'))) + reject(new Error('Failed to fulfill Promise'))) .catch(reason => console.log(reason)); ``` -Where we have two handlers, **resolve** (a function called when the Promise is **fufilled**) and **rejected** (a function called when the Promise is **rejected**). +Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **rejected** (a function called when the Promise is **rejected**). > **Benefits of Promises**: Error Handling using a bunch of nested callbacks can get chaotic. Using Promises, we have a clear path to bubbling errors up and handling them appropriately. Moreover, the value of a Promise after it has been resolved/rejected is immutable - it will never change. @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From e59801dd2917c1e5b24bce53cc4ed7f89f16aa68 Mon Sep 17 00:00:00 2001 From: Farid Nouri Neshat Date: Fri, 22 Jan 2016 20:10:46 +0800 Subject: [PATCH 06/84] Fix symbols example --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b334e3a..14e2c1c 100644 --- a/README.md +++ b/README.md @@ -559,8 +559,8 @@ const key = Symbol(); const keyTwo = Symbol(); const object = {}; -object.key = 'Such magic.'; -object.keyTwo = 'Much Uniqueness' +object[key] = 'Such magic.'; +object[keyTwo] = 'Much Uniqueness' // Two Symbols will never have the same value >> key === keyTwo @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From d16e1bec53ea420dbd8b380836eb3cf6657c35a1 Mon Sep 17 00:00:00 2001 From: Canop Date: Fri, 22 Jan 2016 13:11:36 +0100 Subject: [PATCH 07/84] less verbose API declaration --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d1d3c8..fb567e5 100644 --- a/README.md +++ b/README.md @@ -345,8 +345,8 @@ function sumThree(a, b) { } let api = { - sumTwo : sumTwo, - sumThree: sumThree + sumTwo, + sumThree } export default api From d9021e3d4956baabf29e7d1a63bf9d3651a25e16 Mon Sep 17 00:00:00 2001 From: Farid Nouri Neshat Date: Fri, 22 Jan 2016 20:14:48 +0800 Subject: [PATCH 08/84] Fix promises example --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b334e3a..62edc27 100644 --- a/README.md +++ b/README.md @@ -688,10 +688,10 @@ Into vertical code: ```javascript func1(value1) - .then(func2(value1) { }) - .then(func3(value2) { }) - .then(func4(value3) { }) - .then(func5(value4) { + .then(func2) + .then(func3) + .then(func4) + .then(func5, value5 => { // Do something with value 5 }); ``` @@ -738,4 +738,4 @@ Promise.all(urlPromises) .catch(function(err) { console.log("Failed: ", err); }); -``` \ No newline at end of file +``` From b37f07b56fa675f2acd4c458882a0401705e1201 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 22 Jan 2016 10:14:03 -0500 Subject: [PATCH 09/84] Updated WeakMap example to actually increment age --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 618c9ef..d9048ca 100644 --- a/README.md +++ b/README.md @@ -648,7 +648,8 @@ class Person { } incrementAge() { - let age = _age.get(this); + let age = _age.get(this) + 1; + _age.set(this, age); if(age > 50) { console.log('Midlife crisis'); } From 25e4c8ba2bfc0205bae08ede5dffa51a0e4a4c36 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 22 Jan 2016 11:05:58 -0500 Subject: [PATCH 10/84] Converting repository to JavaScript --- src/convert.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/convert.js diff --git a/src/convert.js b/src/convert.js new file mode 100644 index 0000000..907250a --- /dev/null +++ b/src/convert.js @@ -0,0 +1 @@ +console.log('Converting repository to JavaScript'); \ No newline at end of file From 43847661c9c07ca4fb9b99e29bebf49e852c2ae4 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 22 Jan 2016 12:31:13 -0500 Subject: [PATCH 11/84] remove a line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d9048ca..7f1e9fa 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ However, observe what happens when we replace **var** using **let**: let snack = 'Meow Mix'; function getFood(food) { - if (food) { let snack = 'Friskies'; return snack; From f6b24d8709f9c2a5d75263ca8ec06d1529695f01 Mon Sep 17 00:00:00 2001 From: Demian Ferreiro Date: Fri, 22 Jan 2016 14:37:24 -0300 Subject: [PATCH 12/84] Adjust multiline template string example Remove indentation from template string so it is equivalent to the other snippets, i.e., `"cat\ndog\nnickelodeon"` instead of `"cat\n dog\n nickelodeon"`. --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d9048ca..4e915cf 100644 --- a/README.md +++ b/README.md @@ -232,11 +232,9 @@ var text = [ **Template Literals** will preserve new lines for us without having to explicitly place them in: ```javascript -let text = ( - `cat - dog - nickelodeon` -) +let text = `cat +dog +nickelodeon` ``` **Template Literals** can accept expressions, as well: From 0459edfcbd0b23b1489a08112d4a748aa8c860a4 Mon Sep 17 00:00:00 2001 From: Bulat Bochkariov Date: Fri, 22 Jan 2016 10:40:18 -0800 Subject: [PATCH 13/84] Added missing argument to export example --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d9048ca..f377141 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ function sumTwo(a, b) { return a + b; } -function sumThree(a, b) { +function sumThree(a, b, c) { return a + b + c; } @@ -328,7 +328,7 @@ export function sumTwo(a, b) { return a + b; } -export function sumThree(a, b) { +export function sumThree(a, b, c) { return a + b + c; } ``` @@ -340,7 +340,7 @@ function sumTwo(a, b) { return a + b; } -function sumThree(a, b) { +function sumThree(a, b, c) { return a + b + c; } From 3c92912e4a06d76a7880d7998b642636fbd01beb Mon Sep 17 00:00:00 2001 From: Alexander Burtsev Date: Fri, 22 Jan 2016 21:43:05 +0300 Subject: [PATCH 14/84] Update README.md Adds missed argument in declaration of function `sumThree` --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d9048ca..f377141 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,7 @@ function sumTwo(a, b) { return a + b; } -function sumThree(a, b) { +function sumThree(a, b, c) { return a + b + c; } @@ -328,7 +328,7 @@ export function sumTwo(a, b) { return a + b; } -export function sumThree(a, b) { +export function sumThree(a, b, c) { return a + b + c; } ``` @@ -340,7 +340,7 @@ function sumTwo(a, b) { return a + b; } -function sumThree(a, b) { +function sumThree(a, b, c) { return a + b + c; } From b2990154684b99b3af61caa521c8eb61ef069dd8 Mon Sep 17 00:00:00 2001 From: Bulat Bochkariov Date: Fri, 22 Jan 2016 10:43:24 -0800 Subject: [PATCH 15/84] Fixed typo in map example "Propery" -> "Property" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d9048ca..cc43008 100644 --- a/README.md +++ b/README.md @@ -583,7 +583,7 @@ However, this does not protect us from accidentally overriding functions with sp ```javascript > getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned'); -> TypeError: Propery 'hasOwnProperty' is not a function +> TypeError: Property 'hasOwnProperty' is not a function ``` Actual **Maps** allow us to **set**, **get** and **search** for values (and much more). From 9c12d136836123236c2e6c3d15b123da08160607 Mon Sep 17 00:00:00 2001 From: Yingbai He Date: Fri, 22 Jan 2016 10:48:33 -0800 Subject: [PATCH 16/84] yh: modify named imports --- README.md | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d9048ca..65f7f8d 100644 --- a/README.md +++ b/README.md @@ -364,27 +364,41 @@ import `underscore` > It is important to note that simply **importing an entire file will execute all code at the top level of that file**. -We can also use destructuring to import a list of values from a file: +Similar to Python, we have named imports: ```javascript import { sumTwo, sumThree } from 'math/addition' ``` -Similar to Python, we have named imports: +We can also rename the named imports: ```javascript -import { - sumTwo as addTwoNumbers, +import { + sumTwo as addTwoNumbers, sumThree as sumThreeNumbers } from 'math/addition' ``` -And lastly, we can **import all the things**: +In addition, we can **import all the things** (also called namespace import): ```javascript import * as util from 'math/addition' ``` +Lastly, we can use destructuring to import a list of values from a file: + +```javascript +import * as addtionUtil from 'math/addtion'; +const { sumTwo, sumThree } = addtionUtil; +``` + +or when we are importing the default object but we want to grab some of the functions on the object: + +```javascript +import React from 'react'; +const { Component, PropTypes } = React; +``` + > **Note**: Values that are exported are **bindings**, not references. Therefore, changing the binding of a variable in one module will affect the value within the exported module. Avoid changing the public interface of these exported values. [(back to table of contents)](#table-of-contents) From fbde5ac76cf463351885139adb73439a4b875a38 Mon Sep 17 00:00:00 2001 From: John Bacon Date: Fri, 22 Jan 2016 13:56:08 -0500 Subject: [PATCH 17/84] Modify var vs. let formatting to be consistent --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d9048ca..7f1e9fa 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ However, observe what happens when we replace **var** using **let**: let snack = 'Meow Mix'; function getFood(food) { - if (food) { let snack = 'Friskies'; return snack; From 20babeedc0da193629d1cddec4dd7b3bba26dc07 Mon Sep 17 00:00:00 2001 From: Yogesh Date: Sat, 23 Jan 2016 03:54:13 +0530 Subject: [PATCH 18/84] Found a typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d9048ca..a143b8d 100644 --- a/README.md +++ b/README.md @@ -352,7 +352,7 @@ let api = { export default api ``` -> **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. Moreso, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allow ourselves to interpolate between CommonJS and ES6 modules. +> **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. More so, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allow ourselves to interpolate between CommonJS and ES6 modules. ### Importing in ES6 From 641627eaa3d42bf7486079e36037fb8c191384e7 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 22 Jan 2016 18:25:08 -0500 Subject: [PATCH 19/84] Resolved #22 --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4664245..a5b4992 100644 --- a/README.md +++ b/README.md @@ -231,11 +231,14 @@ var text = [ **Template Literals** will preserve new lines for us without having to explicitly place them in: ```javascript -let text = `cat -dog -nickelodeon` +let text = ( ` + cat + dog + nickelodeon` +) ``` + **Template Literals** can accept expressions, as well: ```javascript From 188c60cf9c632d4ec8662a4d927e7c54abb37e3c Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 22 Jan 2016 22:13:20 -0500 Subject: [PATCH 20/84] Fixing minor typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5b4992..4475890 100644 --- a/README.md +++ b/README.md @@ -388,8 +388,8 @@ import * as util from 'math/addition' Lastly, we can use destructuring to import a list of values from a file: ```javascript -import * as addtionUtil from 'math/addtion'; -const { sumTwo, sumThree } = addtionUtil; +import * as additionUtil from 'math/addtion'; +const { sumTwo, sumThree } = additionUtil; ``` or when we are importing the default object but we want to grab some of the functions on the object: From 12d2259ad7282d1161ac81d8fc9c45a6827f4e89 Mon Sep 17 00:00:00 2001 From: Brian Delahunty Date: Fri, 22 Jan 2016 19:58:44 -0800 Subject: [PATCH 21/84] Fix Template Literals Comparison The string comparison in the `Template Literals` section was incorrect. It was comparing - es5 ```js var text = ( 'cat\n' + 'dog\n' + 'nickelodeon' ) ``` and ```javascript var text = [ 'cat', 'dog', 'nickelodeon' ].join('\n') ``` to - es6 ```javascript let text = ( ` cat dog nickelodeon` ) ``` However, both of the es5 examples result in a string equivalent to: `'cat\ndog\nnickelodeon'` Whereas the previous es6 example results in: `'\n cat\n dog\n nickelodeon'` After this change the es6 example is now the same as the es5 examples: 'cat\ndog\nnickelodeon' --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4475890..3829466 100644 --- a/README.md +++ b/README.md @@ -231,10 +231,9 @@ var text = [ **Template Literals** will preserve new lines for us without having to explicitly place them in: ```javascript -let text = ( ` - cat - dog - nickelodeon` +let text = ( `cat +dog +nickelodeon` ) ``` From f8b8c9e86832d2663a15cc412245a1bdea840c02 Mon Sep 17 00:00:00 2001 From: Andrei Eftimie Date: Sat, 23 Jan 2016 06:21:41 +0200 Subject: [PATCH 22/84] Whitespace cleanup --- README.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 4475890..6182d25 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ A cheatsheet containing ES6 tips, tricks, best practices and code snippet exampl ## var versus let / const -> Besides var, we now have access to two new identifiers for storing values - **let** and **const**. Unlike **var**, **let** and **const** statements are not hoisted to the top of their enclosing scope. +> Besides var, we now have access to two new identifiers for storing values - **let** and **const**. Unlike **var**, **let** and **const** statements are not hoisted to the top of their enclosing scope. An example of using var: @@ -53,7 +53,7 @@ function getFood(food) { getFood(false); // 'Meow Mix' ``` -This change in behavior highlights that we need to be careful when refactoring legacy code which uses **var**. Blindly replacing instances of **var** with **let** may lead to unexpected behavior. +This change in behavior highlights that we need to be careful when refactoring legacy code which uses **var**. Blindly replacing instances of **var** with **let** may lead to unexpected behavior. > **Best Practice**: Leave **var** declarations inside of legacy code to denote that it needs to be carefully refactored. When working on a new codebase, use **let** for variables that will change their value over time, and **const** for variables that will be immutable over time. @@ -64,18 +64,18 @@ This change in behavior highlights that we need to be careful when refactoring l > A common use of **Immediately Invoked Function Expressions** is to enclose values within its scope. In ES6, we now have the ability to create block-based scopes and therefore are not limited purely to function-based scope. ```javascript -(function () { +(function () { var food = 'Meow Mix'; -}()); +}()); console.log(food); // Reference Error ``` Using ES6 Blocks: ```javascript -{ +{ let food = 'Meow Mix'; -} +} console.log(food); // Reference Error ``` @@ -120,11 +120,11 @@ function Person(name) { } Person.prototype.prefixName = function (arr) { - return arr.map((character) => this.name + character); + return arr.map((character) => this.name + character); } ``` -> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the lexical value of **this**. +> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the lexical value of **this**. Arrow Functions are also more concise when used in function expressions which simply return a value: @@ -250,7 +250,7 @@ let text = `The time and date is ${today.toLocaleString()}` ## Destructuring -Destructuring allows us to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax. +Destructuring allows us to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax. ### Destructuring Arrays @@ -535,7 +535,7 @@ class Person { this.age = age; this.gender = gender; } - + incrementAge() { this.age += 1; } @@ -551,7 +551,7 @@ class Personal extends Person { this.occupation = occupation; this.hobby = hobby; } - + incrementAge() { super.incrementAge(); this.age += 20; @@ -577,7 +577,7 @@ object[key] = 'Such magic.'; object[keyTwo] = 'Much Uniqueness' // Two Symbols will never have the same value ->> key === keyTwo +>> key === keyTwo >> false ``` @@ -638,14 +638,14 @@ for (let [key, value] of map.entries()) { ## WeakMaps -In order to store private data in < ES5, we had various ways of doing this. One such method was using naming conventions: +In order to store private data in < ES5, we had various ways of doing this. One such method was using naming conventions: ```javascript class Person { constructor(age) { this._age = age; } - + _incrementAge() { this._age += 1; } @@ -656,7 +656,7 @@ But naming conventions can cause confusion in a codebase and are not always goin ```javascript let _age = new WeakMap(); -class Person { +class Person { constructor(age) { _age.set(this, age); } @@ -706,27 +706,27 @@ func1(value1) .then(func2) .then(func3) .then(func4) - .then(func5, value5 => { - // Do something with value 5 + .then(func5, value5 => { + // Do something with value 5 }); ``` Prior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or [Q](https://github.com/kriskowal/q). Now we have Promises natively: ```javascript -new Promise((resolve, reject) => +new Promise((resolve, reject) => reject(new Error('Failed to fulfill Promise'))) .catch(reason => console.log(reason)); ``` -Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **rejected** (a function called when the Promise is **rejected**). +Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **rejected** (a function called when the Promise is **rejected**). -> **Benefits of Promises**: Error Handling using a bunch of nested callbacks can get chaotic. Using Promises, we have a clear path to bubbling errors up and handling them appropriately. Moreover, the value of a Promise after it has been resolved/rejected is immutable - it will never change. +> **Benefits of Promises**: Error Handling using a bunch of nested callbacks can get chaotic. Using Promises, we have a clear path to bubbling errors up and handling them appropriately. Moreover, the value of a Promise after it has been resolved/rejected is immutable - it will never change. Here is a practical example of using Promises: ```javascript -var fetchJSON = function(url) { +var fetchJSON = function(url) { return new Promise((resolve, reject) => { $.getJSON(url) .done((json) => resolve(json)) @@ -735,17 +735,17 @@ var fetchJSON = function(url) { } ``` -We can also **parallelize** Promises to handle an array of asynchronous operations by using **Promise.all( )**: +We can also **parallelize** Promises to handle an array of asynchronous operations by using **Promise.all( )**: ```javascript -var urls = [ +var urls = [ 'http://www.api.com/items/1234', 'http://www.api.com/items/4567' ]; var urlPromises = urls.map(fetchJSON); -Promise.all(urlPromises) +Promise.all(urlPromises) .then(function(results) { results.forEach(function(data) { }); From 0de186810d7df2755a42f76e988d62b63a5c6b74 Mon Sep 17 00:00:00 2001 From: Andrei Eftimie Date: Sat, 23 Jan 2016 06:23:42 +0200 Subject: [PATCH 23/84] Fat arrow function: remove braces for 1 argument --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6182d25..6d6cef1 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ function Person(name) { } Person.prototype.prefixName = function (arr) { - return arr.map((character) => this.name + character); + return arr.map(character => this.name + character); } ``` From 4e33af915ec3b59108d61bb3290fe2eb288780c1 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 23 Jan 2016 11:18:57 -0500 Subject: [PATCH 24/84] Updating name from ES6 -> ES2015 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4475890..38ecc77 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # es6-cheatsheet -A cheatsheet containing ES6 tips, tricks, best practices and code snippet examples for your day to day workflow. Contributions are welcome! +A cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code snippet examples for your day to day workflow. Contributions are welcome! ## Table of Contents From 2caebd9185e974e4773815470a0734752fe304ba Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 23 Jan 2016 16:24:24 -0500 Subject: [PATCH 25/84] Resolved #31 --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 17fe00c..186edcd 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,35 @@ Person.prototype.prefixName = function (arr) { }; ``` +We can also pass in the proper context of `this`: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }, this); +} +``` + +As well as bind the context: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }.bind(this)); +} +``` + + Using **Arrow Functions**, the lexical value of **this** isn't shadowed and we can re-write the above as shown: ```javascript From 00b67de1890199569bb6022279181c3de6dc320b Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 23 Jan 2016 16:31:12 -0500 Subject: [PATCH 26/84] Re-working imports --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4c0cec3..8cd624e 100644 --- a/README.md +++ b/README.md @@ -413,14 +413,14 @@ In addition, we can **import all the things** (also called namespace import): import * as util from 'math/addition' ``` -Lastly, we can use destructuring to import a list of values from a file: +Lastly, we can import a list of values from a module: ```javascript import * as additionUtil from 'math/addtion'; const { sumTwo, sumThree } = additionUtil; ``` -or when we are importing the default object but we want to grab some of the functions on the object: +When importing the default object we can choose which functions to import: ```javascript import React from 'react'; From 00b40748f7122d49f401d815ac71763a131914dd Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 23 Jan 2016 16:53:09 -0500 Subject: [PATCH 27/84] Resolved #30 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8cd624e..ca3a701 100644 --- a/README.md +++ b/README.md @@ -654,6 +654,8 @@ for (let key of map.keys()) { }; ``` +> **Note**: Using non-primitive values such as functions or objects won't work when testing equality using methods such as `map.get( )`. As such, stick to primitive values such as Strings, Booleans and Numbers. + We can also iterate over maps using **.entries( )**: ```javascript From 7a5409c5eb6d1c2823616f8c89296460cbe1ce85 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 23 Jan 2016 17:02:48 -0500 Subject: [PATCH 28/84] Resolved #33 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ca3a701..f7534bc 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,13 @@ getFood(false); // 'Meow Mix' This change in behavior highlights that we need to be careful when refactoring legacy code which uses **var**. Blindly replacing instances of **var** with **let** may lead to unexpected behavior. +> **Note**: **let** and **const** are block scoped. Therefore, referencing block-scoped identifiers before they are defined will produce a `ReferenceError`. + +```javascript +console.log(x); +let x = "hi"; // ReferenceError: x is not defined +``` + > **Best Practice**: Leave **var** declarations inside of legacy code to denote that it needs to be carefully refactored. When working on a new codebase, use **let** for variables that will change their value over time, and **const** for variables that will be immutable over time. [(back to table of contents)](#table-of-contents) From 227bb99c0c2258b9106cae98e877c6da55e2bb20 Mon Sep 17 00:00:00 2001 From: Harry Moreno Date: Sat, 23 Jan 2016 20:44:36 -0500 Subject: [PATCH 29/84] make classes example consistent line 560 and line 592 should be consistent --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7534bc..07924f7 100644 --- a/README.md +++ b/README.md @@ -557,7 +557,7 @@ function Personal(name, age, gender, occupation, hobby) { Personal.prototype = Object.create(Person.prototype); Personal.prototype.constructor = Personal; Personal.prototype.incrementAge = function () { - return Person.prototype.incrementAge.call(this) += 1; + return Person.prototype.incrementAge.call(this) += 20; } ``` From c49d753afb764b865933e8879b209711411c6c84 Mon Sep 17 00:00:00 2001 From: Harry Moreno Date: Sat, 23 Jan 2016 20:55:23 -0500 Subject: [PATCH 30/84] fix indentation in example --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f7534bc..620919f 100644 --- a/README.md +++ b/README.md @@ -701,9 +701,9 @@ class Person { incrementAge() { let age = _age.get(this) + 1; _age.set(this, age); - if(age > 50) { - console.log('Midlife crisis'); - } + if (age > 50) { + console.log('Midlife crisis'); + } } } ``` From e7eb65af228a9acea1604430b5e041bd7541a6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Sun, 24 Jan 2016 16:27:46 +0100 Subject: [PATCH 31/84] rejected -> reject --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f7534bc..a83f4fb 100644 --- a/README.md +++ b/README.md @@ -756,7 +756,7 @@ new Promise((resolve, reject) => .catch(reason => console.log(reason)); ``` -Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **rejected** (a function called when the Promise is **rejected**). +Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **reject** (a function called when the Promise is **rejected**). > **Benefits of Promises**: Error Handling using a bunch of nested callbacks can get chaotic. Using Promises, we have a clear path to bubbling errors up and handling them appropriately. Moreover, the value of a Promise after it has been resolved/rejected is immutable - it will never change. From 17ba2ffe4e21eff725917f20f10c69ca8364c92f Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sun, 24 Jan 2016 11:31:14 -0500 Subject: [PATCH 32/84] Resolved #34: Added practical use of WeakMaps and implementation notes --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index bdf7d20..6d3321d 100644 --- a/README.md +++ b/README.md @@ -716,6 +716,29 @@ The cool thing about using WeakMaps to store our private data is that their keys > Reflect.ownKeys(person); // [] ``` +A more practical example of using WeakMaps is to store data which is associated to a DOM element without having to pollute the DOM itself: + +```javascript +let map = new WeakMap(); +let el = document.getElementById('someElement') + +// Store a weak reference to the element with a key +map.set(el, 'reference'); + +// Access the value of the element +let value = map.get(el); // 'reference' + +// Remove the reference +el.parentNode.removeChild(el); +el = null; + +value = map.get(el); // undefined +``` + +As shown above, once the object is is destroyed by the garbage collector, the WeakMap will automatically remove the key-value pair which was identified by that object. + +> **Note**: To further illustrate the usefulness of this example, consider how jQuery stores a cache of objects corresponding to DOM elements which have references. Using WeakMaps, jQuery can automatically free up any memory that was associated with a particular DOM element once it has been removed from the document. In general, WeakMaps are very useful for any library that wraps DOM elements. + [(back to table of contents)](#table-of-contents) ## Promises From 9c198dbaa9ba277031fff4abdcc4d4b2ed3fd78e Mon Sep 17 00:00:00 2001 From: battaglr Date: Sun, 24 Jan 2016 13:33:58 -0300 Subject: [PATCH 33/84] Add missing (optional) semicolons - Add missing (optional) semicolons. - Remove unnecessary semicolon in `for` statement. --- README.md | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index bdf7d20..7d723f6 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Person.prototype.prefixName = function (arr) { return arr.map(function (character) { return this.name + character; }, this); -} +}; ``` As well as bind the context: @@ -144,7 +144,7 @@ Person.prototype.prefixName = function (arr) { return arr.map(function (character) { return this.name + character; }.bind(this)); -} +}; ``` @@ -157,7 +157,7 @@ function Person(name) { Person.prototype.prefixName = function (arr) { return arr.map(character => this.name + character); -} +}; ``` > **Best Practice**: Use **Arrow Functions** whenever you need to preserve the lexical value of **this**. @@ -221,11 +221,11 @@ In ES6, we now have access to a terser implementation: Using **Template Literals**, we can now construct strings that have special characters in them without needing to escape them explicitly. ```javascript -var text = "This string contains \"double quotes\" which are escaped." +var text = "This string contains \"double quotes\" which are escaped."; ``` ```javascript -let text = `This string contains "double quotes" which are escaped.` +let text = `This string contains "double quotes" which are escaped.`; ``` **Template Literals** also support interpolation, which makes the task of concatenating strings and values: @@ -251,7 +251,7 @@ var text = ( 'cat\n' + 'dog\n' + 'nickelodeon' -) +); ``` Or: @@ -261,7 +261,7 @@ var text = [ 'cat', 'dog', 'nickelodeon' -].join('\n') +].join('\n'); ``` **Template Literals** will preserve new lines for us without having to explicitly place them in: @@ -270,15 +270,15 @@ var text = [ let text = ( `cat dog nickelodeon` -) +); ``` **Template Literals** can accept expressions, as well: ```javascript -let today = new Date() -let text = `The time and date is ${today.toLocaleString()}` +let today = new Date(); +let text = `The time and date is ${today.toLocaleString()}`; ``` [(back to table of contents)](#table-of-contents) @@ -306,13 +306,13 @@ console.log(b); // 2 ### Destructuring Objects ```javascript -var luke = { occupation: 'jedi', father: 'anakin' } +var luke = { occupation: 'jedi', father: 'anakin' }; var occupation = luke.occupation; // 'jedi' var father = luke.father; // 'anakin' ``` ```javascript -let luke = { occupation: 'jedi', father: 'anakin' } +let luke = { occupation: 'jedi', father: 'anakin' }; let {occupation, father} = luke; console.log(occupation); // 'jedi' console.log(father); // 'anakin' @@ -327,10 +327,10 @@ Prior to ES6, we used libraries such as [Browserify](http://browserify.org/) to ### Exporting in CommonJS ```javascript -module.exports = 1 -module.exports = { foo: 'bar' } -module.exports = ['foo', 'bar'] -module.exports = function bar () {} +module.exports = 1; +module.exports = { foo: 'bar' }; +module.exports = ['foo', 'bar']; +module.exports = function bar () {}; ``` ### Exporting in ES6 @@ -382,9 +382,9 @@ function sumThree(a, b, c) { let api = { sumTwo, sumThree -} +}; -export default api +export default api; ``` > **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. More so, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allow ourselves to interpolate between CommonJS and ES6 modules. @@ -394,7 +394,7 @@ export default api ES6 provides us with various flavors of importing. We can import an entire file: ```javascript -import `underscore` +import `underscore`; ``` > It is important to note that simply **importing an entire file will execute all code at the top level of that file**. @@ -402,7 +402,7 @@ import `underscore` Similar to Python, we have named imports: ```javascript -import { sumTwo, sumThree } from 'math/addition' +import { sumTwo, sumThree } from 'math/addition'; ``` We can also rename the named imports: @@ -411,13 +411,13 @@ We can also rename the named imports: import { sumTwo as addTwoNumbers, sumThree as sumThreeNumbers -} from 'math/addition' +} from 'math/addition'; ``` In addition, we can **import all the things** (also called namespace import): ```javascript -import * as util from 'math/addition' +import * as util from 'math/addition'; ``` Lastly, we can import a list of values from a module: @@ -524,7 +524,7 @@ function initializeCanvas( We can use the spread operator to pass an array of values to be used as parameters to a function: ```javascript -Math.max(...[-1, 100, 9001, -32]) // 9001 +Math.max(...[-1, 100, 9001, -32]); // 9001 ``` [(back to table of contents)](#table-of-contents) @@ -558,7 +558,7 @@ Personal.prototype = Object.create(Person.prototype); Personal.prototype.constructor = Personal; Personal.prototype.incrementAge = function () { return Person.prototype.incrementAge.call(this) += 20; -} +}; ``` ES6 provides much needed syntactic sugar for doing this under the hood. We can create Classes directly: @@ -609,7 +609,7 @@ const keyTwo = Symbol(); const object = {}; object[key] = 'Such magic.'; -object[keyTwo] = 'Much Uniqueness' +object[keyTwo] = 'Much Uniqueness'; // Two Symbols will never have the same value >> key === keyTwo @@ -658,7 +658,7 @@ let map = new Map([ for (let key of map.keys()) { console.log(typeof key); // > string, boolean, number, object, function -}; +} ``` > **Note**: Using non-primitive values such as functions or objects won't work when testing equality using methods such as `map.get( )`. As such, stick to primitive values such as Strings, Booleans and Numbers. @@ -769,7 +769,7 @@ var fetchJSON = function(url) { .done((json) => resolve(json)) .fail((xhr, status, err) => reject(status + err.message)); }); -} +}; ``` We can also **parallelize** Promises to handle an array of asynchronous operations by using **Promise.all( )**: From 1c16543a37f812d9437a74c78153982366069d22 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sun, 24 Jan 2016 11:35:29 -0500 Subject: [PATCH 34/84] Resolved #40 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6d3321d..de204ac 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ console.log(x); let x = "hi"; // ReferenceError: x is not defined ``` -> **Best Practice**: Leave **var** declarations inside of legacy code to denote that it needs to be carefully refactored. When working on a new codebase, use **let** for variables that will change their value over time, and **const** for variables that will be immutable over time. +> **Best Practice**: Leave **var** declarations inside of legacy code to denote that it needs to be carefully refactored. When working on a new codebase, use **let** for variables that will change their value over time, and **const** for variables which cannot be reassigned. [(back to table of contents)](#table-of-contents) From e5c318d97b968effa32ec396a24d345ee60ae49c Mon Sep 17 00:00:00 2001 From: battaglr Date: Sun, 24 Jan 2016 16:18:43 -0300 Subject: [PATCH 35/84] Modify formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrap all text to 80 characters to facilitate reading while editing. - Mark code with “`” instead of “**”. - Use four spaces for indentation in all examples (4 was the most used). Others: - Remove trailing whitespace. - Add space in anonymous functions. - Add missing semicolon. - Separate some statements with a blank-line. --- README.md | 307 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 194 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index 691ca66..0340f82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # es6-cheatsheet -A cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code snippet examples for your day to day workflow. Contributions are welcome! +A cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code +snippet examples for your day to day workflow. Contributions are welcome! ## Table of Contents @@ -19,9 +20,11 @@ A cheatsheet containing ES2015 [ES6] tips, tricks, best practices and code snipp ## var versus let / const -> Besides var, we now have access to two new identifiers for storing values - **let** and **const**. Unlike **var**, **let** and **const** statements are not hoisted to the top of their enclosing scope. +> Besides `var`, we now have access to two new identifiers for storing values +—`let` and `const`. Unlike `var`, `let` and `const` statements are not hoisted +to the top of their enclosing scope. -An example of using var: +An example of using `var`: ```javascript var snack = 'Meow Mix'; @@ -37,7 +40,7 @@ function getFood(food) { getFood(false); // undefined ``` -However, observe what happens when we replace **var** using **let**: +However, observe what happens when we replace `var` using `let`: ```javascript let snack = 'Meow Mix'; @@ -53,27 +56,38 @@ function getFood(food) { getFood(false); // 'Meow Mix' ``` -This change in behavior highlights that we need to be careful when refactoring legacy code which uses **var**. Blindly replacing instances of **var** with **let** may lead to unexpected behavior. +This change in behavior highlights that we need to be careful when refactoring +legacy code which uses `var`. Blindly replacing instances of `var` with `let` +may lead to unexpected behavior. -> **Note**: **let** and **const** are block scoped. Therefore, referencing block-scoped identifiers before they are defined will produce a `ReferenceError`. +> **Note**: `let` and `const` are block scoped. Therefore, referencing +block-scoped identifiers before they are defined will produce +a `ReferenceError`. ```javascript console.log(x); -let x = "hi"; // ReferenceError: x is not defined + +let x = 'hi'; // ReferenceError: x is not defined ``` -> **Best Practice**: Leave **var** declarations inside of legacy code to denote that it needs to be carefully refactored. When working on a new codebase, use **let** for variables that will change their value over time, and **const** for variables which cannot be reassigned. +> **Best Practice**: Leave `var` declarations inside of legacy code to denote +that it needs to be carefully refactored. When working on a new codebase, use +`let` for variables that will change their value over time, and `const` for +variables which cannot be reassigned. [(back to table of contents)](#table-of-contents) ## Replacing IIFEs with Blocks -> A common use of **Immediately Invoked Function Expressions** is to enclose values within its scope. In ES6, we now have the ability to create block-based scopes and therefore are not limited purely to function-based scope. +> A common use of **Immediately Invoked Function Expressions** is to enclose +values within its scope. In ES6, we now have the ability to create block-based +scopes and therefore are not limited purely to function-based scope. ```javascript (function () { var food = 'Meow Mix'; }()); + console.log(food); // Reference Error ``` @@ -83,6 +97,7 @@ Using ES6 Blocks: { let food = 'Meow Mix'; } + console.log(food); // Reference Error ``` @@ -90,7 +105,8 @@ console.log(food); // Reference Error ## Arrow Functions -Often times we have nested functions in which we would like to preserve the context of **this** from its lexical scope. An example is shown below: +Often times we have nested functions in which we would like to preserve the +context of `this` from its lexical scope. An example is shown below: ```javascript function Person(name) { @@ -104,7 +120,8 @@ Person.prototype.prefixName = function (arr) { }; ``` -One common solution to this problem is to store the context of **this** using a variable: +One common solution to this problem is to store the context of `this` using +a variable: ```javascript function Person(name) { @@ -147,8 +164,8 @@ Person.prototype.prefixName = function (arr) { }; ``` - -Using **Arrow Functions**, the lexical value of **this** isn't shadowed and we can re-write the above as shown: +Using **Arrow Functions**, the lexical value of `this` isn't shadowed and we +can re-write the above as shown: ```javascript function Person(name) { @@ -160,9 +177,11 @@ Person.prototype.prefixName = function (arr) { }; ``` -> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the lexical value of **this**. +> **Best Practice**: Use **Arrow Functions** whenever you need to preserve the +lexical value of `this`. -Arrow Functions are also more concise when used in function expressions which simply return a value: +Arrow Functions are also more concise when used in function expressions which +simply return a value: ```javascript var squares = arr.map(function (x) { return x * x }); // Function Expression @@ -173,27 +192,33 @@ const arr = [1, 2, 3, 4, 5]; const squares = arr.map(x => x * x); // Arrow Function for terser implementation ``` -> **Best Practice**: Use **Arrow Functions** in place of function expressions when possible. +> **Best Practice**: Use **Arrow Functions** in place of function expressions +when possible. [(back to table of contents)](#table-of-contents) ## Strings -With ES6, the standard library has grown immensely. Along with these changes are new methods which can be used on strings, such as **.includes()** and **.repeat()**. +With ES6, the standard library has grown immensely. Along with these changes +are new methods which can be used on strings, such as `.includes()` and +`.repeat()`. ### .includes( ) ```javascript var string = 'food'; var substring = 'foo'; + console.log(string.indexOf(substring) > -1); ``` -Instead of checking for a return value `> -1` to denote string containment, we can simply use **.includes()** which will return a boolean: +Instead of checking for a return value `> -1` to denote string containment, +we can simply use `.includes()` which will return a boolean: ```javascript const string = 'food'; const substring = 'foo'; + console.log(string.includes(substring)); // true ``` @@ -218,7 +243,8 @@ In ES6, we now have access to a terser implementation: ### Template Literals -Using **Template Literals**, we can now construct strings that have special characters in them without needing to escape them explicitly. +Using **Template Literals**, we can now construct strings that have special +characters in them without needing to escape them explicitly. ```javascript var text = "This string contains \"double quotes\" which are escaped."; @@ -228,11 +254,13 @@ var text = "This string contains \"double quotes\" which are escaped."; let text = `This string contains "double quotes" which are escaped.`; ``` -**Template Literals** also support interpolation, which makes the task of concatenating strings and values: +**Template Literals** also support interpolation, which makes the task of +concatenating strings and values: ```javascript var name = 'Tiger'; var age = 13; + console.log('My cat is named ' + name + ' and is ' + age + ' years old.'); ``` @@ -241,6 +269,7 @@ Much simpler: ```javascript const name = 'Tiger'; const age = 13; + console.log(`My cat is named ${name} and is ${age} years old.`); ``` @@ -248,9 +277,9 @@ In ES5, we handled new lines as follows: ```javascript var text = ( - 'cat\n' + - 'dog\n' + - 'nickelodeon' + 'cat\n' + + 'dog\n' + + 'nickelodeon' ); ``` @@ -258,13 +287,14 @@ Or: ```javascript var text = [ - 'cat', - 'dog', - 'nickelodeon' + 'cat', + 'dog', + 'nickelodeon' ].join('\n'); ``` -**Template Literals** will preserve new lines for us without having to explicitly place them in: +**Template Literals** will preserve new lines for us without having to +explicitly place them in: ```javascript let text = ( `cat @@ -273,7 +303,6 @@ nickelodeon` ); ``` - **Template Literals** can accept expressions, as well: ```javascript @@ -285,7 +314,8 @@ let text = `The time and date is ${today.toLocaleString()}`; ## Destructuring -Destructuring allows us to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax. +Destructuring allows us to extract values from arrays and objects (even deeply +nested) and store them in variables with a more convenient syntax. ### Destructuring Arrays @@ -299,6 +329,7 @@ var d = arr[3]; ```javascript let [a, b, c, d] = [1, 2, 3, 4]; + console.log(a); // 1 console.log(b); // 2 ``` @@ -314,6 +345,7 @@ var father = luke.father; // 'anakin' ```javascript let luke = { occupation: 'jedi', father: 'anakin' }; let {occupation, father} = luke; + console.log(occupation); // 'jedi' console.log(father); // 'anakin' ``` @@ -322,7 +354,10 @@ console.log(father); // 'anakin' ## Modules -Prior to ES6, we used libraries such as [Browserify](http://browserify.org/) to create modules on the client-side, and [require](https://nodejs.org/api/modules.html#modules_module_require_id) in **Node.js**. With ES6, we can now directly use modules of all types (AMD and CommonJS). +Prior to ES6, we used libraries such as [Browserify](http://browserify.org/) +to create modules on the client-side, and [require](https://nodejs.org/api/modules.html#modules_module_require_id) +in **Node.js**. With ES6, we can now directly use modules of all types +(AMD and CommonJS). ### Exporting in CommonJS @@ -335,7 +370,8 @@ module.exports = function bar () {}; ### Exporting in ES6 -With ES6, we have various flavors of exporting. We can perform **Named Exports**: +With ES6, we have various flavors of exporting. We can perform +**Named Exports**: ```javascript export let name = 'David'; @@ -356,7 +392,7 @@ function sumThree(a, b, c) { export { sumTwo, sumThree }; ``` -We can also export a value simply by using the **export** keyword: +We can also export a value simply by using the `export` keyword: ```javascript export function sumTwo(a, b) { @@ -387,7 +423,12 @@ let api = { export default api; ``` -> **Best Practices**: Always use the **export default** method at **the end** of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as. More so, the common practice in CommonJS modules is to export a single value or object. By sticking to this paradigm, we make our code easily readable and allow ourselves to interpolate between CommonJS and ES6 modules. +> **Best Practices**: Always use the `export default` method at **the end** of +the module. It makes it clear what is being exported, and saves time by having +to figure out what name a value was exported as. More so, the common practice +in CommonJS modules is to export a single value or object. By sticking to this +paradigm, we make our code easily readable and allow ourselves to interpolate +between CommonJS and ES6 modules. ### Importing in ES6 @@ -397,7 +438,8 @@ ES6 provides us with various flavors of importing. We can import an entire file: import `underscore`; ``` -> It is important to note that simply **importing an entire file will execute all code at the top level of that file**. +> It is important to note that simply **importing an entire file will execute +all code at the top level of that file**. Similar to Python, we have named imports: @@ -409,8 +451,8 @@ We can also rename the named imports: ```javascript import { - sumTwo as addTwoNumbers, - sumThree as sumThreeNumbers + sumTwo as addTwoNumbers, + sumThree as sumThreeNumbers } from 'math/addition'; ``` @@ -427,20 +469,25 @@ import * as additionUtil from 'math/addtion'; const { sumTwo, sumThree } = additionUtil; ``` -When importing the default object we can choose which functions to import: +When importing the default object we can choose which functions to import: ```javascript import React from 'react'; const { Component, PropTypes } = React; ``` -> **Note**: Values that are exported are **bindings**, not references. Therefore, changing the binding of a variable in one module will affect the value within the exported module. Avoid changing the public interface of these exported values. +> **Note**: Values that are exported are **bindings**, not references. +Therefore, changing the binding of a variable in one module will affect the +value within the exported module. Avoid changing the public interface of these +exported values. [(back to table of contents)](#table-of-contents) ## Parameters -In ES5, we had varying ways to handle functions which needed **default values**, **indefinite arguments**, and **named parameters**. With ES6, we can accomplish all of this and more using more concise syntax. +In ES5, we had varying ways to handle functions which needed **default values**, +**indefinite arguments**, and **named parameters**. With ES6, we can accomplish +all of this and more using more concise syntax. ### Default Parameters @@ -490,7 +537,8 @@ function logArguments(...args) { ### Named Parameters -One of the patterns in ES5 to handle named parameters was to use the **options object** pattern, adopted from jQuery. +One of the patterns in ES5 to handle named parameters was to use the **options +object** pattern, adopted from jQuery. ```javascript function initializeCanvas(options) { @@ -500,28 +548,31 @@ function initializeCanvas(options) { } ``` -We can achieve the same functionality using destructuring as a formal parameter to a function: +We can achieve the same functionality using destructuring as a formal parameter +to a function: ```javascript function initializeCanvas( { height=600, width=400, lineStroke='black'}) { - ... + // ... } // Use variables height, width, lineStroke here ``` -If we want to make the entire value optional, we can do so by destructuring an empty object: +If we want to make the entire value optional, we can do so by destructuring an +empty object: ```javascript function initializeCanvas( { height=600, width=400, lineStroke='black'} = {}) { - ... + // ... } ``` ### Spread Operator -We can use the spread operator to pass an array of values to be used as parameters to a function: +We can use the spread operator to pass an array of values to be used as +parameters to a function: ```javascript Math.max(...[-1, 100, 9001, -32]); // 9001 @@ -531,7 +582,8 @@ Math.max(...[-1, 100, 9001, -32]); // 9001 ## Classes -Prior to ES6, we implemented Classes by creating a constructor function and adding properties by extending the prototype: +Prior to ES6, we implemented Classes by creating a constructor function and +adding properties by extending the prototype: ```javascript function Person(name, age, gender) { @@ -561,7 +613,8 @@ Personal.prototype.incrementAge = function () { }; ``` -ES6 provides much needed syntactic sugar for doing this under the hood. We can create Classes directly: +ES6 provides much needed syntactic sugar for doing this under the hood. We can +create Classes directly: ```javascript class Person { @@ -577,31 +630,35 @@ class Person { } ``` -And extend them using the **extends** keyword: +And extend them using the `extends` keyword: ```javascript class Personal extends Person { constructor(name, age, gender, occupation, hobby) { - super(name, age, gender); - this.occupation = occupation; - this.hobby = hobby; + super(name, age, gender); + this.occupation = occupation; + this.hobby = hobby; } incrementAge() { - super.incrementAge(); - this.age += 20; - console.log(this.age); + super.incrementAge(); + this.age += 20; + console.log(this.age); } } ``` -> **Best Practice**: While the syntax for creating classes in ES6 obscures how implementation and prototypes work under the hood, it is a good feature for beginners and allows us to write cleaner code. +> **Best Practice**: While the syntax for creating classes in ES6 obscures how +implementation and prototypes work under the hood, it is a good feature for +beginners and allows us to write cleaner code. [(back to table of contents)](#table-of-contents) ## Symbols -Symbols have existed prior to ES6, but now we have a public interface to using them directly. One such example is to create unique property keys which will never collide: +Symbols have existed prior to ES6, but now we have a public interface to using +them directly. One such example is to create unique property keys which will +never collide: ```javascript const key = Symbol(); @@ -620,7 +677,8 @@ object[keyTwo] = 'Much Uniqueness'; ## Maps -**Maps** is a much needed data structure in JavaScript. Prior to ES6, we created **hash** maps through objects: +**Maps** is a much needed data structure in JavaScript. Prior to ES6, we created +**hash** maps through objects: ```javascript var map = new Object(); @@ -628,14 +686,15 @@ map[key1] = 'value1'; map[key2] = 'value2'; ``` -However, this does not protect us from accidentally overriding functions with specific property names: +However, this does not protect us from accidentally overriding functions with +specific property names: ```javascript > getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned'); > TypeError: Property 'hasOwnProperty' is not a function ``` -Actual **Maps** allow us to **set**, **get** and **search** for values (and much more). +Actual **Maps** allow us to `set`, `get` and `search` for values (and much more). ```javascript let map = new Map(); @@ -644,7 +703,9 @@ let map = new Map(); > map.has('name'); // true ``` -The most amazing part of Maps is that we are no longer limited to just using strings. We can now use any type as a key, and it will not be type-casted to a string. +The most amazing part of Maps is that we are no longer limited to just using +strings. We can now use any type as a key, and it will not be type-casted to +a string. ```javascript let map = new Map([ @@ -661,13 +722,15 @@ for (let key of map.keys()) { } ``` -> **Note**: Using non-primitive values such as functions or objects won't work when testing equality using methods such as `map.get( )`. As such, stick to primitive values such as Strings, Booleans and Numbers. +> **Note**: Using non-primitive values such as functions or objects won't work +when testing equality using methods such as `map.get()`. As such, stick to +primitive values such as Strings, Booleans and Numbers. -We can also iterate over maps using **.entries( )**: +We can also iterate over maps using `.entries()`: ```javascript for (let [key, value] of map.entries()) { - console.log(key, value); + console.log(key, value); } ``` @@ -675,7 +738,8 @@ for (let [key, value] of map.entries()) { ## WeakMaps -In order to store private data in < ES5, we had various ways of doing this. One such method was using naming conventions: +In order to store private data in < ES5, we had various ways of doing this. +One such method was using naming conventions: ```javascript class Person { @@ -684,31 +748,34 @@ class Person { } _incrementAge() { - this._age += 1; + this._age += 1; } } ``` -But naming conventions can cause confusion in a codebase and are not always going to be upheld. Instead, we can use WeakMaps to store our values: +But naming conventions can cause confusion in a codebase and are not always +going to be upheld. Instead, we can use WeakMaps to store our values: ```javascript let _age = new WeakMap(); class Person { - constructor(age) { - _age.set(this, age); - } - - incrementAge() { - let age = _age.get(this) + 1; - _age.set(this, age); - if (age > 50) { - console.log('Midlife crisis'); + constructor(age) { + _age.set(this, age); + } + + incrementAge() { + let age = _age.get(this) + 1; + _age.set(this, age); + if (age > 50) { + console.log('Midlife crisis'); + } } - } } ``` -The cool thing about using WeakMaps to store our private data is that their keys do not give away the property names, which can be seen by using **Reflect.ownKeys()**: +The cool thing about using WeakMaps to store our private data is that their +keys do not give away the property names, which can be seen by using +`Reflect.ownKeys()`: ```javascript > const person = new Person(50); @@ -716,11 +783,12 @@ The cool thing about using WeakMaps to store our private data is that their keys > Reflect.ownKeys(person); // [] ``` -A more practical example of using WeakMaps is to store data which is associated to a DOM element without having to pollute the DOM itself: +A more practical example of using WeakMaps is to store data which is associated +to a DOM element without having to pollute the DOM itself: ```javascript let map = new WeakMap(); -let el = document.getElementById('someElement') +let el = document.getElementById('someElement'); // Store a weak reference to the element with a key map.set(el, 'reference'); @@ -735,9 +803,16 @@ el = null; value = map.get(el); // undefined ``` -As shown above, once the object is is destroyed by the garbage collector, the WeakMap will automatically remove the key-value pair which was identified by that object. +As shown above, once the object is is destroyed by the garbage collector, +the WeakMap will automatically remove the key-value pair which was identified +by that object. -> **Note**: To further illustrate the usefulness of this example, consider how jQuery stores a cache of objects corresponding to DOM elements which have references. Using WeakMaps, jQuery can automatically free up any memory that was associated with a particular DOM element once it has been removed from the document. In general, WeakMaps are very useful for any library that wraps DOM elements. +> **Note**: To further illustrate the usefulness of this example, consider how +jQuery stores a cache of objects corresponding to DOM elements which have +references. Using WeakMaps, jQuery can automatically free up any memory that +was associated with a particular DOM element once it has been removed from the +document. In general, WeakMaps are very useful for any library that wraps DOM +elements. [(back to table of contents)](#table-of-contents) @@ -747,15 +822,15 @@ Promises allow us to turn our horizontal code (callback hell): ```javascript func1(function (value1) { - func2(value1, function(value2) { - func3(value2, function(value3) { - func4(value3, function(value4) { - func5(value4, function(value5) { - // Do something with value 5 + func2(value1, function (value2) { + func3(value2, function (value3) { + func4(value3, function (value4) { + func5(value4, function (value5) { + // Do something with value 5 + }); + }); }); - }); }); - }); }); ``` @@ -763,54 +838,60 @@ Into vertical code: ```javascript func1(value1) - .then(func2) - .then(func3) - .then(func4) - .then(func5, value5 => { - // Do something with value 5 - }); + .then(func2) + .then(func3) + .then(func4) + .then(func5, value5 => { + // Do something with value 5 + }); ``` -Prior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or [Q](https://github.com/kriskowal/q). Now we have Promises natively: +Prior to ES6, we used [bluebird](https://github.com/petkaantonov/bluebird) or +[Q](https://github.com/kriskowal/q). Now we have Promises natively: ```javascript new Promise((resolve, reject) => reject(new Error('Failed to fulfill Promise'))) - .catch(reason => console.log(reason)); + .catch(reason => console.log(reason)); ``` -Where we have two handlers, **resolve** (a function called when the Promise is **fulfilled**) and **reject** (a function called when the Promise is **rejected**). +Where we have two handlers, **resolve** (a function called when the Promise is +**fulfilled**) and **reject** (a function called when the Promise is **rejected**). -> **Benefits of Promises**: Error Handling using a bunch of nested callbacks can get chaotic. Using Promises, we have a clear path to bubbling errors up and handling them appropriately. Moreover, the value of a Promise after it has been resolved/rejected is immutable - it will never change. +> **Benefits of Promises**: Error Handling using a bunch of nested callbacks +can get chaotic. Using Promises, we have a clear path to bubbling errors up +and handling them appropriately. Moreover, the value of a Promise after it has +been resolved/rejected is immutable - it will never change. Here is a practical example of using Promises: ```javascript var fetchJSON = function(url) { - return new Promise((resolve, reject) => { - $.getJSON(url) - .done((json) => resolve(json)) - .fail((xhr, status, err) => reject(status + err.message)); - }); + return new Promise((resolve, reject) => { + $.getJSON(url) + .done((json) => resolve(json)) + .fail((xhr, status, err) => reject(status + err.message)); + }); }; ``` -We can also **parallelize** Promises to handle an array of asynchronous operations by using **Promise.all( )**: +We can also **parallelize** Promises to handle an array of asynchronous +operations by using `Promise.all()`: ```javascript var urls = [ - 'http://www.api.com/items/1234', - 'http://www.api.com/items/4567' + 'http://www.api.com/items/1234', + 'http://www.api.com/items/4567' ]; var urlPromises = urls.map(fetchJSON); Promise.all(urlPromises) - .then(function(results) { - results.forEach(function(data) { - }); - }) - .catch(function(err) { - console.log("Failed: ", err); - }); + .then(function (results) { + results.forEach(function (data) { + }); + }) + .catch(function (err) { + console.log('Failed: ', err); + }); ``` From 26bce36ed7e54092b57c09fe5b10855d0bebf2d5 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sun, 24 Jan 2016 14:49:55 -0500 Subject: [PATCH 36/84] Minor fix to import statement --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0340f82..95c3108 100644 --- a/README.md +++ b/README.md @@ -435,7 +435,7 @@ between CommonJS and ES6 modules. ES6 provides us with various flavors of importing. We can import an entire file: ```javascript -import `underscore`; +import 'underscore'; ``` > It is important to note that simply **importing an entire file will execute From a5d62288a35d3545db90267ce41c90c128628be5 Mon Sep 17 00:00:00 2001 From: Andreas Lundgren Date: Mon, 25 Jan 2016 11:44:58 +0100 Subject: [PATCH 37/84] Fixed minor error in named parameters where the use varliables here comment was placed outside of the comment. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 95c3108..27d32f0 100644 --- a/README.md +++ b/README.md @@ -554,9 +554,8 @@ to a function: ```javascript function initializeCanvas( { height=600, width=400, lineStroke='black'}) { - // ... + // Use variables height, width, lineStroke here } - // Use variables height, width, lineStroke here ``` If we want to make the entire value optional, we can do so by destructuring an From 3c70921ce36b9d424aef3957932cbc81214c7edc Mon Sep 17 00:00:00 2001 From: Richard Butler Date: Mon, 25 Jan 2016 12:18:05 +0000 Subject: [PATCH 38/84] Add complex import simplification --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 95c3108..2f83425 100644 --- a/README.md +++ b/README.md @@ -476,6 +476,12 @@ import React from 'react'; const { Component, PropTypes } = React; ``` +This can also be simplified further, using: + +```javascript +import React, { Component, PropTypes } from 'react'; +``` + > **Note**: Values that are exported are **bindings**, not references. Therefore, changing the binding of a variable in one module will affect the value within the exported module. Avoid changing the public interface of these From 4b5974924da29b32a841fab56ac39b110ac42a53 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 26 Jan 2016 00:30:59 +1100 Subject: [PATCH 39/84] Fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95c3108..363644a 100644 --- a/README.md +++ b/README.md @@ -465,7 +465,7 @@ import * as util from 'math/addition'; Lastly, we can import a list of values from a module: ```javascript -import * as additionUtil from 'math/addtion'; +import * as additionUtil from 'math/addition'; const { sumTwo, sumThree } = additionUtil; ``` From d8a45f2073f128e968dcf1b5507027fb34cf4d88 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Mon, 25 Jan 2016 09:55:59 -0800 Subject: [PATCH 40/84] Add additional information about Symbols --- README.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f1265f4..3f4ac2e 100644 --- a/README.md +++ b/README.md @@ -662,22 +662,70 @@ beginners and allows us to write cleaner code. ## Symbols Symbols have existed prior to ES6, but now we have a public interface to using -them directly. One such example is to create unique property keys which will -never collide: +them directly. Symbols are immutable and unique and can be used as keys in any hash. -```javascript -const key = Symbol(); -const keyTwo = Symbol(); -const object = {}; +### Symbol() + +Calling `Symbol()` or `Symbol(description)` will create a unique symbol that cannot be looked up +globally. A Use case for `Symbol()` is to patch objects or namespaces from third parties with your own +logic, but be confident that you won't collide with updates to that library. For example, +if you wanted to add a method `refreshComponent` to the `React.Component` class, and be certain that +you didn't trample a method they add in a later update: -object[key] = 'Such magic.'; -object[keyTwo] = 'Much Uniqueness'; +```js +const refreshComponent = Symbol(); -// Two Symbols will never have the same value ->> key === keyTwo ->> false +React.Component.prototype[refreshComponent] = () => { + // do something +} ``` + +### Symbol.for(key) + +`Symbol.for(key)` will create a Symbol that is still immutable and unique, but can be looked up globally. +Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for `Symbol(description)`. + +```js +Symbol('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol.for('foo') // true +``` + +A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be acheived by +having your code look for a Symbol member on object arguments from third parties that contain some known interface. +For example: + +```js +function reader(obj) { + const specialRead = Symbol.for('specialRead'); + if (obj[specialRead]) { + const reader = obj[specialRead](); + // do something with reader + } else { + throw new TypeError('object cannot be read'); + } +} +``` + +and then in another library: + +```js +const specialRead = Symbol.for('specialRead'); + +class SomeReadableType { + [specialRead]() { + const reader = createSomeReaderFrom(this); + return reader; + } +} +``` + +A notable example of Symbol use for interop is `Symbol.iterable` which exists on all iterable and iterator +types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator +interface. + + [(back to table of contents)](#table-of-contents) ## Maps From 14c986118d6b0a2b3c796f9057938bcc0319fb29 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Mon, 25 Jan 2016 13:05:47 -0500 Subject: [PATCH 41/84] Updating readme to conform to formatting --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3f4ac2e..192b1f2 100644 --- a/README.md +++ b/README.md @@ -664,7 +664,7 @@ beginners and allows us to write cleaner code. Symbols have existed prior to ES6, but now we have a public interface to using them directly. Symbols are immutable and unique and can be used as keys in any hash. -### Symbol() +### Symbol( ) Calling `Symbol()` or `Symbol(description)` will create a unique symbol that cannot be looked up globally. A Use case for `Symbol()` is to patch objects or namespaces from third parties with your own @@ -672,7 +672,7 @@ logic, but be confident that you won't collide with updates to that library. For if you wanted to add a method `refreshComponent` to the `React.Component` class, and be certain that you didn't trample a method they add in a later update: -```js +```javascript const refreshComponent = Symbol(); React.Component.prototype[refreshComponent] = () => { @@ -684,19 +684,20 @@ React.Component.prototype[refreshComponent] = () => { ### Symbol.for(key) `Symbol.for(key)` will create a Symbol that is still immutable and unique, but can be looked up globally. -Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for `Symbol(description)`. +Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for +`Symbol(description)`: -```js +```javascript Symbol('foo') === Symbol('foo') // false Symbol.for('foo') === Symbol('foo') // false Symbol.for('foo') === Symbol.for('foo') // true ``` -A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be acheived by -having your code look for a Symbol member on object arguments from third parties that contain some known interface. -For example: +A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be +acheived by having your code look for a Symbol member on object arguments from third parties that contain some +known interface. For example: -```js +```javascript function reader(obj) { const specialRead = Symbol.for('specialRead'); if (obj[specialRead]) { @@ -708,9 +709,9 @@ function reader(obj) { } ``` -and then in another library: +And then in another library: -```js +```javascript const specialRead = Symbol.for('specialRead'); class SomeReadableType { @@ -721,11 +722,10 @@ class SomeReadableType { } ``` -A notable example of Symbol use for interop is `Symbol.iterable` which exists on all iterable and iterator +> A notable example of Symbol use for interoperability is `Symbol.iterable` which exists on all iterable and iterator types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator interface. - [(back to table of contents)](#table-of-contents) ## Maps From eed3437db67498b5f2186304bc288fe3f3903a39 Mon Sep 17 00:00:00 2001 From: Daniel Norton Date: Mon, 25 Jan 2016 14:40:38 -0600 Subject: [PATCH 42/84] correct grammar past tense of "cast" is "cast" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 192b1f2..dad61af 100644 --- a/README.md +++ b/README.md @@ -757,7 +757,7 @@ let map = new Map(); ``` The most amazing part of Maps is that we are no longer limited to just using -strings. We can now use any type as a key, and it will not be type-casted to +strings. We can now use any type as a key, and it will not be type-cast to a string. ```javascript From 72f821e88145fa81f7569c6ac683f7cdacb8beaa Mon Sep 17 00:00:00 2001 From: Larry Battle Date: Mon, 25 Jan 2016 21:02:08 -0600 Subject: [PATCH 43/84] Fixed syntax error in ES5 Personal example --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 192b1f2..87d0201 100644 --- a/README.md +++ b/README.md @@ -614,7 +614,9 @@ function Personal(name, age, gender, occupation, hobby) { Personal.prototype = Object.create(Person.prototype); Personal.prototype.constructor = Personal; Personal.prototype.incrementAge = function () { - return Person.prototype.incrementAge.call(this) += 20; + Person.prototype.incrementAge.call(this); + this.age += 20; + console.log(this.age); }; ``` From 9c14fbf570c46186d7e08b588c795b2f82c881a2 Mon Sep 17 00:00:00 2001 From: Carl Mungazi Date: Thu, 28 Jan 2016 00:02:45 +0000 Subject: [PATCH 44/84] Update README.md Fixed small typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c01010..0b22125 100644 --- a/README.md +++ b/README.md @@ -696,7 +696,7 @@ Symbol.for('foo') === Symbol.for('foo') // true ``` A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be -acheived by having your code look for a Symbol member on object arguments from third parties that contain some +achieved by having your code look for a Symbol member on object arguments from third parties that contain some known interface. For example: ```javascript From eab6e0d96df12d5c0bb2eba6c1b038fb09c64fd2 Mon Sep 17 00:00:00 2001 From: Ike Peters Date: Wed, 27 Jan 2016 23:45:47 -0800 Subject: [PATCH 45/84] adding more documentation to spread operators --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b22125..2507d11 100644 --- a/README.md +++ b/README.md @@ -576,13 +576,25 @@ function initializeCanvas( ### Spread Operator -We can use the spread operator to pass an array of values to be used as +In ES5, we could find the max of values in an array by using the `apply` method on `Math.max` like this: +```javascript +Math.max.apply(null, [-1, 100, 9001, -32]); // 9001 +``` + +In ES6, we can now use the spread operator to pass an array of values to be used as parameters to a function: ```javascript Math.max(...[-1, 100, 9001, -32]); // 9001 ``` +We can concat array literals easily with this intuitive syntax: + +```javascript +let cities = ['San Francisco', 'Los Angeles']; +let places = ['Miami', ...cities, 'Chicago']; // ['Miami', 'San Francisco', 'Los Angeles', 'Chicago'] +``` + [(back to table of contents)](#table-of-contents) ## Classes From f409f49ba288b8bb53f8f613485894bdfeee5673 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Thu, 28 Jan 2016 10:20:09 -0500 Subject: [PATCH 46/84] Making clearer distinction on exported values --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2507d11..7936f56 100644 --- a/README.md +++ b/README.md @@ -392,7 +392,7 @@ function sumThree(a, b, c) { export { sumTwo, sumThree }; ``` -We can also export a value simply by using the `export` keyword: +We can also export functions, objects and values (etc.) simply by using the `export` keyword: ```javascript export function sumTwo(a, b) { From 6fcc2a729072ab12b66c1056a0da1c32877c50af Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 29 Jan 2016 16:57:02 -0500 Subject: [PATCH 47/84] Adding Generators, Generators + Promises and Async Await --- README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/README.md b/README.md index 7936f56..849739b 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ snippet examples for your day to day workflow. Contributions are welcome! - [Maps](#maps) - [WeakMaps](#weakmaps) - [Promises](#promises) +- [Generators](#generators) +- [Async Await](#async-await) ## var versus let / const @@ -962,3 +964,130 @@ Promise.all(urlPromises) console.log('Failed: ', err); }); ``` + +[(back to table of contents)](#table-of-contents) + +## Generators + +Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid +[callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our +asynchronous code a synchronous feel. Generators are essentially functions which we can +[pause their excution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) +and subsequently return the value of an expression. + +A simple example of using generators is shown below: + +```javascript +function* sillyGenerator() { + yield 1; + yield 2; + yield 3; + yield 4; +} + +var generator = sillyGenerator(); +var value = generator.next(); +> console.log(value); // { value: 1, done: false } +> console.log(value); // { value: 2, done: false } +> console.log(value); // { value: 3, done: false } +> console.log(value); // { value: 4, done: false } +``` + +Where the [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) +will allow us to push our generator forward and evaluate a new expression. While the above example is extremely +contrived, we can utilize Generators to write asynchronous code in a synchronous manner: + +```javascript +// Hiding asynchronousity with Generators + +function request(url) { + getJSON(url, function(response) { + generator.next(response); + }); +} +``` + +And here we write a generator function that will return our data: + +```javascript +function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +} +``` + +By the power of `yield`, we are gauranteed that `entry1` will have the data needed to be parsed and stored +in `data1`. + +While generators allow us to write asynchronous code in a synchronous manner, there is no clear +and easy path for error propagation. As such, as we can augment our generator with Promises: + +```javascript +function request(url) { + return new Promise((resolve, reject) => { + getJSON(url, resolve); + }); +} +``` + +And we write a function which will step through our generator using `next` which in turn will utilize our +`request` method above to yield a Promise: + +```javascript +function iterateGenerator(gen) { + var generator = gen(); + var ret; + (function iterate(val) { + ret = generator.next(); + if(!ret.done) { + ret.value.then(iterate); + } + })(); +} +``` + +By augmenting our Generator with Promises, we have a clear way of propogating errors through the use of our +Promise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before: + +```javascript +iterateGenerator(function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +}); +``` + +We were able to reuse our implementation to use our Generator as before, which shows their power. While Generators +and Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propogate +errors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits: +[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await). + +## Async Await + +While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished +using Generators and Promises with less effort: + +```javascript +var request = require('request'); + +function getJSON(url) { + return new Promise(function(resolve, reject) { + request(url, function(error, response, body) { + resolve(body); + }); + }); +} + +async function main() { + var data = await getJSON(); + console.log(data); // NOT undefined! +} + +main(); +``` + +Under the hood, it performs similarly to Generators. I highly recommend giving it a try, A great resource +for 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). \ No newline at end of file From 464e2939c41b7cb06d8a0999fff2f5531eabf60e Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 29 Jan 2016 17:00:33 -0500 Subject: [PATCH 48/84] Minor typo fix, adding in back to table of contents links --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 849739b..f25633c 100644 --- a/README.md +++ b/README.md @@ -993,7 +993,7 @@ var value = generator.next(); > console.log(value); // { value: 4, done: false } ``` -Where the [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) +Where [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) will allow us to push our generator forward and evaluate a new expression. While the above example is extremely contrived, we can utilize Generators to write asynchronous code in a synchronous manner: @@ -1065,6 +1065,8 @@ and Promises allow us to write asynchronous code in a synchronous manner while r errors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits: [async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await). +[(back to table of contents)](#table-of-contents) + ## Async Await While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished @@ -1089,5 +1091,7 @@ async function main() { main(); ``` -Under the hood, it performs similarly to Generators. I highly recommend giving it a try, A great resource -for 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). \ No newline at end of file +Under the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource +for 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). + +[(back to table of contents)](#table-of-contents) \ No newline at end of file From e561e9f8ab16aa972df78d766fe551e051dc5269 Mon Sep 17 00:00:00 2001 From: hkongm Date: Mon, 1 Feb 2016 11:24:08 +0800 Subject: [PATCH 49/84] add new document that translated in chinese. --- README_zhCn.md | 851 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 851 insertions(+) create mode 100644 README_zhCn.md diff --git a/README_zhCn.md b/README_zhCn.md new file mode 100644 index 0000000..686c938 --- /dev/null +++ b/README_zhCn.md @@ -0,0 +1,851 @@ +# es6-cheatsheet + +这是一个 ES2015(ES6) 的Cheatsheet,其中包括提示、小技巧、最佳实践和一些代码片段,帮助你 +完成日复一日的开发工作。 + +## Table of Contents + +- [var 与 let / const 声明](#var-versus-let--const) +- [代码执行块替换立即执行函数](#replacing-iifes-with-blocks) +- [箭头函数](#arrow-functions) +- [字符串](#strings) +- [解构](#destructuring) +- [模块](#modules) +- [参数](#parameters) +- [类](#classes) +- [Symbols](#symbols) +- [Maps](#maps) +- [WeakMaps](#weakmaps) +- [Promises](#promises) + +## var versus let / const + +> 除了 `var` 以外,我们现在多了两个新的标识符来声明变量的存储,它们就是 `let` 和 `const`。 +不同于 `var` ,`let` 和 `const` 语句不会造成声明提升。 + +一个 `var` 的例子: + +```javascript +var snack = 'Meow Mix'; + +function getFood(food) { + if (food) { + var snack = 'Friskies'; + return snack; + } + return snack; +} + +getFood(false); // undefined +``` + +让我们再观察下面语句中,使用 `let` 替换了 `var` 后的表现: + +```javascript +let snack = 'Meow Mix'; + +function getFood(food) { + if (food) { + let snack = 'Friskies'; + return snack; + } + return snack; +} + +getFood(false); // 'Meow Mix' +``` + +当我们重构使用 `var` 的老代码时,一定要注意这种变化。盲目使用 `let` 替换 `var` 后可能会导致预期意外的结果。 + +> **注意**:`let` 和 `const` 是块级作用域语句。所以在语句块以外引用这些变量时,会造成引用错误 `ReferenceError`。 + +```javascript +console.log(x); + +let x = 'hi'; // ReferenceError: x is not defined +``` + +> **最佳实践**: 在重构老代码时,`var` 声明需要格外的注意。在创建一个新项目时,使用 `let` 声明一个变量,使用 `const` 来声明一个不可改变的常量。 + +[(back to table of contents)](#table-of-contents) + +## Replacing IIFEs with Blocks + +我们以往创建一个 **立即执行函数** 时,一般是在函数最外层包裹一层括号。 +ES6支持块级作用域(更贴近其他语言),我们现在可以通过创建一个代码块(Block)来实现,不必通过创建一个函数来实现, + +```javascript +(function () { + var food = 'Meow Mix'; +}()); + +console.log(food); // Reference Error +``` + +使用支持块级作用域的ES6的版本: + +```javascript +{ + let food = 'Meow Mix'; +} + +console.log(food); // Reference Error +``` + +[(back to table of contents)](#table-of-contents) + +## Arrow Functions + +一些时候,我们在函数嵌套中需要访问上下文中的 `this`。比如下面的例子: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; // Cannot read property 'name' of undefined + }); +}; +``` + +一种通用的方式是把上下文中的 `this` 保存在一个变量里: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + var that = this; // Store the context of this + return arr.map(function (character) { + return that.name + character; + }); +}; +``` + +我们也可以把 `this` 通过属性传进去: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }, this); +}; +``` + +还可以直接使用 `bind`: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }.bind(this)); +}; +``` + +使用 **箭头函数**,`this` 的值不用我们再做如上几段代码的特殊处理,直接使用即可。 +上面的代码可以重写为下面这样: + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(character => this.name + character); +}; +``` + +> **最佳实践**:使用箭头函数,再也不用考虑 `this` 的问题了。 + +当我们编写只返回一个表达式值的简单函数时,也可以使用箭头函数,如下: + +```javascript +var squares = arr.map(function (x) { return x * x }); // Function Expression +``` + +```javascript +const arr = [1, 2, 3, 4, 5]; +const squares = arr.map(x => x * x); // Arrow Function for terser implementation +``` + +> **最佳实践**:尽可能地多使用 **箭头函数**。 + +[(back to table of contents)](#table-of-contents) + +## Strings + +在ES6中,标准库也被同样增强了,像字符串对象就新增了 `.includes()` 和 `.repeat()` 方法。 + +### .includes( ) + +```javascript +var string = 'food'; +var substring = 'foo'; + +console.log(string.indexOf(substring) > -1); +``` + +现在,我们可以使用 `.inclues()` 方法,替代以往判断内容 `> -1` 的方式。 +`.includes()` 方法会极简地返回一个布尔值结果。 + +```javascript +const string = 'food'; +const substring = 'foo'; + +console.log(string.includes(substring)); // true +``` + +### .repeat( ) + +```javascript +function repeat(string, count) { + var strings = []; + while(strings.length < count) { + strings.push(string); + } + return strings.join(''); +} +``` + +在ES6中,我们可以使用一个极简的方法来实现重复字符: + +```javascript +// String.repeat(numberOfRepetitions) +'meow'.repeat(3); // 'meowmeowmeow' +``` + +### Template Literals + +使用 **字符串模板字面量**,我可以在字符串中直接使用特殊字符,而不用转义。 + +```javascript +var text = "This string contains \"double quotes\" which are escaped."; +``` + +```javascript +let text = `This string contains "double quotes" which are escaped.`; +``` + +**字符串模板字面量** 还支持直接插入变量,可以实现字符串与变量的直接连接输出。 + +```javascript +var name = 'Tiger'; +var age = 13; + +console.log('My cat is named ' + name + ' and is ' + age + ' years old.'); +``` + +更简单的版本: + +```javascript +const name = 'Tiger'; +const age = 13; + +console.log(`My cat is named ${name} and is ${age} years old.`); +``` + +ES5中,我们要这样生成多行文本: + +```javascript +var text = ( + 'cat\n' + + 'dog\n' + + 'nickelodeon' +); +``` + +或者: + +```javascript +var text = [ + 'cat', + 'dog', + 'nickelodeon' +].join('\n'); +``` + +**字符串模板字面量** 让我们不必特别关注多行字符串中的换行转义符号,直接换行即可: + +```javascript +let text = ( `cat +dog +nickelodeon` +); +``` + +**字符串模板字面量** 内部可以使用表达式,像这样: + +```javascript +let today = new Date(); +let text = `The time and date is ${today.toLocaleString()}`; +``` + +[(back to table of contents)](#table-of-contents) + +## Destructuring + +解构让我们可以使用非常便捷的语法,直接将数组或者对象中的值直接分别导出到多个变量中, + +### Destructuring Arrays + +**解构数组** + +```javascript +var arr = [1, 2, 3, 4]; +var a = arr[0]; +var b = arr[1]; +var c = arr[2]; +var d = arr[3]; +``` + +```javascript +let [a, b, c, d] = [1, 2, 3, 4]; + +console.log(a); // 1 +console.log(b); // 2 +``` + +### Destructuring Objects + +**结构对象** + +```javascript +var luke = { occupation: 'jedi', father: 'anakin' }; +var occupation = luke.occupation; // 'jedi' +var father = luke.father; // 'anakin' +``` + +```javascript +let luke = { occupation: 'jedi', father: 'anakin' }; +let {occupation, father} = luke; + +console.log(occupation); // 'jedi' +console.log(father); // 'anakin' +``` + +[(back to table of contents)](#table-of-contents) + +## Modules + +ES6之前,浏览器端的模块化代码,我们使用像[Browserify](http://browserify.org/)这样的库, +在 **Node.js** 中,我们则使用 [require](https://nodejs.org/api/modules.html#modules_module_require_id)。 +在ES6中,我们现在可以直接使用AMD 和 CommonJS这些模块了。 + +### Exporting in CommonJS + +```javascript +module.exports = 1; +module.exports = { foo: 'bar' }; +module.exports = ['foo', 'bar']; +module.exports = function bar () {}; +``` + +### Exporting in ES6 + +在ES6中,提供了多种设置模块出口的方式,比如我们要导出一个变量,那么使用 **变量名** : + +```javascript +export let name = 'David'; +export let age = 25;​​ +``` + +还可以为对象 **导出一个列表**: + +```javascript +function sumTwo(a, b) { + return a + b; +} + +function sumThree(a, b, c) { + return a + b + c; +} + +export { sumTwo, sumThree }; +``` + +我们也可以使用简单的一个 `export` 关键字来导出一个结果值: + +```javascript +export function sumTwo(a, b) { + return a + b; +} + +export function sumThree(a, b, c) { + return a + b + c; +} +``` + +最后,我们可以 **导出一个默认出口**: + +```javascript +function sumTwo(a, b) { + return a + b; +} + +function sumThree(a, b, c) { + return a + b + c; +} + +let api = { + sumTwo, + sumThree +}; + +export default api; +``` + +> **最佳实践**:总是在模块的 **最后** 使用 `export default` 方法。 +它让模块的出口更清晰明了,节省了阅读整个模块来寻找出口的时间。 +更多的是,在大量CommonJS模块中,通用的习惯是设置一个出口值或者出口对象。 +最受这个规则,可以让我们的代码更易读,且更方便的联合使用CommonJS和ES6模块。 + +### Importing in ES6 + +ES6提供了好几种模块的导入方式。我们可以单独引入一个文件: + +```javascript +import 'underscore'; +``` + +> 这里需要注意的是, **整个文件的引入方式会执行该文件内的最上层代码**。 + +就像Python一样,我们还可以命名引用: + +```javascript +import { sumTwo, sumThree } from 'math/addition'; +``` + +我们甚至可以使用 `as` 给这些模块重命名: + +```javascript +import { + sumTwo as addTwoNumbers, + sumThree as sumThreeNumbers +} from 'math/addition'; +``` + +另外,我们能 **引入所有的东西(原文:import all the things)** (也称为命名空间引入) + +```javascript +import * as util from 'math/addition'; +``` + +最后,我们能可以从一个模块的众多值中引入一个列表: + +```javascript +import * as additionUtil from 'math/addtion'; +const { sumTwo, sumThree } = additionUtil; +``` + +当我们引用默认对象,我们可以选择其中的函数: + +```javascript +import React from 'react'; +const { Component, PropTypes } = React; +``` + +> **注意**:被导出的值是被 **绑定的(原文:bingdings)**,而不是引用。 +所以,改变一个模块中的值的话,会影响其他引用本模块的代码,一定要避免此种改动发生。 + +[(back to table of contents)](#table-of-contents) + +## Parameters + +在ES5中,许多种方法来处理函数的 **参数默认值(default values)**,**参数数量(indefinite arguments)**,**参数命名(named parameters)**。 +ES6中,我们可以使用非常简洁的语法来处理上面提到的集中情况。 + +### Default Parameters + +```javascript +function addTwoNumbers(x, y) { + x = x || 0; + y = y || 0; + return x + y; +} +``` + +ES6中,我们可以简单为函数参数启用默认值: + +```javascript +function addTwoNumbers(x=0, y=0) { + return x + y; +} +``` + +```javascript +addTwoNumbers(2, 4); // 6 +addTwoNumbers(2); // 2 +addTwoNumbers(); // 0 +``` + +### Rest Parameters + +ES5中,遇到参数数量不确定时,我们只能如此处理: + +```javascript +function logArguments() { + for (var i=0; i < arguments.length; i++) { + console.log(arguments[i]); + } +} +``` + +使用 **rest** 操作符,我们可以给函数传入一个不确定数量的参数列表: + +```javascript +function logArguments(...args) { + for (let arg of args) { + console.log(arg); + } +} +``` + +### Named Parameters + +命名函数 +ES5中,当我们要处理多个 **命名参数** 时,通常会传入一个 **选项对象** 的方式,这种方式被jQuery采用。 + +```javascript +function initializeCanvas(options) { + var height = options.height || 600; + var width = options.width || 400; + var lineStroke = options.lineStroke || 'black'; +} +``` + +我们可以利用上面提到的新特性 **结构** ,来完成与上面同样功能的函数: +We can achieve the same functionality using destructuring as a formal parameter +to a function: + +```javascript +function initializeCanvas( + { height=600, width=400, lineStroke='black'}) { + // ... + } + // Use variables height, width, lineStroke here +``` + +如果我们需要把这个参数变为可选的,那么只要把该参数结构为一个空对象就好了: + +```javascript +function initializeCanvas( + { height=600, width=400, lineStroke='black'} = {}) { + // ... + } +``` + +### Spread Operator + +我们可以利用展开操作符(Spread Operator)来把一组数组的值,当作参数传入: + +```javascript +Math.max(...[-1, 100, 9001, -32]); // 9001 +``` + +[(back to table of contents)](#table-of-contents) + +## Classes + +在ES6以前,我们实现一个类的功能的话,需要首先创建一个构造函数,然后扩展这个函数的原型方法,就像这样: + +```javascript +function Person(name, age, gender) { + this.name = name; + this.age = age; + this.gender = gender; +} + +Person.prototype.incrementAge = function () { + return this.age += 1; +}; +``` + +继承父类的子类需要这样: + +```javascript +function Personal(name, age, gender, occupation, hobby) { + Person.call(this, name, age, gender); + this.occupation = occupation; + this.hobby = hobby; +} + +Personal.prototype = Object.create(Person.prototype); +Personal.prototype.constructor = Personal; +Personal.prototype.incrementAge = function () { + return Person.prototype.incrementAge.call(this) += 20; +}; +``` + +ES6提供了一些语法糖来实现上面的功能,我们可以直接创建一个类: + +```javascript +class Person { + constructor(name, age, gender) { + this.name = name; + this.age = age; + this.gender = gender; + } + + incrementAge() { + this.age += 1; + } +} +``` + +继承父类的子类只要简单的使用 `extends` 关键字就可以了: + +```javascript +class Personal extends Person { + constructor(name, age, gender, occupation, hobby) { + super(name, age, gender); + this.occupation = occupation; + this.hobby = hobby; + } + + incrementAge() { + super.incrementAge(); + this.age += 20; + console.log(this.age); + } +} +``` + +> **最佳实践**:ES6新的类语法把我们从晦涩难懂的实现和原型操作中解救出来,这是个非常适合初学者的功能,而且能让我们写出更干净整洁的代码。 + +[(back to table of contents)](#table-of-contents) + +## Symbols + +符号在ES6版本之前就已经存在了,但现在我们拥有一个公共的接口来直接使用它们。 +下面的例子是创建了两个永远不会冲突的属性。 + +```javascript +const key = Symbol(); +const keyTwo = Symbol(); +const object = {}; + +object[key] = 'Such magic.'; +object[keyTwo] = 'Much Uniqueness'; + +// Two Symbols will never have the same value +>> key === keyTwo +>> false +``` + +[(back to table of contents)](#table-of-contents) + +## Maps + +**Maps** 是一个Javascript中很重要(迫切需要)的数据结构。 +在ES6之前,我们创建一个 **hash** 通常是使用一个对象: + +```javascript +var map = new Object(); +map[key1] = 'value1'; +map[key2] = 'value2'; +``` + +但是,这样的代码无法避免函数被特别的属性名覆盖的意外情况: + +```javascript +> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned'); +> TypeError: Property 'hasOwnProperty' is not a function +``` + +**Maps** 让我们使用 `set`,`get` 和 `search` 操作数据。 + +```javascript +let map = new Map(); +> map.set('name', 'david'); +> map.get('name'); // david +> map.has('name'); // true +``` + +Maps最强大的地方在于我们不必只能使用字符串来做key了,现在可以使用任何类型来当作key,而且key不会被强制类型转换为字符串。 + +```javascript +let map = new Map([ + ['name', 'david'], + [true, 'false'], + [1, 'one'], + [{}, 'object'], + [function () {}, 'function'] +]); + +for (let key of map.keys()) { + console.log(typeof key); + // > string, boolean, number, object, function +} +``` + +> **提示**:当使用 `map.get()` 判断值是否相等时,非基础类型比如一个函数或者对象,将不会正常工作。 +有鉴于此,还是建议使用字符串,布尔和数字类型的数据类型。 + +我们还可以使用 `.entries()` 方法来遍历整个map对象: + +```javascript +for (let [key, value] of map.entries()) { + console.log(key, value); +} +``` + +[(back to table of contents)](#table-of-contents) + +## WeakMaps + +In order to store private data in < ES5, we had various ways of doing this. +One such method was using naming conventions: + +```javascript +class Person { + constructor(age) { + this._age = age; + } + + _incrementAge() { + this._age += 1; + } +} +``` + +在一个开源项目中,命名规则很难维持得一直很好,这样经常会造成一些困扰。 +此时,我们可以选择使用WeakMaps来替代Maps来存储我们的数据: + +```javascript +let _age = new WeakMap(); +class Person { + constructor(age) { + _age.set(this, age); + } + + incrementAge() { + let age = _age.get(this) + 1; + _age.set(this, age); + if (age > 50) { + console.log('Midlife crisis'); + } + } +} +``` + +使用WeakMaps来保存我们私有数据的理由之一是不会暴露出属性名,就像下面的例子中的 `Reflect.ownKeys()`: + +```javascript +> const person = new Person(50); +> person.incrementAge(); // 'Midlife crisis' +> Reflect.ownKeys(person); // [] +``` + +一个使用WeakMaps存储数据更实际的例子,就是有关于一个DOM元素和对该DOM元素(有污染)地操作: + +```javascript +let map = new WeakMap(); +let el = document.getElementById('someElement'); + +// Store a weak reference to the element with a key +map.set(el, 'reference'); + +// Access the value of the element +let value = map.get(el); // 'reference' + +// Remove the reference +el.parentNode.removeChild(el); +el = null; + +value = map.get(el); // undefined +``` + +上面的例子中,一个对象被垃圾回收期给销毁了,WeakMaps会自动的把自己内部所对应的键值对数据同时销毁。 + +> **提示**:结合这个例子,再考虑下jQuery是如何实现缓存带有引用的DOM元素这个功能的,使用了WeakMaps的话,当被缓存的DOM元素被移除的时,jQuery可以自动释放相应元素的内存。 +通常情况下,在涉及DOM元素存储和缓存的情况下,使用WeakMaps是非常适合的。 + +[(back to table of contents)](#table-of-contents) + +## Promises + +Promises让我们让我们多缩进难看的代码(回调地狱): + +```javascript +func1(function (value1) { + func2(value1, function (value2) { + func3(value2, function (value3) { + func4(value3, function (value4) { + func5(value4, function (value5) { + // Do something with value 5 + }); + }); + }); + }); +}); +``` + +写成这样: + +```javascript +func1(value1) + .then(func2) + .then(func3) + .then(func4) + .then(func5, value5 => { + // Do something with value 5 + }); +``` + +在ES6之前,我们使用[bluebird](https://github.com/petkaantonov/bluebird) 或者 +[Q](https://github.com/kriskowal/q)。现在我们有了原生版本的 Promises: + +```javascript +new Promise((resolve, reject) => + reject(new Error('Failed to fulfill Promise'))) + .catch(reason => console.log(reason)); +``` + +这里有两个处理函数,**resolve**(当Promise执行成功完毕时调用的回调函数) 和 **reject** (当Promise执行不接受时调用的回调函数) + +> **Promises的好处**:大量嵌套错误回调函数会使代码变得难以阅读理解。 +使用了Promises,我们可以让我们代码变得更易读,组织起来更合理。 +此外,Promise处理后的值,无论是解决还是拒绝的结果值,都是不可改变的。 + +下面是一些使用Promises的实际例子: + +```javascript +var fetchJSON = function(url) { + return new Promise((resolve, reject) => { + $.getJSON(url) + .done((json) => resolve(json)) + .fail((xhr, status, err) => reject(status + err.message)); + }); +}; +``` + +我们还可以使用 `Promise.all()` 来异步的 **并行** 处理一个数组的数据。 + +```javascript +var urls = [ + 'http://www.api.com/items/1234', + 'http://www.api.com/items/4567' +]; + +var urlPromises = urls.map(fetchJSON); + +Promise.all(urlPromises) + .then(function (results) { + results.forEach(function (data) { + }); + }) + .catch(function (err) { + console.log('Failed: ', err); + }); +``` From f24abc8d70dd2b552a0c82a464ffdf65df6b0a3b Mon Sep 17 00:00:00 2001 From: chriscai Date: Mon, 1 Feb 2016 16:02:45 +0800 Subject: [PATCH 50/84] fixed the wrong char --- README_zhCn.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 686c938..3a3d5c0 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -318,7 +318,7 @@ console.log(b); // 2 ### Destructuring Objects -**结构对象** +**解构对象** ```javascript var luke = { occupation: 'jedi', father: 'anakin' }; @@ -524,7 +524,7 @@ function initializeCanvas(options) { } ``` -我们可以利用上面提到的新特性 **结构** ,来完成与上面同样功能的函数: +我们可以利用上面提到的新特性 **解构** ,来完成与上面同样功能的函数: We can achieve the same functionality using destructuring as a formal parameter to a function: @@ -536,7 +536,7 @@ function initializeCanvas( // Use variables height, width, lineStroke here ``` -如果我们需要把这个参数变为可选的,那么只要把该参数结构为一个空对象就好了: +如果我们需要把这个参数变为可选的,那么只要把该参数解构为一个空对象就好了: ```javascript function initializeCanvas( From aee3c2b016bac3d38d1aec4b22da52327f7d3ebd Mon Sep 17 00:00:00 2001 From: hkongm Date: Tue, 2 Feb 2016 09:10:45 +0800 Subject: [PATCH 51/84] back to in chinese & add the new part of generators and async await --- README_zhCn.md | 160 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 12 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 686c938..1a37dbb 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -17,6 +17,8 @@ - [Maps](#maps) - [WeakMaps](#weakmaps) - [Promises](#promises) +- [Generators](#generators) +- [Async Await](#async-await) ## var versus let / const @@ -67,7 +69,7 @@ let x = 'hi'; // ReferenceError: x is not defined > **最佳实践**: 在重构老代码时,`var` 声明需要格外的注意。在创建一个新项目时,使用 `let` 声明一个变量,使用 `const` 来声明一个不可改变的常量。 -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Replacing IIFEs with Blocks @@ -92,7 +94,7 @@ console.log(food); // Reference Error console.log(food); // Reference Error ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Arrow Functions @@ -181,7 +183,7 @@ const squares = arr.map(x => x * x); // Arrow Function for terser implementation > **最佳实践**:尽可能地多使用 **箭头函数**。 -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Strings @@ -291,7 +293,7 @@ let today = new Date(); let text = `The time and date is ${today.toLocaleString()}`; ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Destructuring @@ -318,7 +320,7 @@ console.log(b); // 2 ### Destructuring Objects -**结构对象** +**解构对象** ```javascript var luke = { occupation: 'jedi', father: 'anakin' }; @@ -334,7 +336,7 @@ console.log(occupation); // 'jedi' console.log(father); // 'anakin' ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Modules @@ -458,7 +460,7 @@ const { Component, PropTypes } = React; > **注意**:被导出的值是被 **绑定的(原文:bingdings)**,而不是引用。 所以,改变一个模块中的值的话,会影响其他引用本模块的代码,一定要避免此种改动发生。 -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Parameters @@ -553,7 +555,7 @@ function initializeCanvas( Math.max(...[-1, 100, 9001, -32]); // 9001 ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Classes @@ -623,7 +625,7 @@ class Personal extends Person { > **最佳实践**:ES6新的类语法把我们从晦涩难懂的实现和原型操作中解救出来,这是个非常适合初学者的功能,而且能让我们写出更干净整洁的代码。 -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Symbols @@ -643,7 +645,7 @@ object[keyTwo] = 'Much Uniqueness'; >> false ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Maps @@ -700,10 +702,11 @@ for (let [key, value] of map.entries()) { } ``` -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## WeakMaps + In order to store private data in < ES5, we had various ways of doing this. One such method was using naming conventions: @@ -771,7 +774,7 @@ value = map.get(el); // undefined > **提示**:结合这个例子,再考虑下jQuery是如何实现缓存带有引用的DOM元素这个功能的,使用了WeakMaps的话,当被缓存的DOM元素被移除的时,jQuery可以自动释放相应元素的内存。 通常情况下,在涉及DOM元素存储和缓存的情况下,使用WeakMaps是非常适合的。 -[(back to table of contents)](#table-of-contents) +[(回到目录)](#table-of-contents) ## Promises @@ -849,3 +852,136 @@ Promise.all(urlPromises) console.log('Failed: ', err); }); ``` + +[(回到目录)](#table-of-contents) + +## Generators + +Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid +[callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our +asynchronous code a synchronous feel. Generators are essentially functions which we can +[pause their excution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) +and subsequently return the value of an expression. + +A simple example of using generators is shown below: + +```javascript +function* sillyGenerator() { + yield 1; + yield 2; + yield 3; + yield 4; +} + +var generator = sillyGenerator(); +var value = generator.next(); +> console.log(value); // { value: 1, done: false } +> console.log(value); // { value: 2, done: false } +> console.log(value); // { value: 3, done: false } +> console.log(value); // { value: 4, done: false } +``` + +Where [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) +will allow us to push our generator forward and evaluate a new expression. While the above example is extremely +contrived, we can utilize Generators to write asynchronous code in a synchronous manner: + +```javascript +// Hiding asynchronousity with Generators + +function request(url) { + getJSON(url, function(response) { + generator.next(response); + }); +} +``` + +And here we write a generator function that will return our data: + +```javascript +function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +} +``` + +By the power of `yield`, we are gauranteed that `entry1` will have the data needed to be parsed and stored +in `data1`. + +While generators allow us to write asynchronous code in a synchronous manner, there is no clear +and easy path for error propagation. As such, as we can augment our generator with Promises: + +```javascript +function request(url) { + return new Promise((resolve, reject) => { + getJSON(url, resolve); + }); +} +``` + +And we write a function which will step through our generator using `next` which in turn will utilize our +`request` method above to yield a Promise: + +```javascript +function iterateGenerator(gen) { + var generator = gen(); + var ret; + (function iterate(val) { + ret = generator.next(); + if(!ret.done) { + ret.value.then(iterate); + } + })(); +} +``` + +[(回到目录)](#table-of-contents) + +By augmenting our Generator with Promises, we have a clear way of propogating errors through the use of our +Promise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before: + +```javascript +iterateGenerator(function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +}); +``` + +We were able to reuse our implementation to use our Generator as before, which shows their power. While Generators +and Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propogate +errors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits: +[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await). + +[(回到目录)](#table-of-contents) + +## Async Await + +While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished +using Generators and Promises with less effort: + +```javascript +var request = require('request'); + +function getJSON(url) { + return new Promise(function(resolve, reject) { + request(url, function(error, response, body) { + resolve(body); + }); + }); +} + +async function main() { + var data = await getJSON(); + console.log(data); // NOT undefined! +} + +main(); +``` + +Under the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource +for 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). + +[(回到目录)](#table-of-contents) From 5d2d8c50f9e450ff723eca1858def505d9beec5f Mon Sep 17 00:00:00 2001 From: hkongm Date: Tue, 2 Feb 2016 09:14:36 +0800 Subject: [PATCH 52/84] fix the lost translating paragragh in last version. --- README_zhCn.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 1a37dbb..2063087 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -706,9 +706,7 @@ for (let [key, value] of map.entries()) { ## WeakMaps - -In order to store private data in < ES5, we had various ways of doing this. -One such method was using naming conventions: +在ES5之前的版本,我们为了存储私有数据,有好几种方法。像使用这种下划线命名约定: ```javascript class Person { From 355f0af137fc05f8c6a7e8c8b8b3a6904296ff8b Mon Sep 17 00:00:00 2001 From: hkongm Date: Tue, 2 Feb 2016 09:58:08 +0800 Subject: [PATCH 53/84] add the generator and async await translating. --- README_zhCn.md | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 2063087..1e51502 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -855,13 +855,10 @@ Promise.all(urlPromises) ## Generators -Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid -[callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our -asynchronous code a synchronous feel. Generators are essentially functions which we can -[pause their excution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) -and subsequently return the value of an expression. +就像[Promises](https://github.com/DrkSephy/es6-cheatsheet#promises)如何让我们避免[回调地狱](http://callbackhell.com/)一样,Generators也可以使我们的代码扁平化,同时给予我们开发者像开发同步代码一样的感觉来写异步代码。Generators本质上是一种支持的函数,随后返回表达式的值。 +Generators实际上是支持[暂停运行](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield),随后根据上一步的返回值再继续运行的一种函数。 -A simple example of using generators is shown below: +下面代码是一个使用generators函数的简单例子: ```javascript function* sillyGenerator() { @@ -879,9 +876,8 @@ var value = generator.next(); > console.log(value); // { value: 4, done: false } ``` -Where [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) -will allow us to push our generator forward and evaluate a new expression. While the above example is extremely -contrived, we can utilize Generators to write asynchronous code in a synchronous manner: +就像上面的例子,当[next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)运行时,它会把我们的generator向前“推动”,同时执行新的表达式。 +我们能利用Generators来像书写同步代码一样书写异步代码。 ```javascript // Hiding asynchronousity with Generators @@ -893,7 +889,7 @@ function request(url) { } ``` -And here we write a generator function that will return our data: +这里我们写个generator函数将要返回我们的数据: ```javascript function* getData() { @@ -904,11 +900,9 @@ function* getData() { } ``` -By the power of `yield`, we are gauranteed that `entry1` will have the data needed to be parsed and stored -in `data1`. +借助于 `yield`,我们可以保证 `entry1` 确实拿到数据并转换后再赋值给 `data1`。 -While generators allow us to write asynchronous code in a synchronous manner, there is no clear -and easy path for error propagation. As such, as we can augment our generator with Promises: +当我们使用generators来像书写同步代码一样书写我们的异步代码逻辑时,没有一种清晰简单的方式来处理期间可能会产生的错误或者异常。在这种情况下,我们可以在我们的generator中引入Promises来处理,就像下面这样: ```javascript function request(url) { @@ -918,8 +912,7 @@ function request(url) { } ``` -And we write a function which will step through our generator using `next` which in turn will utilize our -`request` method above to yield a Promise: +我们再写一个函数,其中使用 `next` 来步进我们的generator的同事,再利用我们上面的 `request` 方法来产生(yield)一个Promise。 ```javascript function iterateGenerator(gen) { @@ -934,10 +927,8 @@ function iterateGenerator(gen) { } ``` -[(回到目录)](#table-of-contents) - -By augmenting our Generator with Promises, we have a clear way of propogating errors through the use of our -Promise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before: +在Generator中引入了Promises后,我们就可以通过Promise的 `.catch` 和 `reject` 来捕捉和处理错误了。 +使用了我们新版的Generator后,新版的调用就像老版本一样简单可读(译者注:有微调): ```javascript iterateGenerator(function* getData() { @@ -948,17 +939,15 @@ iterateGenerator(function* getData() { }); ``` -We were able to reuse our implementation to use our Generator as before, which shows their power. While Generators -and Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propogate -errors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits: -[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await). +在使用Generator后,我们可以重用我们的老版本代码实现,以此展示了Generator的力量。 +当使用Generators和Promises后,我们可以像书写同步代码一样书写异步代码的同时优雅地解决了错误处理问题。 +此后,我们实际上可以开始利用更简单的一种方式了,它就是[async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await)。 [(回到目录)](#table-of-contents) ## Async Await -While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished -using Generators and Promises with less effort: +`async await` 随着ES2016版本就要发布了,它给我们提供了一种更轻松的、更简单的可以替代的实现上面 Generators 配合 Promises 组合代码的一种编码方式,让我们来看看例子: ```javascript var request = require('request'); @@ -979,7 +968,7 @@ async function main() { main(); ``` -Under the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource -for 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). +它们看上去和Generators很像。我(作者)强烈推荐使用 `async await` 来替代Generators + Promises的写法。 +[这里](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html)是个很好的学习资源,让我们学习和使用这项ES7中的新功能。 [(回到目录)](#table-of-contents) From f21e95970e8838ce7343d0fd135dd87a9904d998 Mon Sep 17 00:00:00 2001 From: hkongm Date: Tue, 2 Feb 2016 10:44:15 +0800 Subject: [PATCH 54/84] fix Symbol desc for doc updates. --- README_zhCn.md | 64 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 1e51502..e2a67e3 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -629,22 +629,66 @@ class Personal extends Person { ## Symbols -符号在ES6版本之前就已经存在了,但现在我们拥有一个公共的接口来直接使用它们。 -下面的例子是创建了两个永远不会冲突的属性。 +符号(Symbols)在ES6版本之前就已经存在了,但现在我们拥有一个公共的接口来直接使用它们。 +Symbols对象是一旦创建就不可以被更改的(immutable)而且能被用做hash数据类型中的键。 + +### Symbol( ) +调用 `Symbol()` 或者 `Symbol(描述文本)` 会创建一个唯一的、在全局中不可以访问的符号对象。 +一个 `Symbol()` 的应用场景是:在自己的项目中使用第三方代码库,且你需要给他们的对象或者命名空间打补丁代码,又不想改动或升级第三方原有代码的时候。 +举个例子,如果你想给 `React.Component` 这个类添加一个 `refreshComponent` 方法,但又确定不了这个方法会不会在下个版本中加入,你可以这么做: ```javascript -const key = Symbol(); -const keyTwo = Symbol(); -const object = {}; +const refreshComponent = Symbol(); + +React.Component.prototype[refreshComponent] = () => { + // do something +} +``` + +### Symbol.for(key) + +使用 `Symbol.for(key)` 也是会创建一个不可改变的Symbol对象,但区别于上面的创建方法,这个对象是在全局中可以被访问到的。 +调用两次 `Symbol.for(key)` 会返回相同的Symbol实例。 -object[key] = 'Such magic.'; -object[keyTwo] = 'Much Uniqueness'; +**提示**:这并不同于 `Symbol(description)`。 -// Two Symbols will never have the same value ->> key === keyTwo ->> false +```javascript +Symbol('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol.for('foo') // true ``` +一个Symbols常用的使用场景,是需要使用特别 `Symbol.for(key)` 方法来实现代码间的协作。 +这能让你在你的代码中,查找包含已知的接口的第三方代码中Symbol成员。(译者:这句话好难翻。。。原文:This can be +achieved by having your code look for a Symbol member on object arguments from third parties that contain some known interface. )举个例子: + +```javascript +function reader(obj) { + const specialRead = Symbol.for('specialRead'); + if (obj[specialRead]) { + const reader = obj[specialRead](); + // do something with reader + } else { + throw new TypeError('object cannot be read'); + } +} +``` + +之后在另一个库中: + +```javascript +const specialRead = Symbol.for('specialRead'); + +class SomeReadableType { + [specialRead]() { + const reader = createSomeReaderFrom(this); + return reader; + } +} +``` + +> **注意**:`Symbol.iterable` 在ES6中像其他可枚举的对象,如数组,字符串,generators一样,当这个方法被调用时会激活一个枚举器并返回一个对象。 + [(回到目录)](#table-of-contents) ## Maps From 7b7ad558ef6ccae2ef729138d81eb8b3d62a0d0b Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Wed, 3 Feb 2016 18:37:28 -0500 Subject: [PATCH 55/84] Fixing reference to versions < ES6 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f25633c..4345d84 100644 --- a/README.md +++ b/README.md @@ -807,7 +807,7 @@ for (let [key, value] of map.entries()) { ## WeakMaps -In order to store private data in < ES5, we had various ways of doing this. +In order to store private data versions < ES6, we had various ways of doing this. One such method was using naming conventions: ```javascript From c69c0163b3d5a00569e7e448f54f747bd89d37e0 Mon Sep 17 00:00:00 2001 From: Eugene Glova Date: Sat, 6 Feb 2016 00:13:54 +0300 Subject: [PATCH 56/84] Fix generator next example --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4345d84..82426eb 100644 --- a/README.md +++ b/README.md @@ -986,11 +986,10 @@ function* sillyGenerator() { } var generator = sillyGenerator(); -var value = generator.next(); -> console.log(value); // { value: 1, done: false } -> console.log(value); // { value: 2, done: false } -> console.log(value); // { value: 3, done: false } -> console.log(value); // { value: 4, done: false } +> console.log(generator.next()); // { value: 1, done: false } +> console.log(generator.next()); // { value: 2, done: false } +> console.log(generator.next()); // { value: 3, done: false } +> console.log(generator.next()); // { value: 4, done: false } ``` Where [next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next) @@ -1094,4 +1093,4 @@ main(); Under the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource for 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). -[(back to table of contents)](#table-of-contents) \ No newline at end of file +[(back to table of contents)](#table-of-contents) From 026a484fad0c9d979b42b45d765004fbdf28bfe0 Mon Sep 17 00:00:00 2001 From: Eugene Glova Date: Sat, 6 Feb 2016 00:28:04 +0300 Subject: [PATCH 57/84] Remove outer scope var --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4345d84..32f9165 100644 --- a/README.md +++ b/README.md @@ -1038,9 +1038,8 @@ And we write a function which will step through our generator using `next` which ```javascript function iterateGenerator(gen) { var generator = gen(); - var ret; (function iterate(val) { - ret = generator.next(); + var ret = generator.next(); if(!ret.done) { ret.value.then(iterate); } @@ -1094,4 +1093,4 @@ main(); Under the hood, it performs similarly to Generators. I highly recommend using them over Generators + Promises. A great resource for 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). -[(back to table of contents)](#table-of-contents) \ No newline at end of file +[(back to table of contents)](#table-of-contents) From f8609e33a1f73d581c70f1bb33b7b84e479a9151 Mon Sep 17 00:00:00 2001 From: Cameron Chamberlain Date: Mon, 8 Feb 2016 09:27:44 +1100 Subject: [PATCH 58/84] Fix a few typos gauranteed -> guaranteed propogating -> propagating propogate -> propagate --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32f9165..4af2d2c 100644 --- a/README.md +++ b/README.md @@ -972,7 +972,7 @@ Promise.all(urlPromises) Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid [callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our asynchronous code a synchronous feel. Generators are essentially functions which we can -[pause their excution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) +[pause their execution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) and subsequently return the value of an expression. A simple example of using generators is shown below: @@ -1018,7 +1018,7 @@ function* getData() { } ``` -By the power of `yield`, we are gauranteed that `entry1` will have the data needed to be parsed and stored +By the power of `yield`, we are guaranteed that `entry1` will have the data needed to be parsed and stored in `data1`. While generators allow us to write asynchronous code in a synchronous manner, there is no clear @@ -1047,7 +1047,7 @@ function iterateGenerator(gen) { } ``` -By augmenting our Generator with Promises, we have a clear way of propogating errors through the use of our +By augmenting our Generator with Promises, we have a clear way of propagating errors through the use of our Promise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before: ```javascript @@ -1060,7 +1060,7 @@ iterateGenerator(function* getData() { ``` We were able to reuse our implementation to use our Generator as before, which shows their power. While Generators -and Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propogate +and Promises allow us to write asynchronous code in a synchronous manner while retaining the ability to propagate errors in a nice way, we can actually begin to utilize a simpler construction that provides the same benefits: [async-await](https://github.com/DrkSephy/es6-cheatsheet#async-await). From 13244c4df921be3b40281f1dd14545c6b9a2e00a Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Tue, 16 Feb 2016 11:47:35 +0200 Subject: [PATCH 59/84] fix(README): remove a repeated 'is' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a651c8..ecb8552 100644 --- a/README.md +++ b/README.md @@ -872,7 +872,7 @@ el = null; value = map.get(el); // undefined ``` -As shown above, once the object is is destroyed by the garbage collector, +As shown above, once the object is destroyed by the garbage collector, the WeakMap will automatically remove the key-value pair which was identified by that object. From 6e7bb50ff5185f3e0e3e6939cf5d8588d940c779 Mon Sep 17 00:00:00 2001 From: bhaskarmelkani Date: Mon, 25 Jan 2016 14:13:31 +0530 Subject: [PATCH 60/84] Added getter and setter function in ES6 --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/README.md b/README.md index ecb8552..904e6b4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ snippet examples for your day to day workflow. Contributions are welcome! - [Promises](#promises) - [Generators](#generators) - [Async Await](#async-await) +- [Getter/Setter functions](#getter-and-setter-functions) ## var versus let / const @@ -1093,3 +1094,64 @@ Under the hood, it performs similarly to Generators. I highly recommend using th for 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). [(back to table of contents)](#table-of-contents) +## Getter and setter functions + +ES6 has started supporting getter and setter functions. Using following example:- + +``` +class Employee { + + constructor(name) { + this._name = name; + } + + get name() { + if(this._name) { + return 'Mr. ' + this._name.toUpperCase(); + } else { + return undefined; + } + + } + + set name(newName) { + if(newName == this._name) { + console.log('I already have this name.'); + } else if(newName) { + this._name = newName; + } else { + return false; + } + } +} +var emp = new Employee("James Bond"); +if(emp.name) { // uses the get method in the background + console.log(emp.name); // Mr. James Bond +} +emp.name = "Bond 007"; // uses the setter in the background +console.log(emp.name); // Mr. Bond 007 +``` +Latest browsers are also supporting getter/setter functions in Objects and we can you them for computed properties, adding listeners, preprocessing before setting/getting :- + +``` +var person = { + firstName: 'James', + lastName: 'Bond', + get fullName() { + console.log('Setting FullName'); + return this.firstName + ' ' + this.lastName; + }, + set fullName (name) { + console.log('Getting FullName'); + var words = name.toString().split(' '); + this.firstName = words[0] || ''; + this.lastName = words[1] || ''; + } +} +person.fullName; // James Bond + +person.fullName = 'Bond 007'; + +person.fullName; // Bond 007 +``` +[(back to table of contents)](#table-of-contents) From 3817a36667b375109f2b91206010c67d4ebd556a Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Wed, 17 Feb 2016 14:54:34 -0500 Subject: [PATCH 61/84] Fixing formatting of getter / setter functions --- README.md | 68 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 904e6b4..4c6b096 100644 --- a/README.md +++ b/README.md @@ -1098,7 +1098,7 @@ for getting up and running with ES7 and Babel can be found [here](http://masnun. ES6 has started supporting getter and setter functions. Using following example:- -``` +```javascript class Employee { constructor(name) { @@ -1106,52 +1106,56 @@ class Employee { } get name() { - if(this._name) { - return 'Mr. ' + this._name.toUpperCase(); - } else { - return undefined; - } - + if(this._name) { + return 'Mr. ' + this._name.toUpperCase(); + } else { + return undefined; + } } set name(newName) { - if(newName == this._name) { - console.log('I already have this name.'); - } else if(newName) { - this._name = newName; - } else { - return false; - } + if (newName == this._name) { + console.log('I already have this name.'); + } else if (newName) { + this._name = newName; + } else { + return false; + } } } + var emp = new Employee("James Bond"); -if(emp.name) { // uses the get method in the background + +// uses the get method in the background +if (emp.name) { console.log(emp.name); // Mr. James Bond } -emp.name = "Bond 007"; // uses the setter in the background + +// uses the setter in the background +emp.name = "Bond 007"; console.log(emp.name); // Mr. Bond 007 ``` -Latest browsers are also supporting getter/setter functions in Objects and we can you them for computed properties, adding listeners, preprocessing before setting/getting :- -``` +Latest browsers are also supporting getter/setter functions in Objects and we can use them for computed properties, adding listeners and preprocessing before setting/getting: + +```javascript var person = { - firstName: 'James', - lastName: 'Bond', - get fullName() { - console.log('Setting FullName'); - return this.firstName + ' ' + this.lastName; - }, - set fullName (name) { - console.log('Getting FullName'); - var words = name.toString().split(' '); - this.firstName = words[0] || ''; - this.lastName = words[1] || ''; - } + firstName: 'James', + lastName: 'Bond', + get fullName() { + console.log('Setting FullName'); + return this.firstName + ' ' + this.lastName; + }, + set fullName (name) { + console.log('Getting FullName'); + var words = name.toString().split(' '); + this.firstName = words[0] || ''; + this.lastName = words[1] || ''; + } } -person.fullName; // James Bond +person.fullName; // James Bond person.fullName = 'Bond 007'; - person.fullName; // Bond 007 ``` [(back to table of contents)](#table-of-contents) From dcfdf13cae863832c980499dd4ca137894ae4366 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Wed, 17 Feb 2016 14:55:16 -0500 Subject: [PATCH 62/84] Minor update to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c6b096..e25e730 100644 --- a/README.md +++ b/README.md @@ -1096,7 +1096,7 @@ for getting up and running with ES7 and Babel can be found [here](http://masnun. [(back to table of contents)](#table-of-contents) ## Getter and setter functions -ES6 has started supporting getter and setter functions. Using following example:- +ES6 has started supporting getter and setter functions. Using the following example: ```javascript class Employee { From c3ab2e66a9f7aeb6862260deabdee1baedaa62a6 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Sat, 20 Feb 2016 21:03:50 -0500 Subject: [PATCH 63/84] Resolved #38 --- README.md | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e25e730..a2c5218 100644 --- a/README.md +++ b/README.md @@ -936,34 +936,45 @@ been resolved/rejected is immutable - it will never change. Here is a practical example of using Promises: ```javascript -var fetchJSON = function(url) { - return new Promise((resolve, reject) => { - $.getJSON(url) - .done((json) => resolve(json)) - .fail((xhr, status, err) => reject(status + err.message)); - }); -}; +var request = require('request'); + +return new Promise((resolve, reject) => { + request.get(url, (error, response, body) => { + if (body) { + resolve(JSON.parse(body)); + } else { + resolve({}); + } + }); +}); ``` We can also **parallelize** Promises to handle an array of asynchronous operations by using `Promise.all()`: ```javascript -var urls = [ - 'http://www.api.com/items/1234', - 'http://www.api.com/items/4567' +let urls = [ + '/api/commits', + '/api/issues/opened', + '/api/issues/assigned', + '/api/issues/completed', + '/api/issues/comments', + '/api/pullrequests' ]; -var urlPromises = urls.map(fetchJSON); +let promises = urls.map((url) => { + return new Promise((resolve, reject) => { + $.ajax({ url: url }) + .done((data) => { + resolve(data); + }); + }); +}); -Promise.all(urlPromises) - .then(function (results) { - results.forEach(function (data) { - }); - }) - .catch(function (err) { - console.log('Failed: ', err); - }); +Promise.all(promises) + .then((results) => { + // Do something with results of all our promises + }); ``` [(back to table of contents)](#table-of-contents) From 6f5780fcf147b361c2b2a51cd935be3e00dda410 Mon Sep 17 00:00:00 2001 From: Yingbai He Date: Sun, 21 Feb 2016 16:21:52 -0800 Subject: [PATCH 64/84] yh: modify es6 importing example to make it clearer. Also made cooresponding change on the chinese version --- README.md | 26 +++++++++++++++++++++++++- README_zhCn.md | 26 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2c5218..534a5f0 100644 --- a/README.md +++ b/README.md @@ -424,6 +424,10 @@ let api = { }; export default api; + +/* Which is the same as + * export { api as default }; + */ ``` > **Best Practices**: Always use the `export default` method at **the end** of @@ -471,8 +475,28 @@ Lastly, we can import a list of values from a module: import * as additionUtil from 'math/addition'; const { sumTwo, sumThree } = additionUtil; ``` +Importing from the default binding like this: + +```javascript +import api from 'math/addition'; +// Same as: import { default as api } from 'math/addition'; +``` + +While it is better to keep the exports simple, but we can sometimes mix default import and mixed import if needed. +When we are exporting like this: + +```javascript +// foos.js +export { foo as default, foo1, foo2 }; +``` + +We can import them like the following: + +```javaqscript +import foo, { foo1, foo2 } from 'foos'; +``` -When importing the default object we can choose which functions to import: +When importing a module exported using commonjs syntax (such as React) we can do: ```javascript import React from 'react'; diff --git a/README_zhCn.md b/README_zhCn.md index 42d40cb..e4c74b0 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -449,14 +449,38 @@ import * as util from 'math/addition'; import * as additionUtil from 'math/addtion'; const { sumTwo, sumThree } = additionUtil; ``` +像这样引用默认对象: -当我们引用默认对象,我们可以选择其中的函数: +```javascript +import api from 'math/addition'; +// Same as: import { default as api } from 'math/addition'; +``` + +我们建议一个模块导出的值应该越简洁越好,不过有时候有必要的话命名引用和默认引用可以混着用。如果一个模块是这样导出的: + +```javascript +// foos.js +export { foo as default, foo1, foo2 }; +``` +那我们可以如此导入这个模块的值: + +```javaqscript +import foo, { foo1, foo2 } from 'foos'; +``` + +我们还可以导入commonjs模块,例如React: ```javascript import React from 'react'; const { Component, PropTypes } = React; ``` +更简化版本: + +```javascript +import React, { Component, PropTypes } from 'react'; +``` + > **注意**:被导出的值是被 **绑定的(原文:bingdings)**,而不是引用。 所以,改变一个模块中的值的话,会影响其他引用本模块的代码,一定要避免此种改动发生。 From 749a02b8211140005d11f78b4ae412e587fe538d Mon Sep 17 00:00:00 2001 From: Justin Brown Date: Tue, 23 Feb 2016 20:18:31 -0600 Subject: [PATCH 65/84] Fix switched Console messages Fix switched Console messages for get/set --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 534a5f0..ac298c1 100644 --- a/README.md +++ b/README.md @@ -1178,11 +1178,11 @@ var person = { firstName: 'James', lastName: 'Bond', get fullName() { - console.log('Setting FullName'); + console.log('Getting FullName'); return this.firstName + ' ' + this.lastName; }, set fullName (name) { - console.log('Getting FullName'); + console.log('Setting FullName'); var words = name.toString().split(' '); this.firstName = words[0] || ''; this.lastName = words[1] || ''; From b8e14a4e288563f6b08a603009764e18176073a1 Mon Sep 17 00:00:00 2001 From: HyunSeob Date: Tue, 1 Mar 2016 16:57:54 +0900 Subject: [PATCH 66/84] Fix incorrect word --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac298c1..dc89714 100644 --- a/README.md +++ b/README.md @@ -492,7 +492,7 @@ export { foo as default, foo1, foo2 }; We can import them like the following: -```javaqscript +```javascript import foo, { foo1, foo2 } from 'foos'; ``` From 0eb59758f211de60a248c9d5e75eb865545a5523 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Tue, 1 Mar 2016 08:33:23 -0500 Subject: [PATCH 67/84] Resolved #73: Iterable -> Iterator --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc89714..b47b483 100644 --- a/README.md +++ b/README.md @@ -763,7 +763,7 @@ class SomeReadableType { } ``` -> A notable example of Symbol use for interoperability is `Symbol.iterable` which exists on all iterable and iterator +> A notable example of Symbol use for interoperability is `Symbol.iterator` which exists on all iterable types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator interface. From 2ee7b1e1fdc02dad83803f2e835d558ed48cc5dd Mon Sep 17 00:00:00 2001 From: HyunSeob Date: Wed, 2 Mar 2016 01:09:51 +0900 Subject: [PATCH 68/84] Add korean translation --- README_ko.md | 1100 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1100 insertions(+) create mode 100644 README_ko.md diff --git a/README_ko.md b/README_ko.md new file mode 100644 index 0000000..c5a96b0 --- /dev/null +++ b/README_ko.md @@ -0,0 +1,1100 @@ +# es6-cheatsheet + +ES2015(ES6)의 Tip & Tricks, 좋은 활용사례들과 코드 예제들이 포함된 cheatsheet입니다. +이 문서는 한국어 번역 버전입니다. 오역 제보와 더 좋은 번역을 기다리고 있습니다! + +## 목차 + +- [var VS let / const](#var-vs-let--const) +- [IIFE를 블록으로 교체하기](#IIFE를-블록으로-교체하기) +- [애로우 펑션](#애로우-펑션) +- [문자열](#문자열) +- [Destructuring](#destructuring) +- [모듈](#모듈) +- [파라미터(Parameter)](#파라미터-parameter-) +- [클래스](#클래스) +- [심볼(Symbol)](#심볼-symbol-) +- [맵(Map)](#맵-map-) +- [위크맵(WeakMap)](#위크맵-weakmap-) +- [Promise](#promise) +- [제너레이터](#제너레이터) +- [Async Await](#async-await) +- [Getter/Setter 함수](#getter와-setter-함수) + +## var VS let / const + +> 기존의 `var`에 더해 `let`과 `const`라는 값을 저장하기 위한 두 개의 새로운 식별자가 추가되었습니다. `var`와는 다르게, `let`과 `const` 상태는 스코프 내 최상단으로 호이스팅되지 않습니다. + +다음은 `var`를 활용한 예제입니다. + +```javascript +var snack = '허니버터칩'; + +function getFood(food) { + if (food) { + var snack = '스윙칩'; + return snack; + } + return snack; +} + +getFood(false); // undefined +``` + +그러나, `var` 대신 `let`을 사용하면 다음과 같이 동작합니다. + +```javascript +let snack = '허니버터칩'; + +function getFood(food) { + if (food) { + let snack = '스윙칩'; + return snack; + } + return snack; +} + +getFood(false); // '허니버터칩' +``` + +이런 변경점으로 인해 `var`를 사용했던 레거시 코드를 리팩토링할 때 더욱 조심해야 합니다. 무턱대고 `var` 대신 `let`을 사용하면 예상치 못한 동작을 할 수도 있습니다. + +> **Note**: `let`과 `const`는 블록 스코프 식별자입니다. 따라서, 블록 스코프 식별자로 정의하기 전에 참조하게 되면 `ReferenceError`를 발생시킵니다. + +```javascript +console.log(x); + +let x = 'hi'; // ReferenceError: x is not defined +``` + +> **Best Practice**: 더 조심스럽게 리팩토링하기 위해서 레거시 코드 내에 `var`선언을 남겨두세요. 새로운 코드베이스에서 작업하게 될 때, 변수 사용을 위해서 `let`을 사용하고, 상수 사용을 위해서 `const`를 사용하세요. + +[(목차로 돌아가기)](#목차) + +## IIFE를 블록으로 교체하기 + +> **Immediately Invoked Function Expressions(IIFE)**는 일반적으로 변수들을 별도의 스코프 안에서만 쓰기 위해서 사용되었습니다. ES6에서는 블록을 기반으로 스코프를 만들 수 있게 되었으므로, 더 이상 함수 기반으로 스코프를 만들지 않아도 됩니다. + +```javascript +(function () { + var food = '허니버터칩'; +}()); + +console.log(food); // Reference Error +``` + +ES6 블록을 사용하는 경우, + +```javascript +{ + let food = '허니버터칩'; +} + +console.log(food); // Reference Error +``` + +[(목차로 돌아가기)](#목차) + +## 애로우 펑션 + +종종 다음과 같이 중첩된 함수 안에서 `this`의 문맥(context)를 보존해야 할 일이 있습니다. + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; // Cannot read property 'name' of undefined + }); +}; +``` + +보통 이 문제를 해결하기 위해 다음과 같이 별도의 변수를 사용해서 `this`의 문맥을 저장합니다. + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + var that = this; // this의 문맥을 저장합니다. + return arr.map(function (character) { + return that.name + character; + }); +}; +``` + +또는, 다음과 같은 방법으로 `this` 문맥을 통과시킬 수도 있습니다. + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }, this); +}; +``` + +이 뿐만 아니라 문맥을 bind 할 수도 있습니다. + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(function (character) { + return this.name + character; + }.bind(this)); +}; +``` + +**애로우 펑션**을 사용하면, `this`의 문맥 값이 사라지지 않기 때문에 위의 코드는 다음과 같이 다시 쓸 수 있습니다. + +```javascript +function Person(name) { + this.name = name; +} + +Person.prototype.prefixName = function (arr) { + return arr.map(character => this.name + character); +}; +``` + +> **Best Practice**: `this`의 문맥 값을 보존해야할 때마다 **애로우 펑션**을 사용하세요. + +또한 애로우 펑션은 간단한 값을 리턴하는 함수(함수 표현식)가 필요할 때 사용하면 더욱 간결합니다. + +```javascript +var squares = arr.map(function (x) { return x * x }); // 함수 표현식 +``` + +```javascript +const arr = [1, 2, 3, 4, 5]; +const squares = arr.map(x => x * x); // 간결한 구현을 위한 애로우 펑션 +``` + +> **Best Practice**: 가능하다면 함수 표현식 대신 **애로우 펑션**을 활용하세요. + +[(목차로 돌아가기)](#목차) + +## 문자열 + +ES6에서는 표준 라이브러리가 크게 확장되었습니다. 이러한 변경에 맞춰 문자열에도 `.includes()`와 `.repeat()` 같은 새로운 메소드가 추가되었습니다. + +### .includes( ) + +```javascript +var string = 'food'; +var substring = 'foo'; + +console.log(string.indexOf(substring) > -1); +``` + +문자열 포함 여부를 구현하기 위해서 리턴 값이 `-1`보다 큰 지 체크하는 것 대신, 간단하게 불린 값을 리턴하는 `.includes()` 메소드를 사용할 수 있습니다. + +```javascript +const string = 'food'; +const substring = 'foo'; + +console.log(string.includes(substring)); // true +``` + +### .repeat( ) + +```javascript +function repeat(string, count) { + var strings = []; + while(strings.length < count) { + strings.push(string); + } + return strings.join(''); +} +``` + +ES6에서는 이제 간결하게 구현할 수 있습니다. + +```javascript +// String.repeat(numberOfRepetitions) +'야옹'.repeat(3); // '야옹야옹야옹' +``` + +### 템플릿 리터럴 + +**템플릿 리터럴**을 사용하면 명시적인 문자열 이스케이프를 사용하지 않아도 특수문자를 포함한 문자열을 구축할 수 있습니다. + +```javascript +var text = "이 문자열은 이스케이프 된 \"큰 따옴표\"를 포함합니다."; +``` + +```javascript +let text = `이 문자열은 이스케이프 된 "큰 따옴표"를 포함합니다.`; +``` + +**템플릿 리터럴**은 문자열과 값을 연결시키는 문자열 Interpolation도 지원합니다. + +```javascript +var name = '나비'; +var age = 13; + +console.log('제 고양이의 이름은 ' + name + '이고, 나이는 ' + age + '살 입니다.'); +``` + +더 간단하게 구현하면, + +```javascript +const name = '나비'; +const age = 13; + +console.log(`제 고양이의 이름은 ${name}이고, 나이는 ${age}살 입니다.`); +``` + +ES5에서는 개행을 구현하기 위해서 다음과 같이 했습니다. + +```javascript +var text = ( + '고양이\n' + + '강아지\n' + + '투니버스' +); +``` + +혹은 이렇게, + +```javascript +var text = [ + '고양이', + '강아지', + '투니버스' +].join('\n'); +``` + +**템플릿 리터럴**은 명시적으로 표시하지 않아도 개행을 보존합니다. + +```javascript +let text = ( `고양이 +강아지 +투니버스` +); +``` + +뿐만 아니라, **템플릿 리터럴**은 표현식에도 접근할 수 있습니다. + +```javascript +let today = new Date(); +let text = `현재 시각은 ${today.toLocaleString()}입니다.`; +``` + +[(목차로 돌아가기)](#목차) + +## Destructuring + +Destructuring은 배열 혹은 객체(깊게 중첩된 것도 포함하여)에서 편리한 문법을 이용해 값을 추출하고 저장하는데에 활용됩니다. + +### 배열 Destructuring + +```javascript +var arr = [1, 2, 3, 4]; +var a = arr[0]; +var b = arr[1]; +var c = arr[2]; +var d = arr[3]; +``` + +```javascript +let [a, b, c, d] = [1, 2, 3, 4]; + +console.log(a); // 1 +console.log(b); // 2 +``` + +### 객체 Destructuring + +```javascript +var luke = { occupation: 'jedi', father: 'anakin' }; +var occupation = luke.occupation; // 'jedi' +var father = luke.father; // 'anakin' +``` + +```javascript +let luke = { occupation: 'jedi', father: 'anakin' }; +let {occupation, father} = luke; + +console.log(occupation); // 'jedi' +console.log(father); // 'anakin' +``` + +[(목차로 돌아가기)](#목차) + +## 모듈 + +ES6 이전엔, 클라이언트 단은 [Browserify](http://browserify.org/), **Node.js**에서는 [require](https://nodejs.org/api/modules.html#modules_module_require_id)같은 라이브러리를 사용했습니다. 이제 ES6에서는 모든 종류(AMD와 CommonJS)의 모듈을 직접적으로 사용할 수 있습니다. + +### CommonJS의 모듈 내보내기(Export) + +```javascript +module.exports = 1; +module.exports = { foo: 'bar' }; +module.exports = ['foo', 'bar']; +module.exports = function bar () {}; +``` + +### ES6의 모듈 내보내기 + +ES6에서는, 다양한 방식으로 모듈을 내보낼 수 있습니다. 그 중 **지정 내보내기(named export)**방식은 다음과 같습니다. + +```javascript +export let name = 'David'; +export let age = 25;​​ +``` + +또한 객체를 이용한 **리스트 내보내기(exporting a list)**방식도 있습니다. + +```javascript +function sumTwo(a, b) { + return a + b; +} + +function sumThree(a, b, c) { + return a + b + c; +} + +export { sumTwo, sumThree }; +``` + +간단하게 `export` 키워드만 활용하면 함수, 객체, 값 등을 내보낼 수 있습니다. + +```javascript +export function sumTwo(a, b) { + return a + b; +} + +export function sumThree(a, b, c) { + return a + b + c; +} +``` + +마지막으로, **디폴트 모듈로 내보내기(default binding export)**도 가능합니다. + +```javascript +function sumTwo(a, b) { + return a + b; +} + +function sumThree(a, b, c) { + return a + b + c; +} + +let api = { + sumTwo, + sumThree +}; + +export default api; + +/* 위 코드는 아래와 같습니다. + * export { api as default }; + */ +``` + +> **Best Practice**: `export default`메소드는 항상 모듈 코드의 **마지막**에 위치해야 합니다. 그래야 내보내는 것이 무엇인지 분명해지며, 내보내는 값의 이름을 확인하는 시간을 절약할 수 있습니다. 그 이상으로, CommonJS의 일반적인 관행은 단일 값이나 객체를 내보내는 것입니다. 이런 컨벤션을 따름으로서, 코드의 가독성을 좋게 만들 수 있고 CommonJS와 ES6 모듈을 모두 사용할 수 있게 됩니다. + + +### ES6의 모듈 불러오기(import) + +ES6에서는 다양한 방식으로 모듈을 불러올 수 있습니다. 다음과 같이 파일 전체를 불러올 수 있습니다. + +```javascript +import 'underscore'; +``` + +> 이렇게 단순히 파일 전체를 불러오면 그 파일의 최상단에서 불러온 모든 코드가 실행된다는 점에 유의하시기 바랍니다. + +파이썬하고 유사한 지정 불러오기(named import)를 사용할 수 있습니다. + +```javascript +import { sumTwo, sumThree } from 'math/addition'; +``` + +다음과 같이 불러온 모듈의 이름을 새로 작성할 수도 있습니다. + +```javascript +import { + sumTwo as addTwoNumbers, + sumThree as sumThreeNumbers +} from 'math/addition'; +``` + +거기에 더해서, **모두 불러오기**(네임스페이스 불러오기)도 가능합니다. + +```javascript +import * as util from 'math/addition'; +``` + +마지막으로, 모듈에서 값들의 리스트를 불러올 수도 있습니다. + +```javascript +import * as additionUtil from 'math/addition'; +const { sumTwo, sumThree } = additionUtil; +``` + +디폴트 모듈은 다음과 같이 불러올 수 있습니다. + +```javascript +import api from 'math/addition'; +// 위 코드는 이렇게 표현할 수도 있습니다: import { default as api } from 'math/addition'; +``` + +가급적 간단한 형태로 모듈을 내보내는 것이 좋지만, 필요하다면 때때로 디폴트 모듈을 포함해 여러 이름을 섞어서 내보낼 수도 있습니다. + +```javascript +// foos.js +export { foo as default, foo1, foo2 }; +``` + +이 모듈은 아래와 같이 불러올 수 있습니다. + +```javascript +import foo, { foo1, foo2 } from 'foos'; +``` + +React처럼 CommonJS 문법을 사용해 내보낸 모듈을 불러올 때는 다음과 같이 쓰면 됩니다. + +```javascript +import React from 'react'; +const { Component, PropTypes } = React; +``` + +다음과 같이 더욱 간결해질 수도 있습니다. + +```javascript +import React, { Component, PropTypes } from 'react'; +``` + +> **Note**: 내보내지는 값은 참조되는 것이 아니라 **바인딩**되는 것입니다. 그러므로, 어떤 모듈의 변수 바인딩을 바꾸게 되면 내보낸 모듈 내에서만 바뀌게 됩니다. 이렇게 내보낸 모듈의 값의 인터페이스를 바꾸는 것은 피하세요. + +[(목차로 돌아가기)](#목차) + +## 파라미터(Parameter) + +ES5에서는 **디폴트 값(default values)**이나 **정의되지 않은 인자(indefinite arguments)** 혹은 **네임드 파라미터(named parameters)**를 다루는 함수를 구현하는 방법이 너무 많았습니다. ES6에서는 더욱 간결한 문법을 통해 이것들을 모두 다룰 수 있습니다. + +### 디폴트 파라미터(Default Parameter) + +```javascript +function addTwoNumbers(x, y) { + x = x || 0; + y = y || 0; + return x + y; +} +``` + +ES6에서는 함수 내 파라미터의 디폴트 값을 간단하게 설정할 수 있습니다. + +```javascript +function addTwoNumbers(x=0, y=0) { + return x + y; +} +``` + +```javascript +addTwoNumbers(2, 4); // 6 +addTwoNumbers(2); // 2 +addTwoNumbers(); // 0 +``` + +### 레스트 파라미터(Rest Parameter) + +ES5에서는 인수의 숫자가 가변적인 경우 다음과 같이 처리했습니다. + +```javascript +function logArguments() { + for (var i=0; i < arguments.length; i++) { + console.log(arguments[i]); + } +} +``` + +**레스트(rest)**연산자를 사용하면, 다음과 같이 가변적인 숫자의 인수를 넘길 수 있습니다. + +```javascript +function logArguments(...args) { + for (let arg of args) { + console.log(arg); + } +} +``` + +### 네임드 파라미터(Named Parameter) + +ES5의 네임드 파라미터를 처리하는 방법 중 하나는 jQuery에서 차용된 **options object** 패턴을 사용하는 것입니다. + +```javascript +function initializeCanvas(options) { + var height = options.height || 600; + var width = options.width || 400; + var lineStroke = options.lineStroke || 'black'; +} +``` + +파라미터에 destructuring을 사용하면 같은 기능을 구현할 수 있습니다. + +```javascript +function initializeCanvas( + { height=600, width=400, lineStroke='black'}) { + // 여기에서 height, width, lineStroke 변수를 사용합니다. + } +``` + +만약 모든 파라미터를 선택적으로 넘기고 싶다면, 다음과 같이 빈 객체로 destructuring 하면 됩니다. + +```javascript +function initializeCanvas( + { height=600, width=400, lineStroke='black'} = {}) { + // ... + } +``` + +### 전개 연산자(Spread Operator) + +ES5에서는 배열 내 숫자들의 최대 값을 찾기 위해서 `Math.max`에 `apply` 메소드를 사용했습니다. + +```javascript +Math.max.apply(null, [-1, 100, 9001, -32]); // 9001 +``` + +ES6에서는 이제 전개 연산자를 이용해서 함수에 파라미터로 배열을 넘길 수 있습니다. + +```javascript +Math.max(...[-1, 100, 9001, -32]); // 9001 +``` + +다음과 같이 직관적인 문법을 통해 쉽게 배열 리터럴을 합칠 수도 있습니다. + +```javascript +let cities = ['서울', '부산']; +let places = ['여수', ...cities, '제주']; // ['여수', '서울', '부산', '제주'] +``` + +[(목차로 돌아가기)](#목차) + +## 클래스 + +ES6 이전에는, 생성자 함수(constructor)를 만들고 프로토타입을 확장해서 프로퍼티를 추가하여 클래스를 구현했습니다. + +```javascript +function Person(name, age, gender) { + this.name = name; + this.age = age; + this.gender = gender; +} + +Person.prototype.incrementAge = function () { + return this.age += 1; +}; +``` + +그리고 다음과 같이 클래스를 상속했습니다. + +```javascript +function Personal(name, age, gender, occupation, hobby) { + Person.call(this, name, age, gender); + this.occupation = occupation; + this.hobby = hobby; +} + +Personal.prototype = Object.create(Person.prototype); +Personal.prototype.constructor = Personal; +Personal.prototype.incrementAge = function () { + Person.prototype.incrementAge.call(this); + this.age += 20; + console.log(this.age); +}; +``` + +ES6는 이런 간단한 구현을 위해 편리한 문법을 제공합니다. 이제 클래스를 직접 만들 수 있습니다. + +```javascript +class Person { + constructor(name, age, gender) { + this.name = name; + this.age = age; + this.gender = gender; + } + + incrementAge() { + this.age += 1; + } +} +``` + +그리고 `extends` 키워드를 사용해서 상속할 수 있습니다. + +```javascript +class Personal extends Person { + constructor(name, age, gender, occupation, hobby) { + super(name, age, gender); + this.occupation = occupation; + this.hobby = hobby; + } + + incrementAge() { + super.incrementAge(); + this.age += 20; + console.log(this.age); + } +} +``` + +> **Best Practice**: 클래스를 만들기 위한 ES6의 문법은 내부적으로 어떻게 프로토타입으로 구현되는지 모호하지만, 초보자들에게 좋은 기능이고 더 깨끗한 코드를 작성하도록 도와줍니다. + +[(목차로 돌아가기)](#목차) + +## 심볼(Symbol) + +심볼은 ES6 이전에도 존재했지만, 이제 직접적으로 심볼을 사용할 수 있는 공식 인터페이스가 제공됩니다. 심볼은 고유하고 수정 불가능한 데이터 타입이고 모든 객체의 식별자로 활용할 수 있습니다. + +### Symbol() + +`Symbol()` 혹은 `Symbol(description)` 메소드를 호출하면 전역적으로 사용할 수 없는 고유한 심볼이 생성될 것입니다. `Symbol()`은 써드 파티 라이브러리의 객체 혹은 네임스페이스에 충돌할 염려가 없는 새로운 코드를 덧입히는데 종종 쓰입니다. 예를 들어, 나중에 라이브러리가 업데이트 되더라도 겹칠 우려가 없이 `React.Component` 클래스에 `refreshComponent` 메소드를 추가하고 싶다면 다음과 같이 할 수 있습니다. + +```javascript +const refreshComponent = Symbol(); + +React.Component.prototype[refreshComponent] = () => { + // do something +} +``` + + +### Symbol.for(key) + +`Symbol.for(key)`는 여전히 고유하고 수정 불가능한 심볼을 생성하지만, 전역적으로 사용 가능합니다. `Symbol.for(key)`를 두 번 호출하면 두 번 다 같은 심볼 인스턴스를 반환합니다. 주의하세요. `Symbol(description)`에서는 그렇지 않습니다. + +```javascript +Symbol('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol('foo') // false +Symbol.for('foo') === Symbol.for('foo') // true +``` + +일반적으로 심볼, 특히 `Symbol.for(key)`은 상호 운용성을 위해 사용합니다. 상호 운용성은 몇 가지 알려진 인터페이스를 포함하는 서드 파티 라이브러리의 객체에 인자로 심볼 멤버 형태의 코드를 사용함으로서 만족될 수 있습니다. 예를 들면, + +```javascript +function reader(obj) { + const specialRead = Symbol.for('specialRead'); + if (obj[specialRead]) { + const reader = obj[specialRead](); + // do something with reader + } else { + throw new TypeError('객체를 읽을 수 없습니다.'); + } +} +``` + +또 다른 라이브러리에선 이렇게 할 수 있습니다. + +```javascript +const specialRead = Symbol.for('specialRead'); + +class SomeReadableType { + [specialRead]() { + const reader = createSomeReaderFrom(this); + return reader; + } +} +``` + +> 상호 운용성을 위해 심볼을 사용하는 주목할 만한 예는 모든 반복 가능한(iterable) 타입 혹은 반복자(iterator)에 존재하는 `Symbol.iterator`입니다. 배열, 문자열, 생성자, 등 반복 가능한 타입은 이 메소드를 통해 호출되면 반복자 인터페이스를 포함한 객체 형태로 리턴됩니다. + +[(목차로 돌아가기)](#목차) + +## 맵(Map) +**맵**은 자바스크립트에서 자주 필요한 데이터 구조입니다. ES6 이전엔 객체를 이용해서 **해시** 맵을 생성했습니다. + +```javascript +var map = new Object(); +map[key1] = 'value1'; +map[key2] = 'value2'; +``` + +하지만, 이 방법은 특정 프로퍼티 이름으로 인한 예상치 못한 함수 오버라이드(override)로부터 안전하지 않습니다. + +```javascript +> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned'); +> TypeError: Property 'hasOwnProperty' is not a function +``` + +실제로 **맵**은 값을 위해 `get`, `set` 그리고 `search` 등의 메소드를 제공합니다. + +```javascript +let map = new Map(); +> map.set('name', '현섭'); +> map.get('name'); // 현섭 +> map.has('name'); // true +``` + +맵의 가장 놀라운 점은 더 이상 키 값으로 문자열만 쓰지 않아도 된다는 것입니다. 이제 키 값으로 어떤 타입을 전달해도 문자열로 형변환되지 않습니다. + +```javascript +let map = new Map([ + ['이름', '현섭'], + [true, 'false'], + [1, '하나'], + [{}, '객체'], + [function () {}, '함수'] +]); + +for (let key of map.keys()) { + console.log(typeof key); + // > string, boolean, number, object, function +} +``` + +> **Note**: 함수나 객체처럼 기본형 데이터 타입이 아닌 타입을 사용하면 `map.get()`같은 메소드를 사용할 때 비교 연산자가 제대로 동작하지 않습니다. 따라서, 문자열, 불린, 숫자 같은 기본형 데이터 타입을 계속 쓰는 것이 좋습니다. + +또한 `.entries()`를 사용하면 맵을 순회할 수 있습니다. + +```javascript +for (let [key, value] of map.entries()) { + console.log(key, value); +} +``` + +[(목차로 돌아가기)](#목차) + +## 위크맵(WeakMap) + +ES6 이전에는 private 데이터를 저장하기 위해서 많은 방법을 사용했습니다. 그 중 한가지가 네이밍 컨벤션을 이용한 방법이죠. + +```javascript +class Person { + constructor(age) { + this._age = age; + } + + _incrementAge() { + this._age += 1; + } +} +``` + +그러나 네이밍 컨벤션은 코드베이스에 대해 혼란을 일으킬 수 있고, 항상 유지된다는 보장을 할 수 없었습니다. 이제 위크맵으로 이런 값을 저장할 수 있습니다. + +```javascript +let _age = new WeakMap(); +class Person { + constructor(age) { + _age.set(this, age); + } + + incrementAge() { + let age = _age.get(this) + 1; + _age.set(this, age); + if (age > 50) { + console.log('중년의 위기'); + } + } +} +``` + +Private 데이터를 저장하기 위해 위크맵을 사용해서 좋은 점은 `Reflect.ownKeys()`를 사용해도 프로퍼티 이름을 드러내지 않는다는 것입니다. + +```javascript +> const person = new Person(50); +> person.incrementAge(); // '중년의 위기' +> Reflect.ownKeys(person); // [] +``` + +위크맵을 사용하는 더욱 실질적인 예는 DOM 요소 자체를 훼손시키지 않고도 DOM 요소에 관련된 데이터를 저장하는 것입니다. + +```javascript +let map = new WeakMap(); +let el = document.getElementById('someElement'); + +// 요소에 대한 약한 참조(weak reference)를 저장 +map.set(el, '참조'); + +// 요소의 값에 접근 +let value = map.get(el); // '참조' + +// 참조 제거 +el.parentNode.removeChild(el); +el = null; + +value = map.get(el); // undefined +``` + +위에서 보여준 대로, 객체가 가비지 콜렉터에 의해 한 번 제거된 다음에는 위크맵이 자동적으로 해당 객체에 의해 식별되는 key-value 쌍을 제거합니다. + +> **Note**: 더 나아가, 이 예제의 유용함을 보여주기 위해 jQuery가 참조를 가진 DOM 요소에 대응되는 객체의 캐시를 저장하는 방법을 생각해보세요. 위크맵을 사용하면, jQuery는 문서에서 지워진 특정 DOM 요소에 관련된 모든 메모리를 자동적으로 절약할 수 있습니다. 전반적으로, 위크맵은 DOM 요소를 감싸는 모든 라이브러리에 매우 유용합니다. + +[(목차로 돌아가기)](#목차) + +## Promise + +Promise는 다음과 같이 수평적인 코드(콜백 지옥)의 형태를 바꿀 수 있게 해줍니다. + +```javascript +func1(function (value1) { + func2(value1, function (value2) { + func3(value2, function (value3) { + func4(value3, function (value4) { + func5(value4, function (value5) { + // Do something with value 5 + }); + }); + }); + }); +}); +``` + +수직적인 코드로 바꾸면, + +```javascript +func1(value1) + .then(func2) + .then(func3) + .then(func4) + .then(func5, value5 => { + // Do something with value 5 + }); +``` + +ES6 이전엔, [bluebird](https://github.com/petkaantonov/bluebird) 혹은 [Q](https://github.com/kriskowal/q)같은 라이브러리를 사용했었습니다. 이제는 Promise가 네이티브로 지원됩니다. + +```javascript +new Promise((resolve, reject) => + reject(new Error('Promise가 제대로 동작하지 않았습니다!'))) + .catch(reason => console.log(reason)); +``` + +Promise가 제대로 동작(**fulfill**)했을 때 호출되는 **resolve** 메소드와 Promise가 제대로 동작하지 않(**rejected**)았을 때 호출되는 **reject** 메소드를 이용해 Promise를 다룰 수 있습니다. + +> **Promise의 장점**: 중첩된 콜백 코드에서는 에러 핸들링하기가 혼란스럽습니다. Promise를 사용하면 에러를 적절히 위로 깨끗하게 전파할 수 있습니다. 게다가, resolve/reject된 후의 Promise의 값은 불변입니다. + +아래는 Promise를 사용하는 실질적인 예제입니다. + +```javascript +var request = require('request'); + +return new Promise((resolve, reject) => { + request.get(url, (error, response, body) => { + if (body) { + resolve(JSON.parse(body)); + } else { + resolve({}); + } + }); +}); +``` + +또한 `Promise.all()`을 사용해서 비동기 동작들의 배열을 다루는 Promise를 **병렬화**할 수 있습니다. + +```javascript +let urls = [ + '/api/commits', + '/api/issues/opened', + '/api/issues/assigned', + '/api/issues/completed', + '/api/issues/comments', + '/api/pullrequests' +]; + +let promises = urls.map((url) => { + return new Promise((resolve, reject) => { + $.ajax({ url: url }) + .done((data) => { + resolve(data); + }); + }); +}); + +Promise.all(promises) + .then((results) => { + // Do something with results of all our promises + }); +``` + +[(목차로 돌아가기)](#목차) + +## 제너레이터(Generator) + +[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)하고 나중에 표현식의 값을 돌려주는 함수입니다. + +다음은 제너레이터를 사용하는 간단한 예입니다. + +```javascript +function* sillyGenerator() { + yield 1; + yield 2; + yield 3; + yield 4; +} + +var generator = sillyGenerator(); +> console.log(generator.next()); // { value: 1, done: false } +> console.log(generator.next()); // { value: 2, done: false } +> console.log(generator.next()); // { value: 3, done: false } +> console.log(generator.next()); // { value: 4, done: false } +``` +[next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)를 사용하면 제너레이터를 전진시키고 새로운 표현식을 계산합니다. 위의 예제는 극히 부자연스럽지만, 다음과 같이 제너레이터는 비동기적인 코드를 동기적인 방식으로 작성하는데에 활용할 수 있습니다. + +```javascript +// 제너레이터를 이용해 비동기 동작을 숨김 + +function request(url) { + getJSON(url, function(response) { + generator.next(response); + }); +} +``` + +그리고 데이터를 돌려줄 제너레이터 함수를 작성합니다. + +```javascript +function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +} +``` + +`yield` 덕분에, `data1`에 데이터가 파싱될 필요가 있을 때에만 `entry1`이 데이터를 가질 것임을 보장할 수 있습니다. + +제너레이터는 비동기적인 코드를 동기적인 방식으로 작성하는데 도움을 주지만, 에러 전파는 깨끗하지 않고 쉽지 않은 경로를 통해 해야 합니다. 그렇기 때문에, Promise를 통해 제너레이터를 보완할 수 있습니다. + +```javascript +function request(url) { + return new Promise((resolve, reject) => { + getJSON(url, resolve); + }); +} +``` + +그리고 `next`를 사용하는 제너레이터를 통해 단계별로 진행하는 함수를 작성합니다. `next`는 `request` 메소드를 사용하여 위의 Promise를 돌려줍니다. + +```javascript +function iterateGenerator(gen) { + var generator = gen(); + (function iterate(val) { + var ret = generator.next(); + if(!ret.done) { + ret.value.then(iterate); + } + })(); +} +``` + +Promise를 통해 제너레이터를 보완함으로서, Promise의 `.catch`와 `reject`를 활용해 에러 전파를 깨끗하게 할 수 있게 되었습니다. 다음과 같이 새롭게 개선된 제너레이터를 사용하면 전보다 더 간단합니다. + +```javascript +iterateGenerator(function* getData() { + var entry1 = yield request('http://some_api/item1'); + var data1 = JSON.parse(entry1); + var entry2 = yield request('http://some_api/item2'); + var data2 = JSON.parse(entry2); +}); +``` + +구현했던 코드는 전처럼 제너레이터를 사용하기 위해서 재활용할 수 있습니다. 제너레이터와 Promise가 비동기적인 코드를 동기적인 방식으로 작성하면서도 에러 전파를 좋은 방법으로 하도록 유지시킬 수 있도록 도와줬지만, 사실, [async-await](https://github.com/DrkSephy/es6-cheatsheet/blob/master/README_ko.md#async-await)는 같은 이점을 더 간단한 형태로 활용할 수 있도록 제공합니다. + +[(목차로 돌아가기)](#목차) + +## Async Await + +사실 `async await`는 곧 나올 ES2016의 기능이지만, 제너레이터와 Promise를 같이써야 할 수 있었던 것들을 더 적은 노력으로 가능하게 합니다. + +```javascript +var request = require('request'); + +function getJSON(url) { + return new Promise(function(resolve, reject) { + request(url, function(error, response, body) { + resolve(body); + }); + }); +} + +async function main() { + var data = await getJSON(); + console.log(data); // undefined 값이 아님! +} + +main(); +``` + +간단한 구현이지만, 제너레이터와 비슷하게 동작하는 코드입니다. 저는 제너레이터 + Promise보다는 `async-await`를 사용하는 것을 강력하게 추천드립니다. [여기](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html)에서 ES7과 Babel을 통해 실행할 수 있는 좋은 예제를 얻을 수 있습니다. + +[(목차로 돌아가기)](#목차) + +## Getter와 Setter 함수 + +ES6는 getter와 setter 함수를 지원하기 시작했습니다. 다음 예제를 보세요. + +```javascript +class Employee { + + constructor(name) { + this._name = name; + } + + get name() { + if(this._name) { + return this._name.toUpperCase() + ' 양'; + } else { + return undefined; + } + } + + set name(newName) { + if (newName == this._name) { + console.log('이미 같은 이름을 쓰고 있습니다.'); + } else if (newName) { + this._name = newName; + } else { + return false; + } + } +} + +var emp = new Employee("솔지"); + +// 내부적으로 get 메소드를 활용 +if (emp.name) { + console.log(emp.name); // 솔지 양 +} + +// 내부적으로 setter를 활용 +emp.name = "EXID 솔지"; +console.log(emp.name); // EXID 솔지 양 +``` + +가장 최근의 브라우저들은 객체의 getter와 setter 함수를 지원합니다. set/get 전에 리스너와 전처리작업을 추가하여 계산된 프로퍼티를 위해 getter와 settter를 활용할 수 있습니다. + +```javascript +var person = { + firstName: '솔지', + lastName: '허', + get fullName() { + console.log('이름 Get'); + return this.lastName + ' ' + this.firstName; + }, + set fullName (name) { + console.log('이름 Set'); + var words = name.toString().split(' '); + this.lastName = words[0] || ''; + this.firstName = words[1] || ''; + } +} + +person.fullName; // 허 솔지 +person.fullName = 'EXID 솔지'; +person.fullName; // EXID 솔지 +``` +[(목차로 돌아가기)](#목차) From abc71523356babe5ee3b17a7223d1d01ab73cfed Mon Sep 17 00:00:00 2001 From: HyunSeob Date: Wed, 2 Mar 2016 01:15:59 +0900 Subject: [PATCH 69/84] Fix anchors --- README_ko.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README_ko.md b/README_ko.md index c5a96b0..4f5a83a 100644 --- a/README_ko.md +++ b/README_ko.md @@ -6,18 +6,18 @@ ES2015(ES6)의 Tip & Tricks, 좋은 활용사례들과 코드 예제들이 포 ## 목차 - [var VS let / const](#var-vs-let--const) -- [IIFE를 블록으로 교체하기](#IIFE를-블록으로-교체하기) +- [IIFE를 블록으로 교체하기](#iife를-블록으로-교체하기) - [애로우 펑션](#애로우-펑션) - [문자열](#문자열) - [Destructuring](#destructuring) - [모듈](#모듈) -- [파라미터(Parameter)](#파라미터-parameter-) +- [파라미터(Parameter)](#파라미터parameter) - [클래스](#클래스) -- [심볼(Symbol)](#심볼-symbol-) -- [맵(Map)](#맵-map-) -- [위크맵(WeakMap)](#위크맵-weakmap-) +- [심볼(Symbol)](#심볼symbol) +- [맵(Map)](#맵map) +- [위크맵(WeakMap)](#위크맵weakmap) - [Promise](#promise) -- [제너레이터](#제너레이터) +- [제너레이터(Generator)](#제너레이터generator) - [Async Await](#async-await) - [Getter/Setter 함수](#getter와-setter-함수) From e358ec584206ece59d812ce178beb883a6fe88fe Mon Sep 17 00:00:00 2001 From: "M. Junaid Salaat" Date: Fri, 8 Apr 2016 10:26:42 +0500 Subject: [PATCH 70/84] Fixed results for Getter and setter functions. 'emp.name' is returning the name in upper case. Fixed it. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b47b483..25454dd 100644 --- a/README.md +++ b/README.md @@ -1163,14 +1163,15 @@ var emp = new Employee("James Bond"); // uses the get method in the background if (emp.name) { - console.log(emp.name); // Mr. James Bond + console.log(emp.name); // Mr. JAMES BOND } // uses the setter in the background emp.name = "Bond 007"; -console.log(emp.name); // Mr. Bond 007 +console.log(emp.name); // Mr. BOND 007 ``` + Latest browsers are also supporting getter/setter functions in Objects and we can use them for computed properties, adding listeners and preprocessing before setting/getting: ```javascript From 5c7255506157136cc6310763ca512062209d7191 Mon Sep 17 00:00:00 2001 From: "M. Junaid Salaat" Date: Fri, 8 Apr 2016 10:44:16 +0500 Subject: [PATCH 71/84] erased an extra new line --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 25454dd..d5df345 100644 --- a/README.md +++ b/README.md @@ -1171,7 +1171,6 @@ emp.name = "Bond 007"; console.log(emp.name); // Mr. BOND 007 ``` - Latest browsers are also supporting getter/setter functions in Objects and we can use them for computed properties, adding listeners and preprocessing before setting/getting: ```javascript From 5a1dd7377b7a7d8eb647330ad7403d2b49386561 Mon Sep 17 00:00:00 2001 From: Camilo Bravo Date: Wed, 13 Apr 2016 12:37:52 -0500 Subject: [PATCH 72/84] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5df345..8a34c1d 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ var text = "This string contains \"double quotes\" which are escaped."; ``` ```javascript -let text = `This string contains "double quotes" which are escaped.`; +let text = `This string contains "double quotes" which don't need to be escaped anymore.`; ``` **Template Literals** also support interpolation, which makes the task of From 5466a1fd2c57ffa3625d0767a1b302262fa609a5 Mon Sep 17 00:00:00 2001 From: Camilo Bravo Date: Wed, 13 Apr 2016 12:39:47 -0500 Subject: [PATCH 73/84] Update README_zhCn.md --- README_zhCn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zhCn.md b/README_zhCn.md index e4c74b0..2948555 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -236,7 +236,7 @@ var text = "This string contains \"double quotes\" which are escaped."; ``` ```javascript -let text = `This string contains "double quotes" which are escaped.`; +let text = `This string contains "double quotes" which don't need to be escaped anymore.`; ``` **字符串模板字面量** 还支持直接插入变量,可以实现字符串与变量的直接连接输出。 From a16a17bade41c8cf88c111ccc143ee714cc3e173 Mon Sep 17 00:00:00 2001 From: Do Minh Hai Date: Fri, 15 Apr 2016 15:31:03 +0900 Subject: [PATCH 74/84] ReferenceError on calling statement Declaring statement will not be raised any error. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5df345..cfe6c84 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ block-scoped identifiers before they are defined will produce a `ReferenceError`. ```javascript -console.log(x); +console.log(x); // ReferenceError: x is not defined -let x = 'hi'; // ReferenceError: x is not defined +let x = 'hi'; ``` > **Best Practice**: Leave `var` declarations inside of legacy code to denote From d70c3492822fe1bd195744d6f0513aad514cd4e0 Mon Sep 17 00:00:00 2001 From: Xuefeng Zhu Date: Thu, 12 May 2016 20:08:53 -0500 Subject: [PATCH 75/84] update weakmap example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac49ca8..c6c2ba6 100644 --- a/README.md +++ b/README.md @@ -894,7 +894,7 @@ let value = map.get(el); // 'reference' el.parentNode.removeChild(el); el = null; -value = map.get(el); // undefined +// map is empty, since the element is destroyed ``` As shown above, once the object is destroyed by the garbage collector, From e9d0560d0e20f0057273e25f7a63d3d730104ba3 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Mon, 25 Jul 2016 09:01:56 +0800 Subject: [PATCH 76/84] Fix generator next example (README_zhCn.md) --- README_zhCn.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 2948555..52897d5 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -937,11 +937,10 @@ function* sillyGenerator() { } var generator = sillyGenerator(); -var value = generator.next(); -> console.log(value); // { value: 1, done: false } -> console.log(value); // { value: 2, done: false } -> console.log(value); // { value: 3, done: false } -> console.log(value); // { value: 4, done: false } +> console.log(generator.next()); // { value: 1, done: false } +> console.log(generator.next()); // { value: 2, done: false } +> console.log(generator.next()); // { value: 3, done: false } +> console.log(generator.next()); // { value: 4, done: false } ``` 就像上面的例子,当[next](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next)运行时,它会把我们的generator向前“推动”,同时执行新的表达式。 From 052c7d0aa1fc037d7aff09bd15834d17c7e399ef Mon Sep 17 00:00:00 2001 From: Jorge Yau Date: Sat, 24 Sep 2016 21:09:19 -0400 Subject: [PATCH 77/84] Fix syntax error with es6 {} blocks --- README.md | 42 +++++++++++++++++++++--------------------- README_ko.md | 2 +- README_zhCn.md | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index c6c2ba6..c5821b7 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Using ES6 Blocks: ```javascript { let food = 'Meow Mix'; -} +}; console.log(food); // Reference Error ``` @@ -425,7 +425,7 @@ let api = { export default api; -/* Which is the same as +/* Which is the same as * export { api as default }; */ ``` @@ -725,7 +725,7 @@ React.Component.prototype[refreshComponent] = () => { ### Symbol.for(key) `Symbol.for(key)` will create a Symbol that is still immutable and unique, but can be looked up globally. -Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for +Two identical calls to `Symbol.for(key)` will return the same Symbol instance. NOTE: This is not true for `Symbol(description)`: ```javascript @@ -734,8 +734,8 @@ Symbol.for('foo') === Symbol('foo') // false Symbol.for('foo') === Symbol.for('foo') // true ``` -A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be -achieved by having your code look for a Symbol member on object arguments from third parties that contain some +A common use case for Symbols, and in particular with `Symbol.for(key)` is for interoperability. This can be +achieved by having your code look for a Symbol member on object arguments from third parties that contain some known interface. For example: ```javascript @@ -764,7 +764,7 @@ class SomeReadableType { ``` > A notable example of Symbol use for interoperability is `Symbol.iterator` which exists on all iterable -types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator +types in ES6: Arrays, strings, generators, etc. When called as a method it returns an object with an Iterator interface. [(back to table of contents)](#table-of-contents) @@ -894,7 +894,7 @@ let value = map.get(el); // 'reference' el.parentNode.removeChild(el); el = null; -// map is empty, since the element is destroyed +// map is empty, since the element is destroyed ``` As shown above, once the object is destroyed by the garbage collector, @@ -1005,9 +1005,9 @@ Promise.all(promises) ## Generators -Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid +Similar to how [Promises](https://github.com/DrkSephy/es6-cheatsheet#promises) allow us to avoid [callback hell](http://callbackhell.com/), Generators allow us to flatten our code - giving our -asynchronous code a synchronous feel. Generators are essentially functions which we can +asynchronous code a synchronous feel. Generators are essentially functions which we can [pause their execution](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield) and subsequently return the value of an expression. @@ -1054,9 +1054,9 @@ function* getData() { ``` By the power of `yield`, we are guaranteed that `entry1` will have the data needed to be parsed and stored -in `data1`. +in `data1`. -While generators allow us to write asynchronous code in a synchronous manner, there is no clear +While generators allow us to write asynchronous code in a synchronous manner, there is no clear and easy path for error propagation. As such, as we can augment our generator with Promises: ```javascript @@ -1077,12 +1077,12 @@ function iterateGenerator(gen) { var ret = generator.next(); if(!ret.done) { ret.value.then(iterate); - } - })(); + } + })(); } ``` -By augmenting our Generator with Promises, we have a clear way of propagating errors through the use of our +By augmenting our Generator with Promises, we have a clear way of propagating errors through the use of our Promise `.catch` and `reject`. To use our newly augmented Generator, it is as simple as before: ```javascript @@ -1103,12 +1103,12 @@ errors in a nice way, we can actually begin to utilize a simpler construction th ## Async Await -While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished +While this is actually an upcoming ES2016 feature, `async await` allows us to perform the same thing we accomplished using Generators and Promises with less effort: ```javascript var request = require('request'); - + function getJSON(url) { return new Promise(function(resolve, reject) { request(url, function(error, response, body) { @@ -1116,12 +1116,12 @@ function getJSON(url) { }); }); } - + async function main() { var data = await getJSON(); console.log(data); // NOT undefined! } - + main(); ``` @@ -1149,7 +1149,7 @@ class Employee { } set name(newName) { - if (newName == this._name) { + if (newName == this._name) { console.log('I already have this name.'); } else if (newName) { this._name = newName; @@ -1162,12 +1162,12 @@ class Employee { var emp = new Employee("James Bond"); // uses the get method in the background -if (emp.name) { +if (emp.name) { console.log(emp.name); // Mr. JAMES BOND } // uses the setter in the background -emp.name = "Bond 007"; +emp.name = "Bond 007"; console.log(emp.name); // Mr. BOND 007 ``` diff --git a/README_ko.md b/README_ko.md index 4f5a83a..9d44521 100644 --- a/README_ko.md +++ b/README_ko.md @@ -88,7 +88,7 @@ ES6 블록을 사용하는 경우, ```javascript { let food = '허니버터칩'; -} +}; console.log(food); // Reference Error ``` diff --git a/README_zhCn.md b/README_zhCn.md index 52897d5..66e3c8f 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -89,7 +89,7 @@ console.log(food); // Reference Error ```javascript { let food = 'Meow Mix'; -} +}; console.log(food); // Reference Error ``` From 6af1e6ef38a1b1bfe3a7f918c910bc19b7a75eba Mon Sep 17 00:00:00 2001 From: Sai628 Date: Fri, 16 Dec 2016 17:23:40 +0800 Subject: [PATCH 78/84] Fixed wrong Chinese char --- README_zhCn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zhCn.md b/README_zhCn.md index 66e3c8f..5ab1666 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -410,7 +410,7 @@ export default api; > **最佳实践**:总是在模块的 **最后** 使用 `export default` 方法。 它让模块的出口更清晰明了,节省了阅读整个模块来寻找出口的时间。 更多的是,在大量CommonJS模块中,通用的习惯是设置一个出口值或者出口对象。 -最受这个规则,可以让我们的代码更易读,且更方便的联合使用CommonJS和ES6模块。 +坚持这个规则,可以让我们的代码更易读,且更方便的联合使用CommonJS和ES6模块。 ### Importing in ES6 From e8e9d8f6e8c28575cb33b907b91777e1cae45638 Mon Sep 17 00:00:00 2001 From: Sai628 Date: Fri, 16 Dec 2016 17:38:21 +0800 Subject: [PATCH 79/84] Add missing code comment --- README_zhCn.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README_zhCn.md b/README_zhCn.md index 5ab1666..89216c4 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -405,6 +405,11 @@ let api = { }; export default api; + +/* + * 与以下的语句是对等的: + * export { api as default }; + */ ``` > **最佳实践**:总是在模块的 **最后** 使用 `export default` 方法。 From a64f10895389dfc7d429b9b0928503d0ccb28559 Mon Sep 17 00:00:00 2001 From: Sai628 Date: Wed, 21 Dec 2016 14:50:02 +0800 Subject: [PATCH 80/84] optimize Chinese expression --- README_zhCn.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 89216c4..685039a 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -658,13 +658,13 @@ class Personal extends Person { ## Symbols -符号(Symbols)在ES6版本之前就已经存在了,但现在我们拥有一个公共的接口来直接使用它们。 -Symbols对象是一旦创建就不可以被更改的(immutable)而且能被用做hash数据类型中的键。 +Symbols在ES6版本之前就已经存在了,但现在我们拥有一个公共的接口来直接使用它们。 +Symbols是不可更改的(immutable)并且唯一的(unique),它可用作任何hash数据类型中的键。 ### Symbol( ) -调用 `Symbol()` 或者 `Symbol(描述文本)` 会创建一个唯一的、在全局中不可以访问的符号对象。 +调用 `Symbol()` 或者 `Symbol(描述文本)` 会创建一个唯一的、在全局中不可以访问的Symbol对象。 一个 `Symbol()` 的应用场景是:在自己的项目中使用第三方代码库,且你需要给他们的对象或者命名空间打补丁代码,又不想改动或升级第三方原有代码的时候。 -举个例子,如果你想给 `React.Component` 这个类添加一个 `refreshComponent` 方法,但又确定不了这个方法会不会在下个版本中加入,你可以这么做: +例如,如果你想给 `React.Component` 这个类添加一个 `refreshComponent` 方法,但又确定不了这个方法会不会在下个版本中加入,你可以这么做: ```javascript const refreshComponent = Symbol(); @@ -677,7 +677,7 @@ React.Component.prototype[refreshComponent] = () => { ### Symbol.for(key) 使用 `Symbol.for(key)` 也是会创建一个不可改变的Symbol对象,但区别于上面的创建方法,这个对象是在全局中可以被访问到的。 -调用两次 `Symbol.for(key)` 会返回相同的Symbol实例。 +两次相同的 `Symbol.for(key)` 调用会返回相同的Symbol实例。 **提示**:这并不同于 `Symbol(description)`。 @@ -687,9 +687,9 @@ Symbol.for('foo') === Symbol('foo') // false Symbol.for('foo') === Symbol.for('foo') // true ``` -一个Symbols常用的使用场景,是需要使用特别 `Symbol.for(key)` 方法来实现代码间的协作。 -这能让你在你的代码中,查找包含已知的接口的第三方代码中Symbol成员。(译者:这句话好难翻。。。原文:This can be -achieved by having your code look for a Symbol member on object arguments from third parties that contain some known interface. )举个例子: +Symbols常用的一个使用场景,尤其是使用 `Symbol.for(key)` 方法,是用于实现代码间的互操作。 +在你的代码中,通过在包含一些已知接口的第三方库的对象参数中查找Symbol成员,你可以实现这种互操作。 +例如: ```javascript function reader(obj) { @@ -716,13 +716,14 @@ class SomeReadableType { } ``` -> **注意**:`Symbol.iterable` 在ES6中像其他可枚举的对象,如数组,字符串,generators一样,当这个方法被调用时会激活一个枚举器并返回一个对象。 +> **注意**:关于Symbol互操作的使用,一个值得一提的例子是`Symbol.iterable` 。`Symbol.iterable`存在ES6的所有可枚举对象中:数组(Arrays)、 +> 字符串(strings)、生成器(Generators)等等。当它作为一个方法被调用时,它将会返回一个带有枚举接口的对象。 [(回到目录)](#table-of-contents) ## Maps -**Maps** 是一个Javascript中很重要(迫切需要)的数据结构。 +**Maps** 是一个JavaScript中很重要(迫切需要)的数据结构。 在ES6之前,我们创建一个 **hash** 通常是使用一个对象: ```javascript From 7c54dd64a7b2d3adf384a29a3d4f6f371890ce1e Mon Sep 17 00:00:00 2001 From: Sai628 Date: Tue, 27 Dec 2016 14:23:04 +0800 Subject: [PATCH 81/84] Optimize Chinese expression & Update example code --- README_zhCn.md | 67 +++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/README_zhCn.md b/README_zhCn.md index 685039a..4726231 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -822,7 +822,7 @@ class Person { > Reflect.ownKeys(person); // [] ``` -一个使用WeakMaps存储数据更实际的例子,就是有关于一个DOM元素和对该DOM元素(有污染)地操作: +一个使用WeakMaps存储数据更实际的例子,是存储与DOM元素相关联的数据,而这不会对DOM元素本身产生污染: ```javascript let map = new WeakMap(); @@ -841,16 +841,16 @@ el = null; value = map.get(el); // undefined ``` -上面的例子中,一个对象被垃圾回收期给销毁了,WeakMaps会自动的把自己内部所对应的键值对数据同时销毁。 +上面的例子中,一旦对象被垃圾回收器给销毁了,WeakMaps会自动的把这个对象所对应的键值对数据同时销毁。 -> **提示**:结合这个例子,再考虑下jQuery是如何实现缓存带有引用的DOM元素这个功能的,使用了WeakMaps的话,当被缓存的DOM元素被移除的时,jQuery可以自动释放相应元素的内存。 -通常情况下,在涉及DOM元素存储和缓存的情况下,使用WeakMaps是非常适合的。 +> **提示**:结合这个例子,再考虑下jQuery是如何实现缓存带有引用的DOM元素这个功能的。使用WeakMaps的话,当被缓存的DOM元素被移除的时,jQuery可以自动释放相应元素的内存。 +通常情况下,在涉及DOM元素存储和缓存的情况下,使用WeakMaps是非常有效的。 [(回到目录)](#table-of-contents) ## Promises -Promises让我们让我们多缩进难看的代码(回调地狱): +Promises让我们把多缩进难看的代码(回调地狱): ```javascript func1(function (value1) { @@ -889,40 +889,51 @@ new Promise((resolve, reject) => 这里有两个处理函数,**resolve**(当Promise执行成功完毕时调用的回调函数) 和 **reject** (当Promise执行不接受时调用的回调函数) -> **Promises的好处**:大量嵌套错误回调函数会使代码变得难以阅读理解。 -使用了Promises,我们可以让我们代码变得更易读,组织起来更合理。 -此外,Promise处理后的值,无论是解决还是拒绝的结果值,都是不可改变的。 +> **Promises的好处**:大量嵌套错误处理回调函数会使代码变得难以阅读理解。 +使用Promises,我们可以通过清晰的路径将错误事件让上传递,并且适当地处理它们。 +此外,Promise处理后的值,无论是解决(resolved)还是拒绝(rejected)的结果值,都是不可改变的。 下面是一些使用Promises的实际例子: ```javascript -var fetchJSON = function(url) { - return new Promise((resolve, reject) => { - $.getJSON(url) - .done((json) => resolve(json)) - .fail((xhr, status, err) => reject(status + err.message)); - }); -}; +var request = require('request'); + +return new Promise((resolve, reject) => { + request.get(url, (error, response, body) => { + if (body) { + resolve(JSON.parse(body)); + } else { + resolve({}); + } + }); +}); ``` -我们还可以使用 `Promise.all()` 来异步的 **并行** 处理一个数组的数据。 +我们还可以使用 `Promise.all()` 来 **并行化** 的处理一组异步的操作。 ```javascript -var urls = [ - 'http://www.api.com/items/1234', - 'http://www.api.com/items/4567' +let urls = [ + '/api/commits', + '/api/issues/opened', + '/api/issues/assigned', + '/api/issues/completed', + '/api/issues/comments', + '/api/pullrequests' ]; -var urlPromises = urls.map(fetchJSON); +let promises = urls.map((url) => { + return new Promise((resolve, reject) => { + $.ajax({ url: url }) + .done((data) => { + resolve(data); + }); + }); +}); -Promise.all(urlPromises) - .then(function (results) { - results.forEach(function (data) { - }); - }) - .catch(function (err) { - console.log('Failed: ', err); - }); +Promise.all(promises) + .then((results) => { + // Do something with results of all our promises + }); ``` [(回到目录)](#table-of-contents) From c7f5e40efe77a63c68321edce2fc3fe701083c67 Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Fri, 17 Feb 2017 22:41:30 -0500 Subject: [PATCH 82/84] Resolving #87 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5821b7..f7a8df9 100644 --- a/README.md +++ b/README.md @@ -1131,7 +1131,7 @@ for getting up and running with ES7 and Babel can be found [here](http://masnun. [(back to table of contents)](#table-of-contents) ## Getter and setter functions -ES6 has started supporting getter and setter functions. Using the following example: +ES6 has started supporting getter and setter functions within classes. Using the following example: ```javascript class Employee { From d5608804ac8cd2909c88f0dbad83169ff6bf59cf Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Thu, 8 Feb 2018 17:37:15 -0500 Subject: [PATCH 83/84] Adding License --- README.md | 27 +++++++++++++++++++++++++++ README_ko.md | 27 +++++++++++++++++++++++++++ README_zhCn.md | 27 +++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/README.md b/README.md index f7a8df9..f921963 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ snippet examples for your day to day workflow. Contributions are welcome! - [Generators](#generators) - [Async Await](#async-await) - [Getter/Setter functions](#getter-and-setter-functions) +- [License](#License) ## var versus let / const @@ -1194,3 +1195,29 @@ person.fullName = 'Bond 007'; person.fullName; // Bond 007 ``` [(back to table of contents)](#table-of-contents) + +## License + +The MIT License (MIT) + +Copyright (c) 2015 David Leonard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +[(back to table of contents)](#table-of-contents) \ No newline at end of file diff --git a/README_ko.md b/README_ko.md index 9d44521..3c9b279 100644 --- a/README_ko.md +++ b/README_ko.md @@ -20,6 +20,7 @@ ES2015(ES6)의 Tip & Tricks, 좋은 활용사례들과 코드 예제들이 포 - [제너레이터(Generator)](#제너레이터generator) - [Async Await](#async-await) - [Getter/Setter 함수](#getter와-setter-함수) +- [License](#License) ## var VS let / const @@ -1098,3 +1099,29 @@ person.fullName = 'EXID 솔지'; person.fullName; // EXID 솔지 ``` [(목차로 돌아가기)](#목차) + +## License + +The MIT License (MIT) + +Copyright (c) 2015 David Leonard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +[(목차로 돌아가기)](#목차) \ No newline at end of file diff --git a/README_zhCn.md b/README_zhCn.md index 4726231..e976a1c 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -19,6 +19,7 @@ - [Promises](#promises) - [Generators](#generators) - [Async Await](#async-await) +- [License](#License) ## var versus let / const @@ -1056,3 +1057,29 @@ main(); [这里](http://masnun.com/2015/11/11/using-es7-asyncawait-today-with-babel.html)是个很好的学习资源,让我们学习和使用这项ES7中的新功能。 [(回到目录)](#table-of-contents) + +## License + +The MIT License (MIT) + +Copyright (c) 2015 David Leonard + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +[(回到目录)](#table-of-contents) \ No newline at end of file From a03267ceaf4e445aeca078b924ba92d6456d6b6b Mon Sep 17 00:00:00 2001 From: DrkSephy Date: Thu, 8 Feb 2018 17:38:54 -0500 Subject: [PATCH 84/84] Fixing internal license anchor --- README.md | 2 +- README_ko.md | 2 +- README_zhCn.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f921963..2e21ef2 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ snippet examples for your day to day workflow. Contributions are welcome! - [Generators](#generators) - [Async Await](#async-await) - [Getter/Setter functions](#getter-and-setter-functions) -- [License](#License) +- [License](#license) ## var versus let / const diff --git a/README_ko.md b/README_ko.md index 3c9b279..e4aa2c2 100644 --- a/README_ko.md +++ b/README_ko.md @@ -20,7 +20,7 @@ ES2015(ES6)의 Tip & Tricks, 좋은 활용사례들과 코드 예제들이 포 - [제너레이터(Generator)](#제너레이터generator) - [Async Await](#async-await) - [Getter/Setter 함수](#getter와-setter-함수) -- [License](#License) +- [License](#license) ## var VS let / const diff --git a/README_zhCn.md b/README_zhCn.md index e976a1c..e37daad 100644 --- a/README_zhCn.md +++ b/README_zhCn.md @@ -19,7 +19,7 @@ - [Promises](#promises) - [Generators](#generators) - [Async Await](#async-await) -- [License](#License) +- [License](#license) ## var versus let / const