├── .jshintrc
├── LICENSE
├── README.md
├── S02-forEach
├── forEach.js
├── forEach.md
└── index.html
├── S03-map
├── index.html
├── map.js
└── map.md
├── S04-filter
├── filter.js
├── filter.md
└── index.html
├── S05-find
├── find.js
├── find.md
└── index.html
├── S06-every_sum
├── every_some.js
├── every_some.md
└── index.html
├── S07-reduce
├── index.html
├── reduce.js
└── reduce.md
├── S08-const_let
├── const_let.js
├── const_let.md
└── index.html
├── S09-template_strings
├── index.html
├── template-strings.js
└── template-strings.md
├── S10-arrow_functions
├── arrow_functions.js
├── arrow_functions.md
└── index.html
├── S11-enhanced_object_literals
├── enhanced_object_literals.js
├── enhanced_object_literals.md
└── index.html
├── S12-default_arguments
├── default_arguments.js
├── default_arguments.md
└── index.html
├── S13-rest_and_spread
├── index.html
├── rest_and_spread.js
└── rest_and_spread.md
├── S14-destructuring
├── destructuring.js
├── destructuring.md
└── index.html
├── S15-classes
├── classes.js
├── classes.md
└── index.html
├── S16-generators
├── generators.js
├── generators.md
└── index.html
└── S17-promises_and_fetch
├── index.html
├── promises_and_fetch.js
└── promises_and_fetch.md
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6
3 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Will Batey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #[ES6 Javascript: The Complete Developer's Guide by Stephen Grider](https://www.udemy.com/javascript-es6-tutorial/)
2 |
3 | This repo tracks my progress through this great course by Stephen Grider.
4 |
5 | Comments are in the markdown files in each section directory and also generously sprinkled into each file. :)
6 |
--------------------------------------------------------------------------------
/S02-forEach/forEach.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.forEach();
2 |
3 | // The forEach() method executes a provided function once per array element.
4 |
5 | // We declare the variable colours and assign it to an array literal with our colour names as strings.
6 | var colors = ['red', 'blue', 'green'];
7 |
8 | // The reason we want to avoid writing for loops like the one below is that there is a lot of
9 | // unnecessary logic involved which provides more points of failue (typos, etc.) than if we just
10 | // used a much simpler solution, like a built in helper method.
11 | for (var i = 0; i < colors.length; i++) {
12 | console.log(colors[i]);
13 | }
14 |
15 |
16 | // We invoke the .forEach array helper method that is built into the array object in javascript
17 | // and pass in an annonymous function that logs each item of the array to console.
18 |
19 | // Our annonymous function can be referred to as an 'interator function' as it is invoked
20 | // in every iteration of our loop.
21 |
22 | colors.forEach(function(color) {
23 | console.log(color);
24 | });
25 |
26 | // Stephen argues that one of the key reasons to use a helper method over a generic for loop is that
27 | // we can achieve the same result while writing much less logic.
28 |
29 |
30 | // ----------------------------------------------------------
31 |
32 | // forEach continued.
33 |
34 | // Tasks:
35 |
36 | // --> Create an array of numbers
37 | var numbers = [1, 2, 3, 4, 5];
38 |
39 | // --> Create a variable to hold the sum
40 | var sum = 0;
41 |
42 | // --> Loop over the array, incrementing the sum variable
43 |
44 | // An alternative here is to define the function seperately and then pass the function into .forEach().
45 | // If we did use a seperate function, we would not pass it with parens, which would invoke it and pass the result,
46 | // as what we want is for the function to invoked seperately for each iteration in our array.
47 |
48 | numbers.forEach(function(number, index){ // the first paramater of forEach is the callback function to execute
49 | console.log(index); // for each element of the array, which takes three arguments:
50 | sum += number;
51 | }); // currentValue : The current element being processed in the array
52 | // index: The index of the current element being processed in the array
53 | // --> Print the sum variable // array: The array that forEach() is being applied to.
54 | console.log(sum);
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/S02-forEach/forEach.md:
--------------------------------------------------------------------------------
1 | # forEach Array Helper Method
2 |
3 | - The forEach array helper method takes an array and calls a function that we provide on each item in the array.
4 |
5 | - Array helper methods are built in to the array object in Javascript. In the past, these helper methods have been implemented by utlity libraries such as lodash.js and underscore.js.
6 |
7 | - Array helper methods allow us to stop using manual for loops when dealing with collections of data in arrays.
8 |
9 | - One of Stephen's biggest jumps as a programmer in general was when he really mastered each of the helper methods discussed in this section. By getting to know these methods well, you will be better equipped to work with collections of data, which is a big part of developing modern web applications today.
10 |
--------------------------------------------------------------------------------
/S02-forEach/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S03-map/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S03-map/map.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.map();
2 |
3 | // The map() method creates a new array with the results of
4 | // calling a provided function on every element in this array.
5 |
6 | (function() {
7 |
8 | var numbers = [1,2,3];
9 |
10 | // In large javascript applications, we want to avoid mutating (changing) data as much as possible.
11 |
12 | // It is common practise to output data to a new array rather than changing the original version,
13 | // as this can lead to bugs down the road.
14 |
15 | var doubledNumbers = [];
16 |
17 | // This is how we might implement the map array helper using a for loop.
18 |
19 | for (var i = 0; i < numbers.length ; i++) {
20 | doubledNumbers.push(numbers[i] * 2);
21 | }
22 |
23 |
24 | var doubled = numbers.map(function(number) {
25 |
26 | // It is critical to use the return keyword inside a mapping function,
27 | // otherwise the resulting array would be [undefined, undefined, undefined]
28 |
29 | return number * 2;
30 |
31 | });
32 |
33 |
34 | console.log(doubledNumbers);
35 | console.log(doubled);
36 |
37 | // ---------------------------------------------------
38 |
39 | // Continued....
40 |
41 | var cars = [
42 | { model: 'Buick', price: 'CHEAP' },
43 | { model: 'Camaro', price: 'expensive' }
44 | ];
45 |
46 |
47 | // This operation is frequently referred to as a 'pluck', as it is plucking
48 | // a particular property off of each item in the array.
49 |
50 | // This is quite common in client side rendering frameworks like Angular and React.
51 |
52 | var prices = cars.map(function(car) {
53 | return car.price;
54 | });
55 |
56 | console.log(prices); // ["CHEAP", "expensive"]
57 |
58 | })();
59 |
60 | // Coding challenging below...
61 |
62 | // ----------------------------------
63 |
64 |
65 | (function() {
66 |
67 | // This is a hard one!
68 |
69 | // Implement a 'pluck' function.
70 |
71 | // Pluck should accept an array and a string representing
72 | // a property name and return an array containing that property from each object.
73 |
74 |
75 | // My solution below...
76 |
77 |
78 | function pluck(array, property) {
79 | var newArr = array.map(function(item) {
80 |
81 | return item[property];
82 |
83 | });
84 |
85 | return newArr;
86 | }
87 |
88 | var paints = [
89 | { color: 'red' },
90 | { color: 'blue' },
91 | { color: 'yellow' }
92 | ];
93 |
94 |
95 | console.log(pluck(paints, 'color')); // ['red', blue', 'yellow']
96 |
97 | })();
98 |
--------------------------------------------------------------------------------
/S03-map/map.md:
--------------------------------------------------------------------------------
1 | # .map Array Helper
2 |
3 | - The map array helper method creates a new array with the results of calling a provided function on
4 | every element in the current array.
--------------------------------------------------------------------------------
/S04-filter/filter.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.filter();
2 |
3 | // This is a very useful method which lets us add array items to a new array based on whether they
4 | // pass the test we use in the function we provide.
5 |
6 | ;(function() {
7 |
8 |
9 | var products = [
10 |
11 | { name : 'cucumber', type: 'vegetable' },
12 | { name : 'banana', type: 'fruit' },
13 | { name: 'celery', type: 'vegetable' },
14 | { name: 'orange', type: 'fruit' }
15 |
16 | ];
17 |
18 | // Again, we do not want to mutate data, but create a subset. This is why we create a new array.
19 |
20 | var productsFiltered = [];
21 |
22 |
23 | // Below is an example of how we might implemenet the filter method with a for loop.
24 |
25 | // Again, this is not recommended as it adds an unnecessary layer of logic to what would otherwise
26 | // be a simple solution. It is also harder to read and figure out what is going on.
27 |
28 | for (var i = 0; i < products.length; i++) {
29 | if (products[i].type === 'fruit') {
30 | productsFiltered.push(products[i]);
31 | }
32 | }
33 |
34 | console.log(products);
35 | console.log(productsFiltered);
36 |
37 |
38 | // Below is the way we would do this with .filter();
39 |
40 | var filteredProducts2 = products.filter(function(product) {
41 |
42 | return product.type === 'fruit';
43 |
44 | });
45 |
46 | console.log(filteredProducts2);
47 |
48 | })();
49 |
50 |
51 | // ----------------------------------------------------
52 |
53 | // Below is our more complicated example...
54 |
55 | (function() {
56 |
57 | var products2 = [
58 |
59 | { name : 'cucumber', type: 'vegetable' , quantity: 0, price: 1},
60 | { name : 'banana', type: 'fruit', quantity: 10, price: 15 },
61 | { name: 'celery', type: 'vegetable', quantity: 30, price: 9 },
62 | { name: 'orange', type: 'fruit', quantity: 3, price: 5 }
63 |
64 | ];
65 |
66 | // Type is 'vegtable', quantity is greater than 0 & price less than 10
67 |
68 | var products2Filtered = products2.filter(function(product) {
69 | return product.type === 'vegetable' &&
70 | product.quantity > 0 &&
71 | product.price < 10;
72 | });
73 |
74 | console.log(products2Filtered);
75 |
76 | })();
77 |
78 | // And below is our second more complicated example.....
79 |
80 | // For a post with a given id, we want to filter our comments and return those with a matching postId.
81 |
82 | // This is a plausible real world example of using filter, e.g. on a social networking site.
83 |
84 | (function() {
85 |
86 | // Create our post object
87 |
88 | var post = { id: 4, title: 'New Post' };
89 |
90 | // Create our comments array, which contain our comment objects
91 |
92 | var comments = [
93 |
94 | { postId: 4, content: 'awesome post' },
95 | { postId: 3, content: 'it was ok' },
96 | { postId: 4, content: 'neat' }
97 |
98 | ];
99 |
100 | // Declare our function, which take a post and comments parameter.
101 |
102 | function commentsForPost(post, comments) {
103 |
104 | // Returns the resulting array from running the .filter method on our comments array
105 |
106 | return comments.filter(function(comment) {
107 |
108 | // For every item in our comments array, only return those with a postId value
109 | // that matches the id value of our post object
110 |
111 | return comment.postId === post.id;
112 | });
113 | }
114 |
115 | // Log the result of our commentsForPost function, passing in our example post object and comments array above.
116 |
117 | console.log(commentsForPost(post, comments));
118 |
119 | })();
120 |
121 |
122 | // ------- Coding Challenge:
123 |
124 | // Challenging! Implementing 'reject'.
125 |
126 | // This is a hard one! Create a function called 'reject'.
127 | // Reject should work in the opposite way of 'filter' - if a function returns 'true', the item
128 | // should *not* be included in the new array. Hint: you can reuse filter.
129 |
130 |
131 | (function() {
132 |
133 | function reject(array, iteratorFunction) {
134 |
135 | return array.filter(function(item) {
136 |
137 | // This is the best solution. Simply only return those items that
138 | // return 'false' from our iteratorFunction.
139 |
140 | return !iteratorFunction(item);
141 | });
142 | }
143 |
144 | // My original working solution is below, which uses two new arrays...
145 |
146 |
147 | // function reject(array, iteratorFunction) {
148 |
149 | // var failedTest = array.filter(function(item) {
150 | // return iteratorFunction(item);
151 | // });
152 |
153 | // var passedTest = [];
154 |
155 | // array.filter(function(item) {
156 | // failedTest.includes(item) ? false : passedTest.push(item);
157 | // });
158 |
159 | // return passedTest;
160 | // }
161 |
162 |
163 | var numbers = [10, 20, 30];
164 |
165 | var lessThanFifteen = reject(numbers, function(number) {
166 | return number > 15;
167 | });
168 |
169 | console.log(lessThanFifteen); // [10]
170 |
171 | })();
--------------------------------------------------------------------------------
/S04-filter/filter.md:
--------------------------------------------------------------------------------
1 | # .filter Array Helper Method
2 |
3 | - The filter() method creates a new array with all elements that pass the test implemented by the provided function.
--------------------------------------------------------------------------------
/S04-filter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S05-find/find.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.find()
2 |
3 | // The find() method returns a value of the first element in the array that satisfies
4 | // the provided testing function. Otherwise undefined is returned.
5 |
6 | (function() {
7 |
8 | var users = [
9 |
10 | { name: 'Jill' },
11 | { name: 'Alex' },
12 | { name: 'Bill' }
13 |
14 | ];
15 |
16 |
17 | var user;
18 |
19 | // This is a generic for loop implementation of the find method.
20 |
21 | // If we did not include the break statement, beware that this loop
22 | // would continue iterating over the entire array, even after it had found the
23 | // object we were looking for.
24 |
25 | for (var i = 0; i < users.length; i++) {
26 | if (users[i].name === 'Alex') {
27 | user=users[i];
28 | break;
29 | }
30 | }
31 |
32 | console.log(user);
33 |
34 | // This is how we would use the .find method on the array instead.
35 |
36 | // Be aware that this method returns only the first result it finds.
37 |
38 | var user2 = users.find(function(user) {
39 | return user.name === "Alex";
40 | });
41 |
42 | console.log(user2);
43 |
44 | })();
45 |
46 |
47 | // More complicated example of using the find method below.......
48 |
49 | // ---------------------------------
50 |
51 | (function() {
52 |
53 | function Car(model) {
54 | this.model = model;
55 | }
56 |
57 | var cars = [
58 | new Car('Buick'),
59 | new Car('Camaro'),
60 | new Car('Focus')
61 | ];
62 |
63 | console.log(cars);
64 |
65 | var foundCar = cars.find(function(car) {
66 | return car.model === 'Focus';
67 | });
68 |
69 | console.log(foundCar);
70 |
71 | })();
72 |
73 | // Another more complicated example using our comment / post idea from previous lesson.....
74 |
75 | // ------------------------------------------------------------------
76 |
77 | (function() {
78 |
79 | var posts = [
80 | { id: 1, title: 'New Post' },
81 | { id: 2, title: 'Old Post' }
82 | ];
83 |
84 | var comment = { postId: 1, content: 'Great Post' };
85 |
86 | function postForComment(posts, comment) {
87 | return posts.find(function(post) {
88 | return post.id === comment.postId;
89 | });
90 | }
91 |
92 | console.log(postForComment(posts, comment));
93 |
94 | })();
95 |
96 | // Coding exercise 1 - Finding Admin Users
97 |
98 | // Find the user in the user's array who is an admin. Assign this user to the variable 'admin'.
99 |
100 | (function() {
101 |
102 | var users = [
103 | { id: 1, admin: false },
104 | { id: 2, admin: false },
105 | { id: 3, admin: true }
106 | ];
107 |
108 | var admin = users.find(function(user) {
109 | return user.admin === true;
110 | });
111 |
112 | console.log(admin);
113 |
114 | })();
115 |
116 |
117 | // Coding exercise 2 - What's your balance?
118 |
119 | // Find the account with a balance of 12 and assign it to the variable 'account'.
120 |
121 | (function() {
122 |
123 | var accounts = [
124 | { balance: -10 },
125 | { balance: 12 },
126 | { balance: 0 }
127 | ];
128 |
129 | var account = accounts.find(function(account) {
130 |
131 | return account.balance === 12;
132 |
133 | });
134 |
135 | console.log(account);
136 |
137 | })();
138 |
139 |
140 | // Really Challenging: Custom findWhere Helper
141 |
142 | // This is a tough one. The most common find operatio nis to an object that has a given property.
143 |
144 | // Rather than writing out a full function every time,
145 | // it would be great if we had a shorthand syntax to find an object like this:
146 |
147 | // findWhere(ladder, { height: '20 feet' });
148 |
149 | // Your goal:
150 |
151 | // -> Write a findWhere function that achieves this shorthand approach.
152 | // -> findWhere() should return the found object.
153 |
154 | (function() {
155 |
156 | var ladders = [
157 |
158 | { id: 1, height: 20 },
159 | { id: 3, height: 25 }
160 |
161 | ];
162 |
163 | function findWhere(array, objCriteria) {
164 |
165 | // Accepts an array and object with criteria, e.g. findWhere(ladders, { height: 25 });
166 |
167 | // Takes height from objCriteria and searches ladders for property
168 |
169 | // If found, compares the property's value to check if equal to the one we passed in
170 |
171 | // If equal, we return the object.
172 |
173 |
174 | var property = Object.keys(objCriteria)[0];
175 |
176 | console.log(property);
177 |
178 | var result = ladders.find(function(element) {
179 | return element[property] === objCriteria[property];
180 | });
181 |
182 | return result;
183 | }
184 |
185 | console.log(findWhere(ladders, { height: 25 } ));
186 | console.log(findWhere(ladders, { height: 20 } ));
187 |
188 | })();
189 |
--------------------------------------------------------------------------------
/S05-find/find.md:
--------------------------------------------------------------------------------
1 | # .find Array Helper Method
2 |
3 | - The find() method returns a value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
--------------------------------------------------------------------------------
/S05-find/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S06-every_sum/every_some.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.every()
2 | // Array.prototype.some()
3 |
4 | // The every() method tests whether all elements in the array pass the test implemented by the provided function.
5 |
6 | // The some() method tests whether some element in the array passes the test implemented by the provided function.
7 |
8 | (function() {
9 |
10 | var computers = [
11 |
12 | { name: 'Apple', ram: 24 },
13 | { name: 'Compaq', ram: 4 },
14 | { name: 'Acer', ram: 32 }
15 |
16 | ];
17 |
18 | // First we start with a generic for loop implementation, to show
19 | // how tedious it can be to try and do it this way.
20 |
21 | // For loops are very flexible, but again, they cna be hard to read.
22 |
23 | var allComputersCanRunProgram = true;
24 | var onlySomeComputersCanRunProgram = false;
25 |
26 | for (var i =0; i < computers.length; i++) {
27 | var computer = computers[i];
28 |
29 | if (computer.ram < 16) {
30 | allComputersCanRunProgram = false;
31 | } else {
32 | onlySomeComputersCanRunProgram = true;
33 | }
34 | }
35 |
36 | console.log(allComputersCanRunProgram);
37 | console.log(onlySomeComputersCanRunProgram);
38 |
39 | console.log("--------------- 1 ");
40 |
41 | // Below is how we use the .every method to achieve the same result as above.
42 |
43 | var allComputers2 = computers.every(function(computer) {
44 | return computer.ram > 16;
45 | });
46 |
47 | console.log(allComputers2);
48 |
49 | // And we also use the .some method to achieve the same result.
50 |
51 | var someComputers2 = computers.some(function(computer) {
52 | return computer.ram > 16;
53 | });
54 |
55 | console.log(someComputers2);
56 |
57 | console.log("--------------- 2 ");
58 |
59 | })();
60 |
61 | // Below is another simple example of how we might use the .every and .some array helper methods.
62 |
63 | (function() {
64 |
65 | var names = [
66 |
67 | "Alexandra",
68 | "Matthew",
69 | "Joe"
70 |
71 | ];
72 |
73 | var everyName = names.every(function(name) {
74 | return name.length > 4;
75 | });
76 |
77 | console.log(everyName);
78 |
79 | var someName = names.some(function(name) {
80 | return name.length > 4;
81 | });
82 |
83 | console.log(someName);
84 |
85 | console.log("--------------- 3 ");
86 |
87 | })();
88 |
89 | // -------------------------------------------------------------
90 |
91 | // Another example of when we might use .every / .sum.
92 |
93 | // In this case, we are validating a user's input on a login form to check that something has been entered.
94 |
95 | (function() {
96 |
97 | function Field(value) {
98 | var self = this;
99 | self.value = value;
100 | }
101 |
102 | // We create a method called validate and attach it to
103 | // the prototype of our Field objects.
104 |
105 | // This prototype is inherited by all Field objects created using the new keyword.
106 |
107 | Field.prototype.validate = function() {
108 |
109 | return this.value.length > 0;
110 |
111 | };
112 |
113 | var username = new Field("2cool");
114 | var password = new Field("my_password");
115 | var birthdate = new Field("10/10/2010");
116 |
117 | console.log(username.validate());
118 |
119 | var fields = [username, password, birthdate];
120 |
121 | console.log(fields);
122 |
123 | var formIsValid = fields.every(function(field) {
124 | return field.validate();
125 | });
126 |
127 | console.log(formIsValid);
128 |
129 | if (formIsValid) {
130 | // allow user to submit
131 | } else {
132 | // show error message
133 | }
134 |
135 | })();
136 |
137 | // --------------------------------------
138 |
139 | // Coding exercise: Finding submitted uers
140 |
141 | // Given an array of users, return 'true' if every user has submitted a request form.
142 | // Assign the result to the variable 'hasSubmitted'.
143 |
144 | (function() {
145 |
146 | var users = [
147 | { id: 21, hasSubmitted: true },
148 | { id: 62, hasSubmitted: false },
149 | { id: 4, hasSubmitted: true }
150 | ];
151 |
152 | var hasSubmitted = users.every(function(user) {
153 |
154 | return user.hasSubmitted;
155 |
156 | });
157 |
158 | })();
159 |
160 | // --------------------------------------
161 |
162 | // Coding exercise: In Progress Network Requests
163 |
164 | // Given an array of network objects representing network requests,
165 | // assign the boolean 'true' to the variable 'inProgress' if any network request has a 'status' of 'pending'.
166 |
167 |
168 | (function() {
169 |
170 | var requests = [
171 |
172 | { url: '/photos', status: 'complete' },
173 | { url: '/albums', status: 'pending' },
174 | { url: '/users', status: 'failed' }
175 |
176 | ];
177 |
178 | var inProgress = requests.some(function(request) {
179 |
180 | return request.status === 'pending';
181 |
182 | });
183 |
184 | })();
185 |
186 |
187 |
188 |
--------------------------------------------------------------------------------
/S06-every_sum/every_some.md:
--------------------------------------------------------------------------------
1 | # every & some Array Helper Method
2 |
3 | - The every() method tests whether all elements in the array pass the test implemented by the provided function.
4 |
5 | - The some() method tests whether some element in the array passes the test implemented by the provided function.
--------------------------------------------------------------------------------
/S06-every_sum/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S07-reduce/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S07-reduce/reduce.js:
--------------------------------------------------------------------------------
1 | // Array.prototype.reduce()
2 |
3 | // The reduce() method applies a function against an accumulator
4 | // and each value of the array (from left-to-right) to reduce it to a single value.
5 |
6 | var numbers = [10, 20, 30];
7 |
8 | (function() {
9 |
10 | var sum = 0;
11 |
12 | // We start with our for loop implementation.
13 |
14 | for (var i = 0; i < numbers.length; i++) {
15 | sum += numbers[i];
16 | }
17 |
18 | console.log(sum);
19 |
20 | console.log("------------------- 1");
21 |
22 | })();
23 |
24 | (function() {
25 |
26 | // .reduce takes 2 params:
27 |
28 | // first: callback function
29 | // second: initial value of the first arguments for the first call of the callback function
30 |
31 | // The callback takes four arguments:
32 |
33 | // 1) accumulator value
34 | // 2) current element of the array
35 | // 3) index of the current element in the array
36 | // 4) the array reduce was called upon
37 |
38 | // The result is that we reduce our array into a single value, using a function that we specify.
39 |
40 | var sum = numbers.reduce(function(sum, number) {
41 | return sum + number;
42 | }, 0);
43 |
44 | console.log(sum);
45 |
46 | console.log("------------------- 2");
47 |
48 | })();
49 |
50 | // Another example using .reduce on an array of data
51 |
52 | // We want to end up with an array that is ['red', 'yellow', 'blue']
53 |
54 | (function() {
55 |
56 | var primaryColors = [
57 |
58 | { color: 'red' },
59 | { color: 'yellow' },
60 | { color: 'blue' }
61 |
62 | ];
63 |
64 | var reducedColors = primaryColors.reduce(function(previous, currentElement) {
65 |
66 | previous.push(currentElement.color);
67 |
68 | return previous;
69 |
70 | }, []);
71 |
72 | console.log(reducedColors);
73 |
74 | console.log("------------------- 3");
75 |
76 | })();
77 |
78 | // Another practical use of .reduce below...
79 |
80 | // This is a replication of a tech interview whiteboard question...
81 |
82 | // Question:
83 |
84 | // Given a string such as the examples below, write a function that decides whether the parens are 'balanced'.
85 |
86 | // Examples:
87 |
88 | // "()" - Balanced
89 | // "()()()" - Balanced
90 | // "((()))" - Balanced
91 | // ")(" - NOT BALANCED
92 | // "(()" - NOT BALANCED
93 | // ")()(" - NOT BALANCED
94 |
95 |
96 | (function() {
97 |
98 | function balancedParens(string) {
99 |
100 | // We use the not operator ! to convert the number returned into a Boolean.
101 |
102 | // Javascript coerces a positive or negative number to Truthy, while 0 becomes Falsy.
103 |
104 | return !string.split("").reduce(function(previous, char) {
105 |
106 | if (previous < 0) { return previous; }
107 | if (char === "(") { return ++previous; }
108 | if (char === ")") { return --previous; }
109 | return previous;
110 |
111 | }, 0);
112 |
113 | }
114 |
115 | console.log(balancedParens("(()")); // false
116 | console.log(balancedParens("()")); // true
117 | console.log(balancedParens("(()())")); // true
118 |
119 | console.log("------------------- 3");
120 |
121 | })();
122 |
123 |
124 | // -------------------------------------------------------
125 |
126 | // Coding exercise 1 - Distance travelled
127 |
128 | // Use the reduce helper to find the sum of all the distances travelled.
129 | // Assign the result to the variable 'totalDistance'.
130 |
131 | (function() {
132 |
133 | var trips = [{ distance: 34 }, { distance: 12 } , { distance: 1 }];
134 |
135 | var totalDistance = trips.reduce(function(previous, trip) {
136 | return trip.distance += previous;
137 | }, 0);
138 |
139 |
140 | console.log(totalDistance);
141 |
142 | console.log("------------------- 4");
143 |
144 | })();
145 |
146 |
147 | // Coding exercise 2 - Reducing properties
148 |
149 | // Use the 'reduce' helper to create an object that tallies the number of sitting and standing desks.
150 | // The object returned should have the form '{ sitting: 3, standing: 2 }'.
151 | // The initial value has been provided to you.
152 | // Hint: Don't forget to return the accumulator object (the first argument to the iterator function)
153 |
154 |
155 | (function() {
156 |
157 | var desks = [
158 |
159 | { type: 'sitting' },
160 | { type: 'standing' },
161 | { type: 'sitting' },
162 | { type: 'sitting' },
163 | { type: 'standing' }
164 |
165 | ];
166 |
167 | var totals = { sitting: 0, standing: 0 };
168 |
169 | var deskTypes = desks.reduce(function(previous, desk) {
170 |
171 | if (desk.type === 'sitting') { console.log("Sitting!"); previous.sitting++; }
172 | if (desk.type === 'standing') { console.log("Standing!"); previous.standing++; }
173 | return previous;
174 |
175 | }, { sitting: 0, standing: 0 });
176 |
177 | console.log(deskTypes);
178 |
179 | })();
180 |
181 |
182 | // Coding exercise 3 - Hard mode - Custom 'unique' helper
183 |
184 | // Write a function called 'unique' that will remove all duplicate values from an array.
185 |
186 | // For example, given the following array:
187 |
188 | // var numbers = [1, 1, 2, 3, 4, 4];
189 |
190 | // Your function should return [1, 2, 3, 4]
191 |
192 | (function() {
193 |
194 | var numbers = [1, 1, 2, 3, 4, 4];
195 |
196 | function unique(array) {
197 |
198 | // Create a new blank array that will be returned
199 |
200 | // Check array for number of occurences of each item,
201 | // If item occurs more than once, add to the accumulator
202 | // If accumulator is greater than 0, do NOT add current item to new array
203 |
204 | // If it occurs more than once, only add it once to new array
205 |
206 |
207 | var newArr = [];
208 |
209 | array.map(function(element) { // my first solution (doesn't work for objects)
210 | // doesn't use reduce / find.
211 | if (!newArr.includes(element)) {
212 | newArr.push(element);
213 | }
214 | });
215 |
216 | return newArr;
217 | }
218 |
219 | var numbers2 = [1,3,5,7,3,4,3,3, "hi", "hi", true, true, {id: 1}, {id: 1}, 3,2,1,0,0,0];
220 |
221 | function unique2(array) {
222 | var newArr = [...new Set(array)]; // An interesting solution (without using find/reduce)
223 | return newArr; // This uses the rest and Set.
224 | }
225 |
226 | console.log(unique(numbers));
227 | console.log(unique(numbers2));
228 |
229 | console.log(unique2(numbers));
230 | console.log(unique2(numbers2));
231 |
232 |
233 | })();
234 |
235 | (function() {
236 |
237 | // Another solution that works and uses reduce and find.
238 |
239 | function unique(array) {
240 | return array.reduce(function(acc, number) {
241 | var numberInAcc = acc.find(item => item === number);
242 | if (numberInAcc === undefined) {
243 | acc.push(number);
244 | }
245 | return acc;
246 | }, []);
247 | }
248 |
249 | })();
250 |
--------------------------------------------------------------------------------
/S07-reduce/reduce.md:
--------------------------------------------------------------------------------
1 | # reduce Array Helper Method
2 |
3 | - The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
--------------------------------------------------------------------------------
/S08-const_let/const_let.js:
--------------------------------------------------------------------------------
1 | // Const & Let Keywords
2 |
3 | // The let statement declares a block scope local variable, optionally initializing it to a value.
4 |
5 | // let allows you to declare variables that are limited in scope to the block, statement,
6 | // or expression on which it is used.
7 |
8 | // This is unlike the var keyword, which defines a variable globally,
9 | // or locally to an entire function regardless of block scope.
10 |
11 | // Variables declared by let have as their scope the block in which they are defined,
12 | // as well as in any contained sub-blocks. In this way, let works very much like var.
13 | // The main difference is that the scope of a var variable is the entire enclosing function:
14 |
15 | function varTest() {
16 | var x = 1;
17 | if (true) {
18 | var x = 2; // same variable
19 | console.log(x); // 2
20 | }
21 | console.log(x); // 2
22 | }
23 |
24 | function letTest() {
25 | let x = 1;
26 | if (true) {
27 | let x = 2; // different variable
28 | console.log(x); // 2
29 | }
30 | console.log(x); // 1
31 | }
32 |
33 | // --------------------------
34 |
35 | // Constants are block-scoped, much like variables defined using the let statement.
36 | // The value of a constant cannot change through re-assignment, and it can't be redeclared.
37 |
38 | // This declaration creates a constant that can be either global or local to the function in which it is declared.
39 | // An initializer for a constant is required; that is, you must specify its value in the same statement in which
40 | // it's declared (which makes sense, given that it can't be changed later).
41 |
42 | // The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable,
43 | // just that the variable identifier cannot be reassigned.
44 | // For instance, in case the content is an object, this means the object itself can still be altered.
45 |
46 | // All the considerations about the "temporal dead zone" that apply to let, also apply to const.
47 |
48 | // A constant cannot share its name with a function or a variable in the same scope.
--------------------------------------------------------------------------------
/S08-const_let/const_let.md:
--------------------------------------------------------------------------------
1 | # Const & Let
2 |
3 | - Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through re-assignment, and it can't be redeclared. This declaration creates a constant that can be either global or local to the function in which it is declared. An initializer for a constant is required; that is, you must specify its value in the same statement in which it's declared (which makes sense, given that it can't be changed later).
4 |
5 | - Let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
--------------------------------------------------------------------------------
/S08-const_let/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S09-template_strings/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S09-template_strings/template-strings.js:
--------------------------------------------------------------------------------
1 | // Template Literals
2 |
3 | // Template literals are string literals allowing embedded expressions.
4 | // You can use multi-line strings and string interpolation features with them.
5 | // They were called "template strings" in prior editions of the ES2015 / ES6 specification.
6 |
7 |
8 | // ES5
9 |
10 | (function() {
11 |
12 | function getMessage() {
13 | const year = new Date().getFullYear();
14 |
15 | return "The Year is " + year;
16 | }
17 |
18 | console.log(getMessage());
19 |
20 | })();
21 |
22 |
23 | // ES6 with template strings
24 |
25 | (function() {
26 |
27 | function getMessage() {
28 | return `The year is ${new Date().getFullYear()}`;
29 | }
30 |
31 | console.log(getMessage());
32 |
33 | })();
34 |
35 |
36 | // Template literals come in very handy when concatenating long strings and variable names.
37 |
38 | (function() {
39 |
40 | const device_id = 4;
41 | const guid = 20;
42 | const username = "Hello";
43 |
44 | // ES5 way... very hard to read...
45 | // const data = '{"device_id":"' + device_id + '","guid":"' + guid + '","username":"' + username + '","}';
46 |
47 | // ES6 way:
48 | const data = `{ "device_id": "${device_id}", "guid": "${guid}", "username": "${username}"," }`;
49 |
50 | console.log(data);
51 |
52 | })();
53 |
54 |
--------------------------------------------------------------------------------
/S09-template_strings/template-strings.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wlabatey/es6/bec68df4e01f2300fbc28228cfe3f1a5b72a18d0/S09-template_strings/template-strings.md
--------------------------------------------------------------------------------
/S10-arrow_functions/arrow_functions.js:
--------------------------------------------------------------------------------
1 |
2 | // Arrow Functions
3 |
4 | // An arrow function expression has a shorter syntax compared to function expressions
5 | // and does not bind its own this, arguments, super, or new.target.
6 |
7 | // Arrow functions are always anonymous.
8 |
9 | // These function expressions are best suited for non-method functions and they can not be used as constructors.
10 |
11 |
12 | // ES5 Functions
13 |
14 | (function() {
15 |
16 | const add = function(a,b) {
17 | return a + b;
18 | };
19 |
20 | console.log(add(1,2));
21 |
22 | })();
23 |
24 |
25 | // ES6 Fat Arrow Functions
26 |
27 | (function() {
28 |
29 | const add = (a, b) => a + b; // With a single expression, we can enjoy an implicit return.
30 | // This means we do not need to use the return keyword or curly braces.
31 | console.log(add(2, 2));
32 |
33 | })();
34 |
35 | // ES6 IIFE
36 |
37 | (global => {
38 |
39 | const a = "ES6 IIFE!";
40 | console.log(a);
41 |
42 | })(window);
43 |
44 |
45 | // -----------------------------------
46 |
47 | // Advanced use of arrow functions
48 |
49 | (function() {
50 |
51 | // ES5 function
52 |
53 | const double = function(number) {
54 | return 2 * number;
55 | };
56 |
57 | console.log(double(8));
58 |
59 | })();
60 |
61 | (function() {
62 |
63 | // ES6 function
64 |
65 | // If the function only takes a single argument, we can drop the parens and write it as below.
66 |
67 | // This is the most concise way to use arrow functions.
68 |
69 | const doubleNew = number => 2 * number;
70 |
71 | })();
72 |
73 | (function() {
74 |
75 | // Another example of refactoring a function using fat arrows.
76 |
77 | // The ES5 original....
78 |
79 | const numbers = [1,2,3];
80 |
81 | const a = numbers.map(function(number) {
82 | return 2 * number;
83 | });
84 |
85 | console.log(a);
86 |
87 | // As we only have one argument, we can drop the parens
88 | // and as we only have one expression inside the function,
89 | // we can drop the curly braces and the return statement.
90 |
91 | // Compare how concise this line of code is with not only the ES5 equivalent above,
92 | // but also against writing an entire for loop instead of using the .map array helper method!
93 |
94 | const b = numbers.map(number => 2 * number);
95 |
96 | console.log(b);
97 |
98 | })();
99 |
100 |
101 | // When to use arrow functions
102 |
103 | // Arrow functions fix what was considered a longterm bug of the 'this' keyword in javascript.
104 |
105 | // Until arrow functions, every new function defined its own 'this' value, which can
106 | // be confusing as it is not always what you would expect.
107 |
108 | // In ES5, a workaround was to assign the value of this to a variable that could
109 | // then be referenced to get the correct result, e.g. var self = this;
110 |
111 | // With arrow functions, this is no longer needed.
112 |
113 | (function() {
114 |
115 | const team = {
116 | members: ['Jane', 'Bill'],
117 | teamName: 'Super Squad',
118 | teamSummary: function() {
119 | return this.members.map(member =>
120 | `${member} is on team ${this.teamName}`);
121 | }
122 | };
123 |
124 | console.log(team.teamSummary());
125 |
126 | })();
127 |
--------------------------------------------------------------------------------
/S10-arrow_functions/arrow_functions.md:
--------------------------------------------------------------------------------
1 | # Arrow Functions
2 |
3 | - An arrow function expression has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.
--------------------------------------------------------------------------------
/S10-arrow_functions/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S11-enhanced_object_literals/enhanced_object_literals.js:
--------------------------------------------------------------------------------
1 | // Enhanced Object Literals
2 |
3 | function createBookShop(inventory) {
4 | return {
5 |
6 |
7 | // ES5..
8 |
9 | // inventory: inventory,
10 |
11 | // ES6:
12 |
13 | // When a key and value have the exact same value, we can just write it once like below.
14 |
15 | inventory,
16 |
17 |
18 | // ES5..
19 |
20 | // inventoryValue: function() {
21 |
22 | // ES6:
23 |
24 | // We can now add methods just by using the method name, parens and openign curly brace.
25 | // This saves us having to use the colon and function keyword.
26 |
27 | inventoryValue() {
28 |
29 | console.log("Test inventory value");
30 |
31 | // Use .reduce on inventory to iterate through each book:
32 | // - add item.price to accumulator
33 | // - Return total price
34 |
35 | // ES5 syntax
36 |
37 | return this.inventory.reduce(function(total, book) {
38 |
39 | return total + book.price;
40 |
41 | }, 0);
42 |
43 | },
44 |
45 | // Same this as above, but with arrow functions.
46 |
47 | inventoryValueES6() {
48 |
49 | console.log("Inventory value es6");
50 |
51 | return this.inventory.reduce((total, book) => total + book.price, 0);
52 |
53 | },
54 |
55 | // Use .find on inventory to find first item that satisfies our provided function.
56 |
57 | // Return the price of that item
58 |
59 | priceForTitle(title) {
60 |
61 | console.log("Test price for title");
62 |
63 | // Get book price from a given title
64 |
65 | return this.inventory.find(function(book) {
66 |
67 | return title === book.title;
68 |
69 | }).price;
70 | },
71 |
72 | // Same as above, but using arrow functions. Notice again how concise the code is.
73 |
74 | priceForTitleES6(title) {
75 |
76 | console.log("Test price for title es6");
77 |
78 | return this.inventory.find((book) => title === book.title).price;
79 |
80 | }
81 | };
82 | }
83 |
84 | const inventory = [
85 | { title: 'Harry Potter', price: 10 },
86 | { title: 'Eloquent Javascript', price: 15}
87 | ];
88 |
89 | const bookShop = createBookShop(inventory);
90 |
91 | console.log(bookShop);
92 |
93 | // --------------------------------------------------------------
94 |
95 | // When to use enhanced object literals...
96 |
97 | (function() {
98 |
99 | // We are going to use jQuery to post data / make an http request to some remote place
100 |
101 | // This is just an example to look at the syntax.
102 |
103 | function saveFile(url, data) {
104 |
105 | // Take some data and make a http request with jQuery.
106 |
107 | $.ajax({
108 | url,
109 | data,
110 | method: 'POST'
111 | });
112 | }
113 |
114 | const url = "http://fileupload.com";
115 | const data = { color : "red" };
116 |
117 | saveFile(url, data);
118 |
119 | })();
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/S11-enhanced_object_literals/enhanced_object_literals.md:
--------------------------------------------------------------------------------
1 | # Enhanced Object Literals
2 |
3 | - ES6 PRovides a few new ways of writing out object literals to make things easier and more concise.
4 |
5 | - When a key/value pair is identical, e.g. 'property: property', we can now condense this down to just 'property,' which is more legible.
6 |
7 | - When we are adding methods to an object, we can skip the function keyword and colon. Before, this would have looked like 'methodName: function() {' but we can now just write 'methodName() {'.
--------------------------------------------------------------------------------
/S11-enhanced_object_literals/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S12-default_arguments/default_arguments.js:
--------------------------------------------------------------------------------
1 | // Default Function Arguments
2 |
3 | // Default function parameters allow formal
4 | // parameters to be initialized with default values if no value or undefined is passed.
5 |
6 | (function() {
7 |
8 |
9 | // Example ajax request function in ES5.
10 |
11 | function makeAjaxRequest(url, method) {
12 |
13 | // If no method argument is passed in, set it to 'GET' as the default.
14 |
15 | if (!method) {
16 | method = 'GET';
17 | }
18 |
19 | // logic to make the request.
20 |
21 | console.log(method);
22 |
23 | }
24 |
25 | // -------------------------------------------------------
26 |
27 | // Both of these would return the same result
28 |
29 | makeAjaxRequest('google.com');
30 | makeAjaxRequest('google.com', 'GET');
31 |
32 | })();
33 |
34 | (function() {
35 |
36 | // Same example as above in ES6 with default parameters:
37 |
38 | function makeAjaxRequest(url, method = 'GET') {
39 |
40 | // Do stuff to make request...
41 |
42 | console.log(method);
43 |
44 | }
45 |
46 | makeAjaxRequest('google.com'); // GET
47 | makeAjaxRequest('google.com', 'POST'); // POST
48 |
49 | console.log("----------------------------------------------");
50 |
51 | })();
52 |
53 | // --------------------------------------
54 |
55 | // A more complicated example....
56 |
57 | (function() {
58 |
59 |
60 | function User(id) {
61 | this.id = generateId();
62 | }
63 |
64 | function generateId() {
65 | return Math.floor(Math.random() * 99999999);
66 | }
67 |
68 | function createAdminUser(user) {
69 | user.admin = true;
70 |
71 | return user;
72 | }
73 |
74 | // Ugly way to create a new user object, assign random id and make an admin.
75 |
76 | createAdminUser(new User(generateId()));
77 |
78 | const a = new User(1);
79 |
80 | console.log(a);
81 |
82 | console.log("----------------------------------------------");
83 |
84 | })();
85 |
86 | // Instead of the above, we can do something like below, which uses default values to make our
87 | // createAdminUser function a lot easier to use.
88 |
89 | (function() {
90 |
91 | function User(id) {
92 | this.id = generateId();
93 | }
94 |
95 | function generateId() {
96 | return Math.floor(Math.random() * 99999999);
97 | }
98 |
99 | // Instead of the above
100 |
101 | function createAdminUser(user = new User(generateId)) {
102 | user.admin = true;
103 |
104 | return user;
105 | }
106 |
107 | const a = createAdminUser();
108 |
109 | const b = new User();
110 |
111 | console.log(a);
112 |
113 | console.log(b);
114 |
115 | // We can also use the createAdminUser to make an existing user object into an admin.
116 |
117 | createAdminUser(b);
118 |
119 | console.log(b);
120 |
121 | })();
122 |
--------------------------------------------------------------------------------
/S12-default_arguments/default_arguments.md:
--------------------------------------------------------------------------------
1 | # Default Function Arguments
2 |
3 |
--------------------------------------------------------------------------------
/S12-default_arguments/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S13-rest_and_spread/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S13-rest_and_spread/rest_and_spread.js:
--------------------------------------------------------------------------------
1 | // Rest and Spread
2 |
3 | const line = "-".repeat(100);
4 |
5 | (function() {
6 |
7 | // An example of using the rest parameter to represent an indefinite number of arguments.
8 |
9 | function addNumbers(...numbers) {
10 | console.log(numbers);
11 | return numbers.reduce((sum, number) => {
12 | return sum + number;
13 | }, 0);
14 | }
15 |
16 | console.log(addNumbers(1,2,3,4,5,6,7));
17 |
18 | console.log(line);
19 |
20 | })();
21 |
22 | // More examples...
23 |
24 | // In this example, imagine we are building an application where we are putting together
25 | // a colour pallete and display it to our users.
26 |
27 | // Imagine we have some default colours, and a list of colours our user has entered themselves.
28 |
29 | (function() {
30 |
31 | const defaultColors = ['red', 'green'];
32 | const userFavouriteColours = ['orange', 'yellow'];
33 | const fallColors = ['fire red', 'fall orange'];
34 |
35 | // One option for joining these two arrays together is the .concat array helper method..
36 |
37 | console.log(defaultColors.concat(userFavouriteColours));
38 |
39 | console.log(line);
40 |
41 | console.log(['green', 'blue', ...fallColors, ...defaultColors, ...userFavouriteColours]);
42 |
43 | // In this second option, we first create a new array with the array literal [] syntax.
44 |
45 | // We then use the ... spread operator to take all the items of the original arrays
46 | // and add them individually to our new array.
47 |
48 | // Note the difference between using spread as above, and the below...
49 |
50 | console.log(line);
51 |
52 | // This becomes a new array object with our two seperate arrays inside it.
53 |
54 | console.log([defaultColors, userFavouriteColours]);
55 |
56 | // One reason we might choose to use the ... spread operator to join our two new arrays
57 | // into one single array is that is is clearer to read and figure out what is happening.
58 |
59 | // It is also easier to mix and match single additional items to add to an array along with
60 | // existing arrays, as on line 40 above.
61 |
62 | console.log(line);
63 |
64 | })();
65 |
66 | // One more example...
67 |
68 | (function() {
69 |
70 | // A simple shopping list function that checks to see if we have milk on our list.
71 |
72 | // If we do not, then add it to our list and return the list as a new array.
73 |
74 | function validateShoppingList(...items) {
75 |
76 | if (items.indexOf('milk') === -1) {
77 | return [ 'milk', ...items];
78 | }
79 |
80 | return items;
81 |
82 | // Check list to make sure it always has milk.
83 |
84 | }
85 |
86 | console.log(validateShoppingList('oranges', 'bread')); // ['milk', 'oranges', 'bread']
87 | console.log(validateShoppingList('milk')); // ['milk']
88 |
89 | })();
90 |
91 | // When would we actually want to use rest and spread?
92 |
93 | (function() {
94 |
95 | // Imagine we are creating an open source javascript library that does fancy math calculations...
96 |
97 | const MathLibrary = {
98 |
99 | // Imagine we had a method called calculateProduct which simply multiplies two numbers together.
100 |
101 | // And then our library got really popular, but we wanted to change this method name.
102 |
103 | // Simply changing it might break a lot of other people's code as they depend on this method
104 | // being called calculateProduct.
105 |
106 | // So how would we go about fixing this?
107 |
108 | // We can create a new method called multiply and then edit our calculateProduct method
109 | // to simply return the result of invoking multiply.
110 |
111 | // This means we don't have duplicate logic in our codebase, and we can simply pass all the arguments
112 | // along to the updated method using rest and spread.
113 |
114 | calculateProduct(...rest) {
115 | console.log(rest);
116 | console.log('Please use the multiply method instead.');
117 | return this.multiply(...rest);
118 | },
119 |
120 | multiply(a, b) {
121 | return a * b;
122 | }
123 | };
124 |
125 | // The below will simple multiply the first two arguments
126 |
127 | console.log(MathLibrary.calculateProduct(2,3,4,5)); // 6
128 |
129 | console.log(MathLibrary.multiply(2,3,4)); // 6 aswell
130 |
131 | })();
132 |
--------------------------------------------------------------------------------
/S13-rest_and_spread/rest_and_spread.md:
--------------------------------------------------------------------------------
1 | # Rest and Spread
2 |
3 | - The rest parameter syntax allows us to represent an indefinite number of arguments as an array. If the last named argument of a function is prefixed with ..., it becomes an array whose elements from 0 (inclusive) to theArgs.length (exclusive) are supplied by the actual arguments passed to the function.
4 |
5 | - The spread syntax allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.
--------------------------------------------------------------------------------
/S14-destructuring/destructuring.js:
--------------------------------------------------------------------------------
1 | // Destructuring
2 |
3 | // Pretend we are creating some kind of financial application and we are
4 | // creating an object that represents an expense.
5 |
6 | // ES5
7 |
8 | const line = "-".repeat(50);
9 |
10 | (function() {
11 |
12 | var expense = {
13 | type: 'Business',
14 | amount: '$45 USD'
15 | };
16 |
17 | // As we can see below, we have repeated a lot of identical words, which is something we
18 | // should always seek to avoid.
19 |
20 | // Destructuring is something which will allow us to avoid repetition in ES6.
21 |
22 | var type = expense.type;
23 | var amount = expense.amount;
24 |
25 | })();
26 |
27 | // ES6
28 |
29 | (function() {
30 |
31 | const expense = {
32 | type: 'Business',
33 | amount: '$45 USD'
34 | };
35 |
36 | // In ES6, we can use the below syntax to declare a variable and set it to
37 | // an object property of the exact same name. This only works when the property
38 | // has the exact same name as the variable!
39 |
40 | // We can even compact this further by using commas...
41 |
42 | const { type, amount } = expense;
43 | // const { amount } = expense;
44 |
45 | console.log(type);
46 | console.log(amount);
47 |
48 | console.log(line);
49 |
50 | })();
51 |
52 | // Imagine we are creating an object representing a file on our hard disk.
53 |
54 | (function() {
55 |
56 | // ES5
57 |
58 | var savedFile = {
59 | extension: '.jpg',
60 | name: 'repost',
61 | size: 14040
62 | };
63 |
64 |
65 | // function fileSummary(file) {
66 |
67 | // We can use destructuring in the below function to save us duplicating the same word over and over...
68 |
69 | // By using the following syntax with curly braces, we can reference object properties directly in our
70 | // function, so we don't need to write file.name, file.extension, etc.
71 |
72 | function fileSummary({ name, extension, size }) {
73 |
74 | // return `The file ${file.name} ${file.extension} is of size ${file.size}.`;
75 |
76 | return `The file ${name}${extension} is of size ${size}.`;
77 | }
78 |
79 | console.log(fileSummary(savedFile));
80 |
81 | console.log(line);
82 |
83 | })();
84 |
85 | // Destructuring Arrays
86 |
87 | // When destructuring arrays, we can use the following syntax to pull off individual elements.
88 |
89 | // With arrays, we need to use square braces to pull out elements.
90 |
91 | (function() {
92 |
93 | const companies = [
94 | 'Google',
95 | 'Facebook',
96 | 'Uber'
97 | ];
98 |
99 | const [ name, name2, ...name3 ] = companies; // Google, Facebook
100 |
101 | console.log(name); // Google
102 | console.log(name2); // Facebook
103 | console.log(name3); // ['Uber']
104 |
105 | console.log(line);
106 |
107 | })();
108 |
109 | (function() {
110 |
111 | const companies = [
112 |
113 | { name: 'Google', location: 'Mountain View' },
114 | { name: 'Facebook', location: 'Menlo Park' },
115 | { name: 'Uber', location: 'San Francisco' }
116 |
117 | ];
118 |
119 | // In ES5, if we want to access a specific property of an element in an array, we need to do this:
120 |
121 | // var location = companies[0].location; // 'Mountain View'
122 |
123 | // In ES6, we can do this...
124 |
125 | // Which is using square and curley braces to get the first element of the array and then get the location
126 | // property inside that object.
127 |
128 | const [{ location }] = companies;
129 |
130 | console.log(location);
131 |
132 | console.log(line);
133 |
134 | })();
135 |
136 | (function() {
137 |
138 | const Google = {
139 | locations: ['Mountain View', 'New York', 'London']
140 | };
141 |
142 | // In this example, we use destructuring to access the first element of the array
143 | // inside our Google object.
144 |
145 | // This syntax looks quite odd, as it is quite different from ES5.
146 |
147 | const { locations: [ location ] } = Google;
148 |
149 | console.log(location);
150 |
151 | console.log(line);
152 |
153 | })();
154 |
155 | (function() {
156 |
157 | // Imagine we are creating some kind of application where a user needs to sign up.
158 |
159 | // We start with a simple signUp function which takes a couple arguments, but later
160 | // in time we decide we want to add more information to it (email, DOB, city, etc.)
161 |
162 | // If we have a function like this with a long list of arguments, it can be quite
163 | // difficult to remember the order the arguments need to go in when using it later on.
164 |
165 | function signUp({ username, password, email, dateOfBirth, city }) {
166 |
167 | // create new user
168 |
169 | }
170 |
171 | // other code
172 | // other code
173 | // other code
174 | // other code
175 | // other code
176 | // other code
177 | // other code
178 | // other code
179 |
180 | signUp('myName', 'myPassword', 'myemail@example.com', '1/1/1990', 'New York');
181 |
182 | // An other option is instead to create a user object and then use destructuring
183 | // to pass in all the properties from our user object.
184 |
185 | // We can't escape the fact that we must still have all the properties, but by using
186 | // destructuring, we no longer need the correct order.
187 |
188 | const user = {
189 |
190 | username: 'myname',
191 | password: 'mypassword',
192 | email: 'myemail@example.com',
193 | dateOfBirth: '1/1/1990',
194 | city: 'New York'
195 |
196 | };
197 |
198 | signUp(user);
199 |
200 | console.log(line);
201 |
202 | })();
203 |
204 | // Stephen was working on a project that took data from an API and presented it as a series of
205 | // points on a graph.
206 |
207 | (function() {
208 |
209 | const points = [
210 |
211 | // The data he was getting was an array containing multiple arrays with the coordinates.
212 |
213 | [4, 5],
214 | [10, 1],
215 | [0, 40]
216 |
217 | ];
218 |
219 | // But the library he was using needed the data to be represented as an array containing
220 | // multiple objects with x and y properties.
221 |
222 | // [
223 |
224 | // { x: 4, y: 5 },
225 | // { x: 10, y: 1 },
226 | // { x: 0, y: 40 }
227 |
228 | // ];
229 |
230 | // His challenge then was to change the structure of the data to work with the library he was using.
231 |
232 | // We can do this with ES6
233 |
234 | // Below, we use destructuring in the argument list to pull off the first two items of the array
235 | // that we pass in and then again in the function body to create a new object with x & y properties.
236 |
237 | const pointsList = points.map(([x, y]) => ({x, y}));
238 |
239 | console.log(pointsList);
240 |
241 | console.log(line);
242 |
243 | })();
244 |
245 | (function() {
246 |
247 | // Recursion with Destructuring
248 |
249 | // Use array destructuring, recursion and the rest/spread operators to create a function 'double'
250 | // that will return a new array with all values inside of it multiplied by two.
251 |
252 | // DO NOT USE ANY ARRAY HELPERS.
253 |
254 | // Input: double([1,2,3])
255 |
256 | // Output: [2,4,6]
257 |
258 | // Hint: Don't forget that with recursion, you must add a base case so you don't get an infinite call stack.
259 | // e.g. 'const [number, ...rest] = numbers' and number is undefined, do you need to keep walking through
260 | // the array?
261 |
262 |
263 | const numbers = [1,2,3];
264 |
265 | function double([first, ...rest]) {
266 |
267 | // Must use array destructuring
268 | // Must use recursion
269 | // Must use rest/spread operators
270 |
271 | // Return a new array with every element doubled.
272 |
273 | // Add a test to check that our new array does not contain any element which is undefined.
274 |
275 | return rest.length ? [ first * 2, ...double(rest) ] : [ first * 2 ];
276 |
277 | }
278 |
279 | // console.log(double(numbers));
280 | // console.log(double([1]));
281 |
282 | })();
283 |
284 |
285 | // Another solution...
286 |
287 | const numbers = [1,2,3];
288 |
289 | function double([number, ...rest], arr = []) {
290 |
291 |
292 | console.log(`number is: ${number}`);
293 | console.log(`rest is: ${rest}`);
294 | console.log(`arr is: ${arr}`);
295 |
296 | if (!number && !rest.length) {
297 | return arr;
298 | }
299 |
300 | return double(rest, [ ...arr, number * 2]);
301 | }
302 |
303 | // This one takes an array as the first argument and then uses destructuring to assign
304 | // the first item of the array to the parameter 'number' and the rest to an array called 'rest'
305 |
306 | // We also have an argument called arr which acts as our accumulator (like in the .reduce array helper)
307 | // By default, arr is set to an empty array.
308 |
309 | // We then check to see if we have a number and rest to work with.
310 | // If we don't, then we return arr
311 |
312 | // If (!number && !rest.length) returns false, then we recursively call the double function...
313 |
314 | // We return the result of calling double on the 'rest' array.
315 |
316 | // We take everything accumulated in the current arr and spread them out into arr and then add the current number * 2.
317 |
318 | console.log(double(numbers));
319 |
320 |
--------------------------------------------------------------------------------
/S14-destructuring/destructuring.md:
--------------------------------------------------------------------------------
1 | # Destructuring
2 |
3 | - The destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects into distinct variables.
--------------------------------------------------------------------------------
/S14-destructuring/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S15-classes/classes.js:
--------------------------------------------------------------------------------
1 | // Classes in ES6
2 |
3 | // JavaScript classes introduced in ECMAScript 6 are syntactical sugar
4 | // over JavaScript's existing prototype-based inheritance.
5 |
6 | // The class syntax is NOT introducing a new object-oriented inheritance model to JavaScript.
7 |
8 | // JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.
9 |
10 |
11 | // We are going to use the example of a car object and then create another objetc that inherits from it.
12 |
13 |
14 | // ---------------------------------
15 |
16 | // Eric Elliott argues that using class inheritances in Javascript is not ideal.
17 |
18 | // In JavaScript, class inheritance piggybacks on top of the very rich, flexible prototypal inheritance features
19 | // built into the language a long time ago, but when you use class inheritance — even
20 | // the ES6+ `class` inheritance built on top of prototypes, you’re not using the full power & flexibility
21 | // of prototypal OO. In fact, you’re painting yourself into corners and opting into all of the class
22 | // inheritance problems.
23 |
24 | // See here: https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9#.yb1afcwtx
25 |
26 | // ---------------------------------
27 |
28 | (function() {
29 |
30 |
31 | function Car(options) {
32 | this.title = options.title;
33 | }
34 |
35 | // Stephen argues that using .prototype is confusing and difficult when compared to the way ES6
36 | // handles prototypal inheritance with classes.
37 |
38 | Car.prototype = {
39 | drive() {
40 | console.log('vroom');
41 | }
42 | };
43 |
44 | const car = new Car({ title: 'Focus' });
45 |
46 | console.log(car);
47 | car.drive();
48 |
49 |
50 | // Again, below is the boilerplate code required to allow our new Toyota object to inherit properties
51 | // from our Car object.
52 |
53 | function Toyota(options) {
54 | Car.call(this,options); // We call the Car function constructor to initialise our Toyota object with a title property.
55 | this.color = options.color;
56 | }
57 |
58 |
59 | // Object.create() allows us to create a new object with a specified protoype object.
60 | // We set the prototype of Toyota to a new empty object which has Car.prototype as its prototype.
61 | // This way, our Toyota objects will be able to access the methods and properties of our Car object.
62 |
63 | Toyota.prototype = Object.create(Car.prototype);
64 |
65 | // We set the constructor property of Toyota.property to our constructor function.
66 |
67 | Toyota.prototype.constructor = Toyota;
68 |
69 | // We add the honk method to Toyota's prototype object
70 |
71 | Toyota.prototype.honk = function() {
72 | console.log('beep');
73 | };
74 |
75 |
76 | // -----------------------------------
77 |
78 | // Stephen's point with going through the above code is to show how complicated the boilerplate code can be
79 | // when setting up objects and inheritance in ES5.
80 |
81 |
82 | const toyota = new Toyota({color: 'red', title: 'Daily Driver'});
83 | console.log(toyota);
84 | toyota.honk();
85 | toyota.drive();
86 |
87 | console.log("------------------------------------------");
88 |
89 | })();
90 |
91 |
92 | // Now we are going to refactor the above code using ES6 classes.
93 |
94 | // We have created equivalent functionality to the above, but using far less boilerplate code.
95 |
96 | (function(){
97 |
98 | // This gives us a new class object of Car
99 |
100 | class Car {
101 |
102 | // The constructor method is a special method for creating and
103 | // initializing an object created with a class.
104 |
105 | constructor({ title }) {
106 | this.title = title;
107 | }
108 |
109 |
110 | // We can add methods to our Car object by using ehanced object literal syntax, like below.
111 |
112 | drive() {
113 | console.log('vroom');
114 | }
115 | }
116 |
117 | class Toyota extends Car {
118 |
119 | constructor(options) {
120 | super(options); // The super keyword allows us to call a method of
121 | // the exact same name on the parent class.
122 |
123 | // This is equivalent of calling Car.constructor();
124 |
125 | this.color = options.color;
126 | }
127 |
128 | honk() {
129 | console.log('beep');
130 | }
131 | }
132 |
133 | const car = new Car({title: 'Focus'});
134 | const toyota = new Toyota({title: 'Toyota', color: 'red'});
135 |
136 | console.log(car); // An empty Car object
137 | console.log(toyota);
138 | car.drive();
139 | toyota.drive();
140 | toyota.honk();
141 |
142 |
143 | })();
--------------------------------------------------------------------------------
/S15-classes/classes.md:
--------------------------------------------------------------------------------
1 | # Classes
2 |
3 | - JavaScript classes introduced in ECMAScript 6 are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.
--------------------------------------------------------------------------------
/S15-classes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S16-generators/generators.js:
--------------------------------------------------------------------------------
1 | // We start with an example of for... of loops.
2 |
3 | // This quite similar to the array helper methods we looked at when starting the course.
4 |
5 | // The for...of statement creates a loop iterating over iterable objects (including Array, Map,
6 | // Set, String, TypedArray, arguments object and so on), invoking a custom iteration hook with statements
7 | // to be executed for the value of each distinct property.
8 |
9 | (function(){
10 |
11 | const colors = ['red', 'green', 'blue'];
12 |
13 | for (let color of colors) {
14 | console.log(color);
15 | }
16 |
17 | const numbers = [1,2,3,4];
18 |
19 | let total = 0;
20 | for (let number of numbers) {
21 | total += number;
22 | console.log(total);
23 | }
24 |
25 | // ---------------------------------------------------------------------------------------------------------------------------------------
26 | // ---------------------------------------------------------------------------------------------------------------------------------------
27 |
28 | })();
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | // Generators let us run some code, return a value and then return to the function and continue executing code.
38 |
39 | // From MDN:
40 |
41 | // Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.
42 |
43 | // Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead.
44 | // When the iterator's next() method is called, the generator function's body is executed until the first yield expression,
45 | // which specifies the value to be returned from the iterator or, with yield*, delegates to another generator function.
46 | // The next() method returns an object with a value property containing the yielded value and a done property which indicates
47 | // whether the generator has yielded its last value as a boolean. Calling the next() method with an argument will resume
48 | // the generator function execution, replacing the yield statement where execution was paused with the argument from next().
49 |
50 | (function() {
51 |
52 | function* shopping() {
53 |
54 | // stuff on the sidewalk
55 |
56 | // walking down the sidewalk
57 |
58 | // go int othe store with cash
59 |
60 | const stuffFromStore = yield 'cash';
61 |
62 | // walking to laundry place
63 |
64 | const cleanClothes = yield 'laundry';
65 |
66 | // walking back home
67 |
68 | return [stuffFromStore, cleanClothes];
69 | }
70 |
71 | // Stuff happening in the store
72 |
73 | const gen = shopping(); // Invoking our generator function with parens doesn't actually do anything.
74 |
75 | console.log(gen); // shopping generator object
76 |
77 | console.log(gen.next()); // leaving our house
78 |
79 | // walk into the store
80 | // walk up and down the aisles
81 | // purchase our stuff
82 |
83 | console.log(gen.next('groceries')); // leaving the store with groceries
84 |
85 | console.log(gen.next('clean clothes')); // leave the laundry place with clean clothes
86 |
87 | // ---------------------------------------------------------------------------------------------------------------------------------------
88 | // ---------------------------------------------------------------------------------------------------------------------------------------
89 |
90 | })();
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | // Another example with a colors generator function.
99 |
100 | (function(){
101 |
102 | function* colors() {
103 | yield 'red';
104 | yield 'blue';
105 | yield 'green';
106 | }
107 |
108 | // const gen = colors();
109 | // console.log(gen.next());
110 | // console.log(gen.next());
111 | // console.log(gen.next());
112 |
113 | // ---------------------------------------------------------------------------------------------------------------------------------------
114 | // ---------------------------------------------------------------------------------------------------------------------------------------
115 | // ------------------------------- Stephen's "big reveal": generators work perfectly with for...of loops. -------------------------------
116 | // ---------------------------------------------------------------------------------------------------------------------------------------
117 | // ---------------------------------------------------------------------------------------------------------------------------------------
118 |
119 | // Below is the example.
120 |
121 | // Our loop iterates through our generator and pushes each result into our myColors array.
122 |
123 | const myColors = [];
124 |
125 | for (let color of colors()) {
126 | myColors.push(color);
127 | }
128 | console.log(myColors); // ["red", "blue", "green"]
129 |
130 | // Generators can be used to iterate over any data structure we want, which is one of their biggest uses.
131 |
132 | // ---------------------------------------------------------------------------------------------------------------------------------------
133 | // ---------------------------------------------------------------------------------------------------------------------------------------
134 |
135 | })();
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | // Below is another example, showing where generator functions can be useful.
144 |
145 | // We are first creating an object that represents a software engineering team.
146 |
147 | // We then create another object representing a testing team, which will be separate from the engineering team.
148 |
149 | // We then combine generator functions.
150 |
151 | (function(){
152 |
153 | const testingTeam = {
154 | lead: 'Amanada',
155 | tester: 'Bill'
156 | };
157 |
158 | const engineeringTeam = {
159 |
160 | testingTeam,
161 | size: 3,
162 | department: 'Engineering',
163 | lead: 'Jill',
164 | manager: 'Alex',
165 | engineer: 'Dave'
166 |
167 | };
168 |
169 | // What we might use a generator for is to create a function that only iterates through our employee keys on the above object,
170 | // not the size or department.
171 |
172 | function* TeamIterator(team) {
173 | yield team.lead;
174 | yield team.manager;
175 | yield team.engineer;
176 | const testTeamGenerator = TestTeamIterator(team.testingTeam);
177 |
178 | // The yield* keyword can be thought of as a trap door that lets our for..of loop fall into our TestTeamIterator generator
179 | // and lets it also iterate over our other yield statements in the TeamTeamIterator generator.
180 |
181 | // This is called Generator Delegation.
182 |
183 | yield* testTeamGenerator;
184 | }
185 |
186 | function* TestTeamIterator(team) {
187 | yield team.lead;
188 | yield team.tester;
189 | }
190 |
191 | const myTeam = [];
192 |
193 | for (let member of TeamIterator(engineeringTeam)) {
194 | myTeam.push(member);
195 | }
196 | console.log(myTeam);
197 |
198 | console.log("-----------------------------------------------------------------");
199 |
200 | // ---------------------------------------------------------------------------------------------------------------------------------------
201 | // ---------------------------------------------------------------------------------------------------------------------------------------
202 |
203 | })();
204 |
205 |
206 |
207 |
208 |
209 |
210 | // Next, we take the above code and refactor it to make it more concise.
211 |
212 | // We use symbol iterators to do this.
213 |
214 | // The way it helps is that it allows us to merge our Iterator generators into our two team objects.
215 |
216 | // Symbol iterator is a special object in ES6 that teaches objects how to deal with for...of loop.
217 |
218 | (function(){
219 |
220 | const testingTeam = {
221 | lead: 'Amanada',
222 | tester: 'Bill',
223 |
224 | // Our for...of loop discovers the key called [Symbol.iterator] and if it exists,
225 | // it will use the generator function it is pointing at for iteration.
226 |
227 | // In ES6 we can use key interpolation by using square brackets around the key name.
228 | // This does not create an array, but allows us to have a dynamically generated key.
229 |
230 | [Symbol.iterator]: function* () {
231 |
232 | // We use 'this' here to refer to the testingteam object.
233 |
234 | yield this.lead;
235 | yield this.tester;
236 | }
237 | };
238 |
239 | const engineeringTeam = {
240 |
241 | testingTeam,
242 | size: 3,
243 | department: 'Engineering',
244 | lead: 'Jill',
245 | manager: 'Alex',
246 | engineer: 'Dave',
247 | [Symbol.iterator]: function* () {
248 |
249 | yield this.lead;
250 | yield this.manager;
251 | yield this.engineer;
252 |
253 | // We use yield* here to make sure that when iterating through our engineeringTeam object,
254 | // we also drop down into our testingTeam object and also walk through that too.
255 |
256 | yield* testingTeam;
257 | }
258 |
259 | };
260 |
261 | const myTeam = [];
262 |
263 | // We no longer need to use a separately defined generator function.
264 |
265 | // We can just pass our engineeringTeam object and our for...of loop will find the [Symbol.iterator] object
266 | // which will use the generator to iterate through the object and also the testingTeam object to produce
267 | // the same result as before.
268 |
269 | for (let member of engineeringTeam) {
270 | myTeam.push(member);
271 | }
272 |
273 | console.log(myTeam);
274 |
275 | console.log("-----------------------------------------------------------------");
276 |
277 | })();
278 |
279 |
280 | // Next we create a basic tree data structure to show how we can use a generator to iterate through an unknown
281 | // number of nodes.
282 |
283 | (function() {
284 |
285 | // We create a class of Comment, which contains content and children
286 |
287 | class Comment {
288 | constructor(author, content, children) {
289 | this.author = author;
290 | this.content = content;
291 | this.children = children;
292 | }
293 |
294 | // We use a symbol iterator with this specific syntax to allow a for..of loop to
295 | // yield the current node's content, and then we use another for..of loop
296 | // to iterate over all the child nodes of our current node and yield all of each
297 | // child's content too.
298 |
299 | *[Symbol.iterator]() {
300 | yield this.content;
301 | for (let child of this.children) {
302 | yield* child;
303 | }
304 | }
305 | }
306 |
307 | // We create an array of child comments
308 |
309 | const children = [
310 | new Comment('will', 'good comment', []),
311 | new Comment('jaffathecake', 'bad comment', []),
312 | new Comment('Annonymous', 'meh', [])
313 | ];
314 |
315 | // We Create our tree structure, with a top level comment and then use our array of child comments.
316 |
317 | const tree = new Comment('Dude1000', 'Great post!', children);
318 |
319 | const myTree = [];
320 |
321 | // Here we iterate over our tree and push all the values to our new content & authors array.
322 |
323 | for (let value of tree) {
324 | myTree.push(value);
325 | }
326 |
327 | console.log(myTree);
328 | console.log(tree);
329 |
330 | })();
--------------------------------------------------------------------------------
/S16-generators/generators.md:
--------------------------------------------------------------------------------
1 | # Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.
2 |
3 | - Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.
4 |
5 | Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator's next() method is called, the generator function's body is executed until the first yield expression, which specifies the value to be returned from the iterator or, with yield*, delegates to another generator function. The next() method returns an object with a value property containing the yielded value and a done property which indicates whether the generator has yielded its last value as a boolean. Calling the next() method with an argument will resume the generator function execution, replacing the yield statement where execution was paused with the argument from next().
--------------------------------------------------------------------------------
/S16-generators/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S17-promises_and_fetch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | es6
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/S17-promises_and_fetch/promises_and_fetch.js:
--------------------------------------------------------------------------------
1 | // Promises and Fetch
2 |
3 | // The Promise object is used for asynchronous computations.
4 |
5 | // A Promise represents a value which may be available now, or in the future, or never.
6 |
7 | // The three states of promises:
8 |
9 | // - 'unresolved' - waiting for something to finish
10 | // - 'resolved' - something finished and it went okay
11 | // - 'rejected' - something finished and it went wrong
12 |
13 | // Promises allow us to assign a callback function to execute
14 | // when the promise returns a status of 'resolved' or 'rejected'.
15 |
16 | {
17 | let promise = new Promise((resolve, reject) => {
18 |
19 | // resolve(); // .then() functions are executed
20 |
21 | // reject(); // .catch() functions are executed.
22 |
23 | setTimeout(() => {
24 | resolve();
25 | }, 3000);
26 |
27 | });
28 |
29 | promise
30 | .then(() => console.log('finally finished!'))
31 | .then(() => console.log('and then I ran!'))
32 | .catch(() => console.log('something went wrong!'));
33 | }
34 |
35 | {
36 | const url = "https://jsonplaceholder.typicode.com/posts123456/";
37 |
38 | // The Fetch API provides an interface for fetching resources (including across the network).
39 | // It will seem familiar to anyone who has used XMLHttpRequest, but the new
40 | // API provides a more powerful and flexible feature set.
41 |
42 | // If the server returns a status code higher than 300, it does NOT enter the catch case
43 | // when we use fetch.
44 |
45 | // This is not the same as any other ajax library, where if the promise fails it will
46 | // enter the catch phase.
47 |
48 | // Fetch only enters the catch case when the network request fails to be issued at all.
49 |
50 | fetch(url)
51 | .then(response => console.log(response))
52 | .catch(error => console.log('BAD', error));
53 | }
--------------------------------------------------------------------------------
/S17-promises_and_fetch/promises_and_fetch.md:
--------------------------------------------------------------------------------
1 | # Promises and Fetch
2 |
3 | - The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.
4 |
5 | - The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set.
--------------------------------------------------------------------------------