Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- ES6 tips and tricks to make your code cleaner, shorter, and easier to read!
- On first step, we talk about constants or maybe we said const,
- const doesn't make the variable immutable, just locks its assignment.
- If you have a complex assignment (object or array), then the value can still be modified.
- */
- {
- const d = [1, 2, 3, 4];
- const dave = { name: 'David Jones', age: 32 };
- d.push(5);
- dave.job = "salesman";
- console.log(d); // [1, 2, 3, 4, 5]
- console.log(dave); // { age: 32, job: "salesman", name: 'David Jones'}}
- }
- /**
- Template literals make working with strings so much easier than before.
- They're started with a back tick, and can have variables inserted using ${variable}.
- Compare these two lines of code:
- **/
- {
- var fName = 'Peter', sName = 'Smith', age = 43, job = 'photographer';
- var a = 'Hi, I\'m ' + fName + ' ' + sName + ', I\'m ' + age + ' and work as a ' + job + '.';
- var b = `Hi, I'm ${fName} ${sName}, I'm ${age} and work as a ${job}.`;
- }
- /**
- This makes life far simpler and code easier to read. You can put anything inside of the curly braces: variables,
- equations, or function calls. I'll use these in examples throughout this article.
- Syntax Block scoping
- JavaScript has always been scoped by functions, which is why it had become common to wrap the whole of a JavaScript
- file in an empty immediately invoked function expression(IIFE).This is done to isolate all of the variables in the file,
- so there are no variable conflicts. Now, we have block scoping and two new variable declarations which are bound to a block.
- ‘Let’ Declaration
- This is similar to var but has a few notable differences.Because it's block scoped,
- a new variable with the same name can be declared without affecting outer variables.
- **/
- {
- var a = 'car';
- {
- let a = 5;
- console.log(a) // 5
- }
- console.log(a) // car
- }
- /**
- *
- Because its bound to a block scope, it solves this classic interview question:
- "what is output, and how would you get it to work as you expect?"
- *
- **/
- {
- for (var i = 1; i < 5; i++) {
- setTimeout(() => {
- console.log(i);
- }, 1000);
- }
- }
- /*
- In this case it outputs "5 5 5 5 5" because the variable i changes on each iteration.
- If you switch out the var for let then everything changes.
- Now, each loop creates a new block scope with the value for i bound to that loop.It is though you've written:
- */
- {
- let i = 1; setTimeout(() => { console.log(i) }, 1000)
- let i = 2; setTimeout(() => { console.log(i) }, 1000)
- let i = 3; setTimeout(() => { console.log(i) }, 1000)
- let i = 4; setTimeout(() => { console.log(i) }, 1000)
- let i = 5; setTimeout(() => { console.log(i) }, 1000)
- }
- // Another difference between var and let is that let isn't hoisted as var is.
- {
- console.log(a); // undefined
- console.log(b); // ReferenceError
- var a = 'car';
- let b = 5;
- }
- /*
- Because of its tighter scoping and more predictable behaviour,
- some people have said that you should use let instead of var,
- except where you specifically need the hoisting or looser scoping of the var declaration.
- Problem with block scoping functions
- Function declarations are now specified to be bound to block scoping.
- */
- {
- bar(); // works
- function bar() { return console.log( 4 * 2 ) }
- bar(); // doesn't work
- }
- /*
- The problem comes when you declare a function inside an if statement.
- Consider this:
- */
- {
- if (something) {
- function baz() { console.log('I passed') }
- }
- else { function baz() { console.log('I didn\'t pass') } }
- baz();
- }
- /*
- Before ES6, both function declarations would have been hoisted and the result would have been
- 'I didn\'t pass' no matter what something was.
- Now we get 'ReferenceError', as baz is always bound by the block scope.
- Spread
- ES6 introduces the ...operator, which is referred to as the ‘spread operator’.
- It has two main uses: spreading an array or object into a new array or object,
- and joining multiple parameters into an array.
- The first use case is the one you'll probably encounter most, so we’ll look at that first.
- */
- {
- let a = [3, 4, 5];
- let b = [1, 2, ...a, 6];
- console.log(b); // [1, 2, 3, 4, 5, 6]
- }
- // This can be very useful for passing in a set of variables to a function from an array.
- {
- function foo(a, b, c) {
- console.log(`a = ${a}, b = ${b}, c = ${c}`)
- }
- let data = [5, 15, 2];
- let arr = [4, 12, 15, 16]
- foo(...data); // a=5, b=15, c=2
- foo(arr) // a = 4,12,15,16, b = undefined, c = undefined
- foo(...arr) // a = 4, b = 12, c = 15
- }
- /*
- *
- An object can also be spread, inputting each of the key value pairs into the new object.
- (Object spread is actually in stage 4 of proposal and will be officially in ES2018.
- Its only supported by Chrome 60 or later, Firefox 55 or later, and Node 6.4.0 or later)
- *
- */
- {
- let car = { type: 'vehicle ', wheels: 4 };
- let fordGt = { make: 'Ford', ...car, model: 'GT' };
- console.log(fordGt); // {make: 'Ford', model: 'GT', type: 'vehicle', wheels: 4}
- }
- /*
- *
- Another feature of the spread operator is that it creates a new array or object.
- The example below creates a new array for b, but c just refers to the same array.
- *
- */
- {
- let a = [1, 2, 3];
- let b = [...a];
- let c = a; b.push(4);
- console.log(a); // [1, 2, 3]
- console.log(b); // [1, 2, 3, 4] referencing different arrays
- c.push(5);
- console.log(a); // [1, 2, 3, 5]
- console.log(c); // [1, 2, 3, 5] referencing the same array
- }
- /*
- The second use case is gathering variables together into an array.
- This is very useful for when you don’t know how many variables are being passed to a function.
- */
- {
- function foo(...args) { console.log(args); }
- foo('car', 54, 'tree'); // [ 'car', 54, 'tree' ]
- }
- /*
- Default Parameters
- Functions can now be defined with default parameters.
- Missing or undefined values are initialized with the default value.
- Just be careful — because null and false values are coerced to 0.
- */
- {
- function foo(a = 5, b = 10) { console.log(a + b); }
- foo(); // 15
- foo( 7, 12 ); // 19
- foo( undefined, 8 ); // 13
- foo( 8 ); // 18
- foo( null ); // 10 as null is coerced to 0
- }
- // The default values can be more than just values — they can also be expressions or functions.
- {
- function foo(a) { return a * 4; }
- function bar(x = 2, y = x + 4, z = foo(x)) { console.log([x, y, z]); }
- bar(); // [ 2, 6, 8 ]
- bar( 1, 2, 3 ); //[ 1, 2, 3 ]
- bar( 10, undefined, 3 ); // [ 10, 14, 3 ]
- }
- /*
- Destructuring is the process of taking apart the array or object on the left hand side of the equal sign.
- The array or object can come from a variable, function, or equation.
- */
- {
- let [a, b, c] = [6, 2, 9]; console.log(`a=${a}, b=${b}, c=${c}`); // a=6, b=2, c=9
- function foo() { return ['car', 'dog', 6]; }
- let [x, y, z] = foo();
- console.log(`x=${x}, y=${y}, z=${z}`); // x=car, y=dog, z=6
- }
- // With object destructuring, the keys of the object can be listed inside curly braces to extract that key - value pair.
- {
- function bar() { return { a: 1, b: 2, c: 3 }; }
- let { a, c } = bar();
- console.log(a); // 1
- console.log(c); // 3
- console.log(b); // undefined
- }
- /*
- Sometimes, you want to extract the values but assign them to a new variable.
- This is done using a 'key: variable' pairing on the left of the equals sign.
- */
- {
- function baz() { return { x: 'car', y: 'London', z: { name: 'John', age: 21 } }; }
- let { x: vehicle, y: city, z: { name: driver } } = baz();
- console.log(`I'm going to ${city} with ${driver} in their ${vehicle}.`); // I'm going to London with John in their car.
- }
- // Another thing that object destructuring allows is assigning a value to multiple variables.
- {
- let { x: first, x: second } = { x: 4 };
- console.log(first, second); // 4, 4
- }
- /*
- Object Literals and Concise Parameters
- When you are creating an object literal from variables, ES6 allows you to omit the key if it is the same as the variable name.
- */
- {
- let a = 4, b = 7;
- let c = { a: a, b: b };
- let concise = { a, b };
- console.log(c, concise) // {a: 4, b: 7}, {a: 4, b: 7}
- }
- // This can also be used in combination with destructuring to make your code much simpler and cleaner.
- {
- function foo() {
- return { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' }};
- }
- }
- // pre-ES6
- {
- let a = foo(), name = a.name, age = a.age, company = a.job.company;
- }
- // ES6 destructuring and concise parameters
- {
- let { name, age, job: {company}} = foo();
- console.log(foo());
- }
- /*
- It can also be used to destructure objects passed into functions.Method 1 and 2 are how you would have done it before ES6,
- and method 3 uses destructuring and concise parameters.
- */
- {
- let person = { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' } };
- // console.log(person);
- person.isActor === false;
- person.zipcode === '98750-345';
- person.last_name = 'Silveira';
- console.log(`This woman called ${person.name}, she's ${person.age} years old, works at ${person.job.title} in ${person.job.company}.`);
- // method 1
- function old1(person) {
- var yearOfBirth = 2018 - person.age;
- console.log( `${ person.name } works at ${ person.job.company } and was born in ${ yearOfBirth }.`);
- }
- // method 2
- function old1(person) {
- var age = person.age,
- yearOfBirth = 2018 - age,
- name = person.name,
- company = person.job.company;
- console.log( `${ name } works at ${ company } and was born in ${ yearOfBirth }.`);
- }
- // method 3
- function es6({ age, name, job: {company}}) {
- let thisYear = new Date();
- let yearOfBirth = thisYear - age;
- console.log( `${name} works at ${company} and was born in ${yearOfBirth}.`);
- }
- }
- /*
- Using ES6, we can extract the age, name and company without extra variable declaration.
- Dynamic Property Names
- ES6 adds the ability to create or add properties with dynamically assigned keys.
- */
- {
- let city = 'sheffield_';
- let a = { [city + 'population']: 350000 };
- a[city + 'county'] = 'South Yorkshire';
- console.log(a); // {sheffield_population: 350000, sheffield_county: 'South Yorkshire' }
- }
- /*
- Arrow Functions
- Arrow functions have two main aspects: their structure and their this binding.
- They can have a much simpler structure than traditional functions because they don't need the function key word,
- and they automatically return whatever is after the arrow.
- */
- {
- var foo = function (a, b) { return a * b; }
- let bar = (a, b) => a * b;
- console.log(bar(2,4), foo(2,4))
- }
- // If the function requires more than a simple calculation, curly braces can be used and the function returns whatever is returned from the block scope.
- {
- let baz = (c, d) => {
- let length = c.length + d.toString().length;
- let e = c.join(', ');
- return `${e} and there is a total length of ${length}`;
- }
- }
- // One of the most useful places for arrow functions is in array functions like.map, .forEach or.sort.
- {
- let arr = [5, 6, 7, 8, 'a'];
- let b = arr.map(item => item + 3);
- console.log(b); // [ 8, 9, 10, 11, 'a3' ]
- }
- // As well as having a shorter syntax, it also fixes the issues that often arose around the this binding behaviour. The fix with
- // pre-ES6 functions was to store the this reference, often as a self variable.
- {
- var clickController = {
- doSomething: function () {
- var self = this;
- btn.addEventListener('click', function () {
- self.doSomething()
- }, false);
- }
- };
- }
- /*
- This had to be done because the this binding is dynamic.This means that the this inside the event listener and the this
- inside the doSomething do not refer to the same thing.
- Inside arrow functions, the this binding is lexical, not dynamic.This was the main design feature of the arrow function.
- Whilst lexical this binding can be great, sometimes that's not what is wanted.
- */
- /**
- {
- let a = { oneThing: (a) => {
- let b = a * 2;
- this.otherThing(b);
- },
- otherThing: (b) => {...a}
- };
- a.oneThing(6);
- }
- **/
- /*
- When we use a.oneThing(6), the this.otherThing(b) reference fails as this doesn't point to the a object,
- but to the surrounding scope. If you are rewriting legacy code using ES6 syntax, this is something to watch out for.
- */
- /*
- *
- for … of Loops
- ES6 adds a way to iterate over each of the values in an array.This is different from the existing for ...
- in loop that loops over the key / index.
- *
- */
- {
- let a = ['a', 'b', 'c', 'd'];
- // let b = [ 1, 2, 3, 4]
- // ES6
- for ( var val of a ) {
- console.log( val );
- } // results on array "a" "b" "c" "d"
- // pre-ES6
- for ( var idx in a ) {
- console.log( idx );
- } // results on array 0 1 2 3
- }
- /*
- *
- Using the new for … of loop saves adding a let val = a[idx] inside each loop.
- Arrays, strings, generators and collections are all iterable in standard JavaScript.Plain objects can't normally be iterated over,
- unless you have defined an iterator for it.
- Number Literals
- ES5 code handled decimal and hexadecimal number formats well, but octal form wasn't specified. In fact, it was actively disallowed in strict mode.
- ES6 has added a new format, adding an o after the initial 0 to declare the number an octal.They've also added a binary format.
- */
- {
- Number(29) // 29
- Number(035) // 35 in old octal form.
- Number(0o35) // 29 in new octal form
- Number(0x1d) // 29 in hexadecimal
- Number(0b11101) // 29 in binary form
- }
- /**
- *
- And Much More…
- There is much, much more that ES6 offers us to make our code cleaner, shorter, easier to read and more robust.
- I aim to write a continuation of this article covering the less well known bits of ES6.
- If you can’t wait that long, have a read of Kyle Simpson’s You Don’t Know JS book on ES6, or check out this brilliant little website!
- Do you want to become a developer and get your first software job ? Download the 7 Steps to Becoming a Developer and Getting Your First Job.
- If you liked this and found it helpful, show your support by clapping away and subscribe to get more articles like this one!
- Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles,
- and interactive coding lessons - all freely available to the public. We also have thousands of freeCodeCamp study groups around the world.
- */
- // rest operator sample
- {
- function mostrandoNomeCompleto(){
- console.log('Qtde nomes: ', arguments.length);
- let nomeCompleto = "";
- Array.prototype.forEach.call(arguments, (valor) =>{
- nomeCompleto += " " + valor;
- });
- console.log(nomeCompleto);
- }
- mostrandoNomeCompleto('Wendel', 'Gomes', 'Santana');
- }
- // By using promises you can rewrite this code:
- {
- setTimeout(function() {
- console.log('I promised to run after 1s')
- setTimeout(function() {
- console.log('I promised to run after 2s')
- }, 1000)
- }, 1000)
- }
- // as
- {
- const wait = () => new Promise((resolve, reject) => {
- setTimeout(resolve, 1000)
- })
- wait().then(() => {
- console.log('I promised to run after 1s')
- return wait()
- })
- .then(() => console.log('I promised to run after 2s'))
- }
- // Class definition
- {
- class Person {
- constructor(name) {
- this.name = name
- }
- hello() {
- return 'Hello, I am ' + this.name + '.'
- }
- }
- class Actor extends Person {
- hello() {
- return super.hello() + ' I am an actor.'
- }
- }
- let tomCruise = new Actor('Tom Cruise')
- console.log(tomCruise.hello())
- }
- /* Numeros Primos */
- {
- let primes = [2, 3, 5, 7];
- // let primes = ;
- for(const value of primes) {
- console.log(value);
- }
- }
- /*
- *
- There are only 6 falsy values, everything else is truthy:
- false,
- 0,
- '', "" (Empty String),
- null,
- undefined,
- NaN
- *
- */
- {
- const number = 42;
- const string = '42';
- Number(string); // Coerces to number 42
- String(number); // Coerces to string '42'
- Boolean(string); // Coerces to boolean 1
- Boolean({}); // true
- Boolean([]); //true
- Boolean("0"); // true
- null == 0 // false
- }
- /*
- * Coercion
- */
- {
- console.log(1 + '2') // 1 coerces to '1', results = '12'
- console.log(1 + true) // true coerces to 1, results = 2
- console.log(1 + null) // null coerces to 0, results = 1
- console.log(1 + undefined) // undefined coerces to 0, results = 1
- console.log('abc' + undefined) // undefined coerces to 'undefined', results = 'abcundefined'
- console.log(1 < 2 < 3) // => true < 3 (left to right associativity) restuls, => 1 < 3 (coercion) => true
- console.log(1 > 2 > 3) // => false > 3 => 1 > 3 => false
- console.log(1 == '1') // true is a coercion
- console.log(1 === '1') // false
- }
- /*
- * Super()
- */
- {
- const anObject = { y: 'y', test: () => 'zoo' }
- const x = {
- __proto__: anObject,
- test() {
- return super.test() + 'x'
- }
- }
- console.log(x.test()) //zoox
- }
- /*
- * for/in and object keys
- */
- {
- const obj = {
- a: 1,
- b: 2,
- c: 3,
- d: 4
- }
- for (let elem in obj) {
- console.log( obj[elem] )
- } // 1 2 3 4
- for (let elem in obj) {
- console.log(`${elem} = ${obj[elem]}`);
- }
- const string = 'hello';
- for (let character in string) {
- console.log(string[character])
- } // h e l l o
- }
- /*
- *
- * Object Entries
- *
- */
- {
- console.log(Object.entries('Wendel Gomes Santana'));
- }
- /**
- *
- * Object x Map
- *
- */
- {
- let Vehicle = {
- type: "General",
- display: function(){console.log(this.type);}
- }
- let Car = Object.create(Vehicle); // create a new Car inherits from Vehicle
- Car.type = "Car"; // overwrite the property
- Car.display(); // "Car"
- Vehicle.display(); // still "General"
- }
- /*
- *
- * Class extending and constructor
- *
- */
- {
- class MyArray extends Array {
- // Overwrite species to the parent Array constructor
- static get [Symbol.species]() { return Array; }
- }
- let a = new MyArray(1,2,3);
- let mapped = a.map(x => x * x);
- console.log(mapped)
- console.log(mapped instanceof MyArray); // false
- console.log(mapped instanceof Array); // true
- }
- {
- class Cat {
- constructor(name) {
- this.name = name;
- }
- speak() {
- console.log(`${this.name} makes a noise.`);
- }
- }
- class Lion extends Cat {
- speak() {
- super.speak();
- console.log(`${this.name} roars.`);
- }
- }
- let l = new Lion('Fuzzy');
- l.speak();
- // Fuzzy makes a noise.
- // Fuzzy roars.
- }
- /*
- *
- * Testing empty elements in array. With JSON parsing
- *
- */
- {
- let arrLegal = JSON.parse('{"arr":["a","b","c"]}')
- console.log(arrLegal)
- let arrParse = JSON.parse('{"arr":["a",null,"c"]}')
- console.log(arrParse)
- let arrArrw = JSON.parse('{"arr":["a",undefined,"c"]}')
- console.log(arrArrw)
- // let arrFail = JSON.parse('{"arr":["a",,"c"]}')
- // console.log(arrFail)
- }
- /*
- *
- There's numerous ways to loop over arrays and objects in JavaScript, and the tradeoffs are a common cause of confusion.
- Some style guides go so far as to ban certain looping constructs. In this article,
- I'll describe the differences between iterating over an array with the 4 primary looping constructs:
- for (let i = 0; i < arr.length; ++i)
- arr.forEach((v, i) => { ... })
- for (let i in arr)
- for (const v of arr)
- I'll provide an overview of the difference between these looping constructs using several different edge cases.
- I'll also link to the relevant ESLint rules that you can use to enforce looping best practices in your projects.
- *
- */
- /*
- Syntactic Overview
- The for and for/in looping constructs give you access to the index in the array, not the actual element. For example,
- suppose you want to print out the values stored in the below array:
- */
- {
- const arr = ['a', 'b', 'c'];
- // With for and for/in, you need to print out arr[i]:
- for (let i = 0; i < arr.length; ++i) {
- console.log(arr[i]);
- }
- for (let i in arr) {
- console.log(arr[i]);
- }
- }
- /**
- With the other two constructs, forEach() and for/of, you get access to the array element itself.
- With forEach() you can access the array index i, with for/of you cannot.
- * */
- {
- arr.forEach((v, i) => console.log(v));
- for (const v of arr) {
- console.log(v);
- }
- }
- /**
- Non-Numeric Properties
- JavaScript arrays are objects. That means you can add string properties to your array, not just numbers.
- */
- {
- const arr = ['a', 'b', 'c'];
- typeof arr; // 'object'
- // Assign to a non-numeric property
- arr.test = 'bad';
- arr.test; // 'abc'
- arr[1] === arr['1']; // true, JavaScript arrays are just special objects
- // 3 of the 4 looping constructs ignore the non-numeric property. However, for/in will actually print out "bad":
- const arr = ['a', 'b', 'c'];
- arr.test = 'bad';
- // Prints "a, b, c, bad"
- for (let i in arr) {
- console.log(arr[i]);
- }
- }
- /**
- This is why iterating through an array using for/in is generally bad practice.
- The other looping constructs correctly ignore the num-numeric key:
- */
- {
- const arr = ['a', 'b', 'c'];
- arr.test = 'abc';
- // Prints "a, b, c"
- for (let i = 0; i < arr.length; ++i) {
- console.log(arr[i]);
- }
- // Prints "a, b, c"
- arr.forEach((el, i) => console.log(i, el));
- // Prints "a, b, c"
- for (const el of arr) {
- console.log(el);
- }
- }
- /**
- Takeaway: Avoid using for/in over an array unless you're certain you mean to iterate over non-numeric keys and inherited keys.
- Use the guard-for-in ESLint rule to disallow for/in.
- */
- /*
- *
- Empty Elements
- JavaScript arrays allow empty elements. The below array is syntactically valid and has length 3:
- *
- */
- {
- const arr = ['a',, 'c'];
- arr.length; // 3
- }
- /*
- *
- * What makes things even more confusing is that looping constructs treat ['a',, 'c'] differently from ['a', undefined, 'c'].
- * Below is how the 4 looping constructs handle ['a',, 'c'] with an empty element. for/in and for/each skip the empty element,
- * for and for/of do not.
- *
- */
- // Prints "a, undefined, c"
- for (let i = 0; i < arr.length; ++i) {
- console.log(arr[i]);
- }
- // Prints "a, c"
- arr.forEach(v => console.log(v));
- // Prints "a, c"
- for (let i in arr) {
- console.log(arr[i]);
- }
- // Prints "a, undefined, c"
- for (const v of arr) {
- console.log(v);
- }
- /**
- In case you're wondering, all 4 constructs print "a, undefined, c" for ['a', undefined, 'c'].
- *
- There's another way to add an empty element to an array:
- */
- // Equivalent to `['a', 'b', 'c',, 'e']`
- const arr = ['a', 'b', 'c'];
- arr[5] = 'e';
- /**
- forEach() and for/in skip empty elements in the array, for and for/of do not.
- The forEach() behavior may cause problems, however, holes in JavaScript arrays
- are generally rare because they are not supported in JSON:
- */
- // $ node
- JSON.parse('{"arr":["a","b","c"]}')
- // { arr: [ 'a', 'b', 'c' ] }
- JSON.parse('{"arr":["a",null,"c"]}')
- // { arr: [ 'a', null, 'c' ] }
- JSON.parse('{"arr":["a",,"c"]}')
- // SyntaxError: Unexpected token , in JSON at position 12
- /**
- So you don't have to worry about holes in user data, unless you give your users access to the full JavaScript runtime.
- Takeaway: for/in and forEach() skip empty elements, also known as "holes", in the array.
- There's rarely any reason to treat holes as a special case as opposed to treating the index as having value undefined.
- If the special behavior with holes causes you concern, below is an example .eslintrc.yml file that disallows calling forEach().
- *
- parserOptions:
- ecmaVersion: 2018
- rules:
- no-restricted-syntax:
- - error
- - selector: CallExpression[callee.property.name="forEach"]
- message: Do not use `forEach()`, use `for/of` instead
- */
- /**
- *
- Function Context
- Function context is a fancy way of saying what this refers to. for, for/in, and for/of retain the outside scope's value of this,
- but the forEach() callback will have a different this unless you use an arrow function.
- *
- **/
- 'use strict';
- const arr = ['a'];
- // Prints "undefined"
- arr.forEach(function() {
- console.log(this);
- });
- /**
- *
- Takeaway: Use arrow functions with forEach().
- Use the no-arrow-callback ESLint rule to require arrow functions for all callbacks that don't use this.
- *
- Async/Await and Generators
- Another edge case with forEach() is that it doesn't quite work right with async/await or generators.
- If your forEach() callback is synchronous then it doesn't matter, but you can't use await within a forEach() callback:
- */
- async function run() {
- const arr = ['a', 'b', 'c'];
- arr.forEach(el => {
- // SyntaxError
- await new Promise(resolve => setTimeout(resolve, 1000));
- console.log(el);
- });
- }
- /**
- * You can't use yield either:
- */
- function* run() {
- const arr = ['a', 'b', 'c'];
- arr.forEach(el => {
- // SyntaxError
- yield new Promise(resolve => setTimeout(resolve, 1000));
- console.log(el);
- });
- }
- /*
- *
- *The above examples work fine with for/of:
- *
- */
- async function asyncFn() {
- const arr = ['a', 'b', 'c'];
- for (const el of arr) {
- await new Promise(resolve => setTimeout(resolve, 1000));
- console.log(el);
- }
- }
- function* generatorFn() {
- const arr = ['a', 'b', 'c'];
- for (const el of arr) {
- yield new Promise(resolve => setTimeout(resolve, 1000));
- console.log(el);
- }
- }
- /**
- *
- * Even if you mark your forEach() callback as async, you're in for substantial headache in trying to get async forEach()
- * to work in series and pause your async function. For example, the below script will print 0-9 in reverse order.
- *
- */
- async function print(n) {
- // Wait 1 second before printing 0, 0.9 seconds before printing 1, etc.
- await new Promise(resolve => setTimeout(() => resolve(), 1000 - n * 100));
- // Will usually print 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 but order is not strictly
- // guaranteed.
- console.log(n);
- }
- async function test() {
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(print);
- }
- test();
- /**
- Takeaway: If you're using async/await or generators, remember that forEach() is syntactic sugar. Like sugar,
- it should be used sparingly and shouldn't be used for everything.
- *
- * The Aggregation Mixins is a manner to extend multiple classes on javascript
- *
- */
- {
- const aggregation = (baseClass, ...mixins) => {
- class base extends baseClass {
- constructor (...args) {
- super(...args);
- mixins.forEach((mixin) => {
- copyProps(this,(new mixin));
- });
- }
- }
- let copyProps = (target, source) => { // this function copies all properties and symbols, filtering out some special ones
- Object.getOwnPropertyNames(source)
- .concat(Object.getOwnPropertySymbols(source))
- .forEach((prop) => {
- if (!prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
- Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
- })
- }
- mixins.forEach((mixin) => { // outside contructor() to allow aggregation(A,B,C).staticFunction() to be called etc.
- copyProps(base.prototype, mixin.prototype);
- copyProps(base, mixin);
- });
- return base;
- }
- // Sample with a Person Object
- class Person{
- constructor(n){
- this.name=n;
- }
- }
- class Male{
- constructor(s='male'){
- this.sex=s;
- }
- }
- class Child{
- constructor(a=12){
- this.age=a;
- }
- tellAge(){console.log(this.name+' is '+this.age+' years old.');}
- }
- class Boy extends aggregation(Person,Male,Child){}
- let m = new Boy('Mike');
- m.tellAge(); // Mike is 12 years old.
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement