Advertisement
Guest User

Untitled

a guest
Sep 15th, 2019
194
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.50 KB | None | 0 0
  1. /*
  2. ES6 tips and tricks to make your code cleaner, shorter, and easier to read!
  3.  
  4. On first step, we talk about constants or maybe we said const,
  5. const doesn't make the variable immutable, just locks its assignment.
  6. If you have a complex assignment (object or array), then the value can still be modified.
  7. */
  8.  
  9. {
  10. const d = [1, 2, 3, 4];
  11. const dave = { name: 'David Jones', age: 32 };
  12. d.push(5);
  13. dave.job = "salesman";
  14. console.log(d); // [1, 2, 3, 4, 5]
  15. console.log(dave); // { age: 32, job: "salesman", name: 'David Jones'}}
  16. }
  17.  
  18. /**
  19. Template literals make working with strings so much easier than before.
  20. They're started with a back tick, and can have variables inserted using ${variable}.
  21. Compare these two lines of code:
  22. **/
  23.  
  24. {
  25. var fName = 'Peter', sName = 'Smith', age = 43, job = 'photographer';
  26. var a = 'Hi, I\'m ' + fName + ' ' + sName + ', I\'m ' + age + ' and work as a ' + job + '.';
  27. var b = `Hi, I'm ${fName} ${sName}, I'm ${age} and work as a ${job}.`;
  28. }
  29.  
  30. /**
  31. This makes life far simpler and code easier to read. You can put anything inside of the curly braces: variables,
  32. equations, or function calls. I'll use these in examples throughout this article.
  33. Syntax Block scoping
  34. JavaScript has always been scoped by functions, which is why it had become common to wrap the whole of a JavaScript
  35. file in an empty immediately invoked function expression(IIFE).This is done to isolate all of the variables in the file,
  36. so there are no variable conflicts. Now, we have block scoping and two new variable declarations which are bound to a block.
  37. ‘Let’ Declaration
  38. This is similar to var but has a few notable differences.Because it's block scoped,
  39. a new variable with the same name can be declared without affecting outer variables.
  40. **/
  41.  
  42. {
  43. var a = 'car';
  44. {
  45. let a = 5;
  46. console.log(a) // 5
  47. }
  48. console.log(a) // car
  49. }
  50.  
  51.  
  52. /**
  53. *
  54. Because its bound to a block scope, it solves this classic interview question:
  55. "what is output, and how would you get it to work as you expect?"
  56. *
  57. **/
  58.  
  59. {
  60. for (var i = 1; i < 5; i++) {
  61. setTimeout(() => {
  62. console.log(i);
  63. }, 1000);
  64. }
  65. }
  66.  
  67. /*
  68. In this case it outputs "5 5 5 5 5" because the variable i changes on each iteration.
  69. If you switch out the var for let then everything changes.
  70. Now, each loop creates a new block scope with the value for i bound to that loop.It is though you've written:
  71. */
  72.  
  73. {
  74. let i = 1; setTimeout(() => { console.log(i) }, 1000)
  75. let i = 2; setTimeout(() => { console.log(i) }, 1000)
  76. let i = 3; setTimeout(() => { console.log(i) }, 1000)
  77. let i = 4; setTimeout(() => { console.log(i) }, 1000)
  78. let i = 5; setTimeout(() => { console.log(i) }, 1000)
  79. }
  80.  
  81. // Another difference between var and let is that let isn't hoisted as var is.
  82.  
  83. {
  84. console.log(a); // undefined
  85. console.log(b); // ReferenceError
  86. var a = 'car';
  87. let b = 5;
  88. }
  89.  
  90. /*
  91. Because of its tighter scoping and more predictable behaviour,
  92. some people have said that you should use let instead of var,
  93. except where you specifically need the hoisting or looser scoping of the var declaration.
  94. Problem with block scoping functions
  95. Function declarations are now specified to be bound to block scoping.
  96. */
  97.  
  98. {
  99. bar(); // works
  100. function bar() { return console.log( 4 * 2 ) }
  101. bar(); // doesn't work
  102. }
  103.  
  104. /*
  105. The problem comes when you declare a function inside an if statement.
  106. Consider this:
  107. */
  108.  
  109. {
  110. if (something) {
  111. function baz() { console.log('I passed') }
  112. }
  113. else { function baz() { console.log('I didn\'t pass') } }
  114. baz();
  115. }
  116.  
  117. /*
  118. Before ES6, both function declarations would have been hoisted and the result would have been
  119. 'I didn\'t pass' no matter what something was.
  120. Now we get 'ReferenceError', as baz is always bound by the block scope.
  121. Spread
  122. ES6 introduces the ...operator, which is referred to as the ‘spread operator’.
  123. It has two main uses: spreading an array or object into a new array or object,
  124. and joining multiple parameters into an array.
  125. The first use case is the one you'll probably encounter most, so we’ll look at that first.
  126. */
  127.  
  128. {
  129. let a = [3, 4, 5];
  130. let b = [1, 2, ...a, 6];
  131. console.log(b); // [1, 2, 3, 4, 5, 6]
  132. }
  133.  
  134. // This can be very useful for passing in a set of variables to a function from an array.
  135.  
  136. {
  137. function foo(a, b, c) {
  138. console.log(`a = ${a}, b = ${b}, c = ${c}`)
  139. }
  140. let data = [5, 15, 2];
  141. let arr = [4, 12, 15, 16]
  142. foo(...data); // a=5, b=15, c=2
  143. foo(arr) // a = 4,12,15,16, b = undefined, c = undefined
  144. foo(...arr) // a = 4, b = 12, c = 15
  145. }
  146.  
  147. /*
  148. *
  149. An object can also be spread, inputting each of the key value pairs into the new object.
  150. (Object spread is actually in stage 4 of proposal and will be officially in ES2018.
  151. Its only supported by Chrome 60 or later, Firefox 55 or later, and Node 6.4.0 or later)
  152. *
  153. */
  154.  
  155. {
  156. let car = { type: 'vehicle ', wheels: 4 };
  157. let fordGt = { make: 'Ford', ...car, model: 'GT' };
  158. console.log(fordGt); // {make: 'Ford', model: 'GT', type: 'vehicle', wheels: 4}
  159. }
  160.  
  161. /*
  162. *
  163. Another feature of the spread operator is that it creates a new array or object.
  164. The example below creates a new array for b, but c just refers to the same array.
  165. *
  166. */
  167.  
  168. {
  169. let a = [1, 2, 3];
  170. let b = [...a];
  171. let c = a; b.push(4);
  172. console.log(a); // [1, 2, 3]
  173. console.log(b); // [1, 2, 3, 4] referencing different arrays
  174. c.push(5);
  175. console.log(a); // [1, 2, 3, 5]
  176. console.log(c); // [1, 2, 3, 5] referencing the same array
  177. }
  178.  
  179. /*
  180. The second use case is gathering variables together into an array.
  181. This is very useful for when you don’t know how many variables are being passed to a function.
  182. */
  183.  
  184. {
  185. function foo(...args) { console.log(args); }
  186. foo('car', 54, 'tree'); // [ 'car', 54, 'tree' ]
  187. }
  188.  
  189. /*
  190. Default Parameters
  191. Functions can now be defined with default parameters.
  192. Missing or undefined values are initialized with the default value.
  193. Just be careful — because null and false values are coerced to 0.
  194. */
  195.  
  196. {
  197. function foo(a = 5, b = 10) { console.log(a + b); }
  198. foo(); // 15
  199. foo( 7, 12 ); // 19
  200. foo( undefined, 8 ); // 13
  201. foo( 8 ); // 18
  202. foo( null ); // 10 as null is coerced to 0
  203. }
  204.  
  205. // The default values can be more than just values — they can also be expressions or functions.
  206.  
  207. {
  208. function foo(a) { return a * 4; }
  209. function bar(x = 2, y = x + 4, z = foo(x)) { console.log([x, y, z]); }
  210. bar(); // [ 2, 6, 8 ]
  211. bar( 1, 2, 3 ); //[ 1, 2, 3 ]
  212. bar( 10, undefined, 3 ); // [ 10, 14, 3 ]
  213. }
  214.  
  215. /*
  216. Destructuring is the process of taking apart the array or object on the left hand side of the equal sign.
  217. The array or object can come from a variable, function, or equation.
  218. */
  219.  
  220. {
  221. let [a, b, c] = [6, 2, 9]; console.log(`a=${a}, b=${b}, c=${c}`); // a=6, b=2, c=9
  222. function foo() { return ['car', 'dog', 6]; }
  223. let [x, y, z] = foo();
  224. console.log(`x=${x}, y=${y}, z=${z}`); // x=car, y=dog, z=6
  225. }
  226.  
  227. // With object destructuring, the keys of the object can be listed inside curly braces to extract that key - value pair.
  228.  
  229. {
  230. function bar() { return { a: 1, b: 2, c: 3 }; }
  231. let { a, c } = bar();
  232. console.log(a); // 1
  233. console.log(c); // 3
  234. console.log(b); // undefined
  235. }
  236.  
  237. /*
  238. Sometimes, you want to extract the values but assign them to a new variable.
  239. This is done using a 'key: variable' pairing on the left of the equals sign.
  240. */
  241.  
  242. {
  243. function baz() { return { x: 'car', y: 'London', z: { name: 'John', age: 21 } }; }
  244. let { x: vehicle, y: city, z: { name: driver } } = baz();
  245. console.log(`I'm going to ${city} with ${driver} in their ${vehicle}.`); // I'm going to London with John in their car.
  246. }
  247.  
  248. // Another thing that object destructuring allows is assigning a value to multiple variables.
  249.  
  250. {
  251. let { x: first, x: second } = { x: 4 };
  252. console.log(first, second); // 4, 4
  253. }
  254.  
  255. /*
  256. Object Literals and Concise Parameters
  257. 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.
  258. */
  259.  
  260. {
  261. let a = 4, b = 7;
  262. let c = { a: a, b: b };
  263. let concise = { a, b };
  264. console.log(c, concise) // {a: 4, b: 7}, {a: 4, b: 7}
  265. }
  266.  
  267. // This can also be used in combination with destructuring to make your code much simpler and cleaner.
  268.  
  269. {
  270. function foo() {
  271. return { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' }};
  272. }
  273. }
  274.  
  275. // pre-ES6
  276. {
  277. let a = foo(), name = a.name, age = a.age, company = a.job.company;
  278. }
  279.  
  280. // ES6 destructuring and concise parameters
  281. {
  282. let { name, age, job: {company}} = foo();
  283. console.log(foo());
  284. }
  285.  
  286. /*
  287. It can also be used to destructure objects passed into functions.Method 1 and 2 are how you would have done it before ES6,
  288. and method 3 uses destructuring and concise parameters.
  289. */
  290.  
  291. {
  292. let person = { name: 'Anna', age: 56, job: { company: 'Tesco', title: 'Manager' } };
  293. // console.log(person);
  294. person.isActor === false;
  295. person.zipcode === '98750-345';
  296. person.last_name = 'Silveira';
  297. console.log(`This woman called ${person.name}, she's ${person.age} years old, works at ${person.job.title} in ${person.job.company}.`);
  298.  
  299. // method 1
  300. function old1(person) {
  301. var yearOfBirth = 2018 - person.age;
  302. console.log( `${ person.name } works at ${ person.job.company } and was born in ${ yearOfBirth }.`);
  303. }
  304.  
  305. // method 2
  306. function old1(person) {
  307. var age = person.age,
  308. yearOfBirth = 2018 - age,
  309. name = person.name,
  310. company = person.job.company;
  311. console.log( `${ name } works at ${ company } and was born in ${ yearOfBirth }.`);
  312. }
  313.  
  314. // method 3
  315. function es6({ age, name, job: {company}}) {
  316. let thisYear = new Date();
  317. let yearOfBirth = thisYear - age;
  318. console.log( `${name} works at ${company} and was born in ${yearOfBirth}.`);
  319. }
  320. }
  321.  
  322. /*
  323. Using ES6, we can extract the age, name and company without extra variable declaration.
  324. Dynamic Property Names
  325. ES6 adds the ability to create or add properties with dynamically assigned keys.
  326. */
  327.  
  328. {
  329. let city = 'sheffield_';
  330. let a = { [city + 'population']: 350000 };
  331. a[city + 'county'] = 'South Yorkshire';
  332. console.log(a); // {sheffield_population: 350000, sheffield_county: 'South Yorkshire' }
  333. }
  334.  
  335. /*
  336. Arrow Functions
  337. Arrow functions have two main aspects: their structure and their this binding.
  338. They can have a much simpler structure than traditional functions because they don't need the function key word,
  339. and they automatically return whatever is after the arrow.
  340. */
  341.  
  342. {
  343. var foo = function (a, b) { return a * b; }
  344. let bar = (a, b) => a * b;
  345. console.log(bar(2,4), foo(2,4))
  346. }
  347.  
  348. // 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.
  349.  
  350. {
  351. let baz = (c, d) => {
  352. let length = c.length + d.toString().length;
  353. let e = c.join(', ');
  354. return `${e} and there is a total length of ${length}`;
  355. }
  356. }
  357.  
  358. // One of the most useful places for arrow functions is in array functions like.map, .forEach or.sort.
  359.  
  360. {
  361. let arr = [5, 6, 7, 8, 'a'];
  362. let b = arr.map(item => item + 3);
  363. console.log(b); // [ 8, 9, 10, 11, 'a3' ]
  364. }
  365.  
  366. // As well as having a shorter syntax, it also fixes the issues that often arose around the this binding behaviour. The fix with
  367. // pre-ES6 functions was to store the this reference, often as a self variable.
  368.  
  369. {
  370. var clickController = {
  371. doSomething: function () {
  372. var self = this;
  373. btn.addEventListener('click', function () {
  374. self.doSomething()
  375. }, false);
  376. }
  377. };
  378. }
  379.  
  380. /*
  381. This had to be done because the this binding is dynamic.This means that the this inside the event listener and the this
  382. inside the doSomething do not refer to the same thing.
  383. Inside arrow functions, the this binding is lexical, not dynamic.This was the main design feature of the arrow function.
  384. Whilst lexical this binding can be great, sometimes that's not what is wanted.
  385. */
  386.  
  387. /**
  388. {
  389. let a = { oneThing: (a) => {
  390. let b = a * 2;
  391. this.otherThing(b);
  392. },
  393. otherThing: (b) => {...a}
  394. };
  395. a.oneThing(6);
  396. }
  397. **/
  398.  
  399. /*
  400. When we use a.oneThing(6), the this.otherThing(b) reference fails as this doesn't point to the a object,
  401. but to the surrounding scope. If you are rewriting legacy code using ES6 syntax, this is something to watch out for.
  402. */
  403.  
  404. /*
  405. *
  406. for … of Loops
  407. ES6 adds a way to iterate over each of the values in an array.This is different from the existing for ...
  408. in loop that loops over the key / index.
  409. *
  410. */
  411.  
  412. {
  413. let a = ['a', 'b', 'c', 'd'];
  414. // let b = [ 1, 2, 3, 4]
  415.  
  416. // ES6
  417. for ( var val of a ) {
  418. console.log( val );
  419. } // results on array "a" "b" "c" "d"
  420.  
  421. // pre-ES6
  422. for ( var idx in a ) {
  423. console.log( idx );
  424. } // results on array 0 1 2 3
  425. }
  426.  
  427. /*
  428. *
  429. Using the new for … of loop saves adding a let val = a[idx] inside each loop.
  430.  
  431. Arrays, strings, generators and collections are all iterable in standard JavaScript.Plain objects can't normally be iterated over,
  432. unless you have defined an iterator for it.
  433.  
  434. Number Literals
  435. ES5 code handled decimal and hexadecimal number formats well, but octal form wasn't specified. In fact, it was actively disallowed in strict mode.
  436. 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.
  437.  
  438. */
  439.  
  440. {
  441. Number(29) // 29
  442. Number(035) // 35 in old octal form.
  443. Number(0o35) // 29 in new octal form
  444. Number(0x1d) // 29 in hexadecimal
  445. Number(0b11101) // 29 in binary form
  446. }
  447.  
  448. /**
  449. *
  450. And Much More…
  451. There is much, much more that ES6 offers us to make our code cleaner, shorter, easier to read and more robust.
  452. I aim to write a continuation of this article covering the less well known bits of ES6.
  453. 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!
  454. 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.
  455. If you liked this and found it helpful, show your support by clapping away and subscribe to get more articles like this one!
  456. Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles,
  457. and interactive coding lessons - all freely available to the public. We also have thousands of freeCodeCamp study groups around the world.
  458. */
  459.  
  460. // rest operator sample
  461.  
  462. {
  463. function mostrandoNomeCompleto(){
  464. console.log('Qtde nomes: ', arguments.length);
  465. let nomeCompleto = "";
  466. Array.prototype.forEach.call(arguments, (valor) =>{
  467. nomeCompleto += " " + valor;
  468. });
  469. console.log(nomeCompleto);
  470. }
  471.  
  472. mostrandoNomeCompleto('Wendel', 'Gomes', 'Santana');
  473. }
  474.  
  475. // By using promises you can rewrite this code:
  476.  
  477. {
  478. setTimeout(function() {
  479. console.log('I promised to run after 1s')
  480. setTimeout(function() {
  481. console.log('I promised to run after 2s')
  482. }, 1000)
  483. }, 1000)
  484. }
  485.  
  486. // as
  487.  
  488. {
  489. const wait = () => new Promise((resolve, reject) => {
  490. setTimeout(resolve, 1000)
  491. })
  492.  
  493. wait().then(() => {
  494. console.log('I promised to run after 1s')
  495. return wait()
  496. })
  497. .then(() => console.log('I promised to run after 2s'))
  498. }
  499.  
  500. // Class definition
  501.  
  502. {
  503. class Person {
  504. constructor(name) {
  505. this.name = name
  506. }
  507.  
  508. hello() {
  509. return 'Hello, I am ' + this.name + '.'
  510. }
  511. }
  512.  
  513. class Actor extends Person {
  514. hello() {
  515. return super.hello() + ' I am an actor.'
  516. }
  517. }
  518.  
  519. let tomCruise = new Actor('Tom Cruise')
  520. console.log(tomCruise.hello())
  521. }
  522.  
  523. /* Numeros Primos */
  524.  
  525. {
  526.  
  527. let primes = [2, 3, 5, 7];
  528. // let primes = ;
  529.  
  530. for(const value of primes) {
  531. console.log(value);
  532. }
  533. }
  534.  
  535. /*
  536. *
  537. There are only 6 falsy values, everything else is truthy:
  538. false,
  539. 0,
  540. '', "" (Empty String),
  541. null,
  542. undefined,
  543. NaN
  544. *
  545. */
  546.  
  547. {
  548. const number = 42;
  549. const string = '42';
  550. Number(string); // Coerces to number 42
  551. String(number); // Coerces to string '42'
  552. Boolean(string); // Coerces to boolean 1
  553. Boolean({}); // true
  554. Boolean([]); //true
  555. Boolean("0"); // true
  556. null == 0 // false
  557. }
  558.  
  559. /*
  560. * Coercion
  561. */
  562.  
  563. {
  564. console.log(1 + '2') // 1 coerces to '1', results = '12'
  565. console.log(1 + true) // true coerces to 1, results = 2
  566. console.log(1 + null) // null coerces to 0, results = 1
  567. console.log(1 + undefined) // undefined coerces to 0, results = 1
  568. console.log('abc' + undefined) // undefined coerces to 'undefined', results = 'abcundefined'
  569. console.log(1 < 2 < 3) // => true < 3 (left to right associativity) restuls, => 1 < 3 (coercion) => true
  570. console.log(1 > 2 > 3) // => false > 3 => 1 > 3 => false
  571. console.log(1 == '1') // true is a coercion
  572. console.log(1 === '1') // false
  573. }
  574.  
  575. /*
  576. * Super()
  577. */
  578.  
  579. {
  580. const anObject = { y: 'y', test: () => 'zoo' }
  581. const x = {
  582. __proto__: anObject,
  583. test() {
  584. return super.test() + 'x'
  585. }
  586. }
  587. console.log(x.test()) //zoox
  588. }
  589.  
  590. /*
  591. * for/in and object keys
  592. */
  593. {
  594. const obj = {
  595. a: 1,
  596. b: 2,
  597. c: 3,
  598. d: 4
  599. }
  600.  
  601. for (let elem in obj) {
  602. console.log( obj[elem] )
  603. } // 1 2 3 4
  604.  
  605. for (let elem in obj) {
  606. console.log(`${elem} = ${obj[elem]}`);
  607. }
  608.  
  609. const string = 'hello';
  610. for (let character in string) {
  611. console.log(string[character])
  612. } // h e l l o
  613.  
  614. }
  615.  
  616. /*
  617. *
  618. * Object Entries
  619. *
  620. */
  621. {
  622. console.log(Object.entries('Wendel Gomes Santana'));
  623. }
  624.  
  625. /**
  626. *
  627. * Object x Map
  628. *
  629. */
  630. {
  631. let Vehicle = {
  632. type: "General",
  633. display: function(){console.log(this.type);}
  634. }
  635. let Car = Object.create(Vehicle); // create a new Car inherits from Vehicle
  636. Car.type = "Car"; // overwrite the property
  637. Car.display(); // "Car"
  638. Vehicle.display(); // still "General"
  639. }
  640.  
  641. /*
  642. *
  643. * Class extending and constructor
  644. *
  645. */
  646.  
  647. {
  648. class MyArray extends Array {
  649. // Overwrite species to the parent Array constructor
  650. static get [Symbol.species]() { return Array; }
  651. }
  652. let a = new MyArray(1,2,3);
  653. let mapped = a.map(x => x * x);
  654. console.log(mapped)
  655. console.log(mapped instanceof MyArray); // false
  656. console.log(mapped instanceof Array); // true
  657. }
  658.  
  659. {
  660. class Cat {
  661. constructor(name) {
  662. this.name = name;
  663. }
  664.  
  665. speak() {
  666. console.log(`${this.name} makes a noise.`);
  667. }
  668. }
  669.  
  670. class Lion extends Cat {
  671. speak() {
  672. super.speak();
  673. console.log(`${this.name} roars.`);
  674. }
  675. }
  676.  
  677. let l = new Lion('Fuzzy');
  678. l.speak();
  679. // Fuzzy makes a noise.
  680. // Fuzzy roars.
  681. }
  682.  
  683. /*
  684. *
  685. * Testing empty elements in array. With JSON parsing
  686. *
  687. */
  688.  
  689. {
  690. let arrLegal = JSON.parse('{"arr":["a","b","c"]}')
  691. console.log(arrLegal)
  692. let arrParse = JSON.parse('{"arr":["a",null,"c"]}')
  693. console.log(arrParse)
  694. let arrArrw = JSON.parse('{"arr":["a",undefined,"c"]}')
  695. console.log(arrArrw)
  696. // let arrFail = JSON.parse('{"arr":["a",,"c"]}')
  697. // console.log(arrFail)
  698. }
  699.  
  700. /*
  701. *
  702. There's numerous ways to loop over arrays and objects in JavaScript, and the tradeoffs are a common cause of confusion.
  703. Some style guides go so far as to ban certain looping constructs. In this article,
  704. I'll describe the differences between iterating over an array with the 4 primary looping constructs:
  705.  
  706. for (let i = 0; i < arr.length; ++i)
  707. arr.forEach((v, i) => { ... })
  708. for (let i in arr)
  709. for (const v of arr)
  710.  
  711. I'll provide an overview of the difference between these looping constructs using several different edge cases.
  712. I'll also link to the relevant ESLint rules that you can use to enforce looping best practices in your projects.
  713. *
  714. */
  715.  
  716. /*
  717. Syntactic Overview
  718. The for and for/in looping constructs give you access to the index in the array, not the actual element. For example,
  719. suppose you want to print out the values stored in the below array:
  720. */
  721.  
  722. {
  723. const arr = ['a', 'b', 'c'];
  724. // With for and for/in, you need to print out arr[i]:
  725.  
  726. for (let i = 0; i < arr.length; ++i) {
  727. console.log(arr[i]);
  728. }
  729. for (let i in arr) {
  730. console.log(arr[i]);
  731. }
  732. }
  733.  
  734. /**
  735. With the other two constructs, forEach() and for/of, you get access to the array element itself.
  736. With forEach() you can access the array index i, with for/of you cannot.
  737. * */
  738. {
  739. arr.forEach((v, i) => console.log(v));
  740. for (const v of arr) {
  741. console.log(v);
  742. }
  743. }
  744.  
  745. /**
  746. Non-Numeric Properties
  747. JavaScript arrays are objects. That means you can add string properties to your array, not just numbers.
  748. */
  749.  
  750. {
  751. const arr = ['a', 'b', 'c'];
  752. typeof arr; // 'object'
  753. // Assign to a non-numeric property
  754. arr.test = 'bad';
  755.  
  756. arr.test; // 'abc'
  757. arr[1] === arr['1']; // true, JavaScript arrays are just special objects
  758. // 3 of the 4 looping constructs ignore the non-numeric property. However, for/in will actually print out "bad":
  759.  
  760. const arr = ['a', 'b', 'c'];
  761. arr.test = 'bad';
  762.  
  763. // Prints "a, b, c, bad"
  764. for (let i in arr) {
  765. console.log(arr[i]);
  766. }
  767. }
  768.  
  769. /**
  770. This is why iterating through an array using for/in is generally bad practice.
  771. The other looping constructs correctly ignore the num-numeric key:
  772. */
  773. {
  774. const arr = ['a', 'b', 'c'];
  775. arr.test = 'abc';
  776. // Prints "a, b, c"
  777. for (let i = 0; i < arr.length; ++i) {
  778. console.log(arr[i]);
  779. }
  780. // Prints "a, b, c"
  781. arr.forEach((el, i) => console.log(i, el));
  782. // Prints "a, b, c"
  783. for (const el of arr) {
  784. console.log(el);
  785. }
  786. }
  787.  
  788. /**
  789. Takeaway: Avoid using for/in over an array unless you're certain you mean to iterate over non-numeric keys and inherited keys.
  790. Use the guard-for-in ESLint rule to disallow for/in.
  791. */
  792.  
  793. /*
  794. *
  795. Empty Elements
  796. JavaScript arrays allow empty elements. The below array is syntactically valid and has length 3:
  797. *
  798. */
  799.  
  800. {
  801. const arr = ['a',, 'c'];
  802. arr.length; // 3
  803. }
  804. /*
  805. *
  806. * What makes things even more confusing is that looping constructs treat ['a',, 'c'] differently from ['a', undefined, 'c'].
  807. * Below is how the 4 looping constructs handle ['a',, 'c'] with an empty element. for/in and for/each skip the empty element,
  808. * for and for/of do not.
  809. *
  810. */
  811.  
  812. // Prints "a, undefined, c"
  813. for (let i = 0; i < arr.length; ++i) {
  814. console.log(arr[i]);
  815. }
  816.  
  817. // Prints "a, c"
  818. arr.forEach(v => console.log(v));
  819.  
  820. // Prints "a, c"
  821. for (let i in arr) {
  822. console.log(arr[i]);
  823. }
  824.  
  825. // Prints "a, undefined, c"
  826. for (const v of arr) {
  827. console.log(v);
  828. }
  829.  
  830. /**
  831. In case you're wondering, all 4 constructs print "a, undefined, c" for ['a', undefined, 'c'].
  832. *
  833. There's another way to add an empty element to an array:
  834. */
  835.  
  836. // Equivalent to `['a', 'b', 'c',, 'e']`
  837. const arr = ['a', 'b', 'c'];
  838. arr[5] = 'e';
  839.  
  840. /**
  841. forEach() and for/in skip empty elements in the array, for and for/of do not.
  842. The forEach() behavior may cause problems, however, holes in JavaScript arrays
  843. are generally rare because they are not supported in JSON:
  844. */
  845.  
  846. // $ node
  847. JSON.parse('{"arr":["a","b","c"]}')
  848. // { arr: [ 'a', 'b', 'c' ] }
  849. JSON.parse('{"arr":["a",null,"c"]}')
  850. // { arr: [ 'a', null, 'c' ] }
  851. JSON.parse('{"arr":["a",,"c"]}')
  852. // SyntaxError: Unexpected token , in JSON at position 12
  853.  
  854. /**
  855. So you don't have to worry about holes in user data, unless you give your users access to the full JavaScript runtime.
  856. Takeaway: for/in and forEach() skip empty elements, also known as "holes", in the array.
  857. There's rarely any reason to treat holes as a special case as opposed to treating the index as having value undefined.
  858. If the special behavior with holes causes you concern, below is an example .eslintrc.yml file that disallows calling forEach().
  859. *
  860. parserOptions:
  861. ecmaVersion: 2018
  862. rules:
  863. no-restricted-syntax:
  864. - error
  865. - selector: CallExpression[callee.property.name="forEach"]
  866. message: Do not use `forEach()`, use `for/of` instead
  867. */
  868.  
  869. /**
  870. *
  871. Function Context
  872. 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,
  873. but the forEach() callback will have a different this unless you use an arrow function.
  874. *
  875. **/
  876.  
  877. 'use strict';
  878.  
  879. const arr = ['a'];
  880.  
  881. // Prints "undefined"
  882. arr.forEach(function() {
  883. console.log(this);
  884. });
  885.  
  886. /**
  887. *
  888. Takeaway: Use arrow functions with forEach().
  889. Use the no-arrow-callback ESLint rule to require arrow functions for all callbacks that don't use this.
  890. *
  891. Async/Await and Generators
  892. Another edge case with forEach() is that it doesn't quite work right with async/await or generators.
  893. If your forEach() callback is synchronous then it doesn't matter, but you can't use await within a forEach() callback:
  894. */
  895.  
  896. async function run() {
  897. const arr = ['a', 'b', 'c'];
  898. arr.forEach(el => {
  899. // SyntaxError
  900. await new Promise(resolve => setTimeout(resolve, 1000));
  901. console.log(el);
  902. });
  903. }
  904.  
  905. /**
  906. * You can't use yield either:
  907. */
  908.  
  909. function* run() {
  910. const arr = ['a', 'b', 'c'];
  911. arr.forEach(el => {
  912. // SyntaxError
  913. yield new Promise(resolve => setTimeout(resolve, 1000));
  914. console.log(el);
  915. });
  916. }
  917. /*
  918. *
  919. *The above examples work fine with for/of:
  920. *
  921. */
  922.  
  923. async function asyncFn() {
  924. const arr = ['a', 'b', 'c'];
  925. for (const el of arr) {
  926. await new Promise(resolve => setTimeout(resolve, 1000));
  927. console.log(el);
  928. }
  929. }
  930.  
  931. function* generatorFn() {
  932. const arr = ['a', 'b', 'c'];
  933. for (const el of arr) {
  934. yield new Promise(resolve => setTimeout(resolve, 1000));
  935. console.log(el);
  936. }
  937. }
  938.  
  939. /**
  940. *
  941. * Even if you mark your forEach() callback as async, you're in for substantial headache in trying to get async forEach()
  942. * to work in series and pause your async function. For example, the below script will print 0-9 in reverse order.
  943. *
  944. */
  945.  
  946. async function print(n) {
  947. // Wait 1 second before printing 0, 0.9 seconds before printing 1, etc.
  948. await new Promise(resolve => setTimeout(() => resolve(), 1000 - n * 100));
  949. // Will usually print 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 but order is not strictly
  950. // guaranteed.
  951. console.log(n);
  952. }
  953.  
  954. async function test() {
  955. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(print);
  956. }
  957.  
  958. test();
  959.  
  960. /**
  961.  
  962. Takeaway: If you're using async/await or generators, remember that forEach() is syntactic sugar. Like sugar,
  963. it should be used sparingly and shouldn't be used for everything.
  964.  
  965. *
  966. * The Aggregation Mixins is a manner to extend multiple classes on javascript
  967. *
  968. */
  969.  
  970. {
  971. const aggregation = (baseClass, ...mixins) => {
  972. class base extends baseClass {
  973. constructor (...args) {
  974. super(...args);
  975. mixins.forEach((mixin) => {
  976. copyProps(this,(new mixin));
  977. });
  978. }
  979. }
  980. let copyProps = (target, source) => { // this function copies all properties and symbols, filtering out some special ones
  981. Object.getOwnPropertyNames(source)
  982. .concat(Object.getOwnPropertySymbols(source))
  983. .forEach((prop) => {
  984. if (!prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
  985. Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop));
  986. })
  987. }
  988. mixins.forEach((mixin) => { // outside contructor() to allow aggregation(A,B,C).staticFunction() to be called etc.
  989. copyProps(base.prototype, mixin.prototype);
  990. copyProps(base, mixin);
  991. });
  992. return base;
  993. }
  994.  
  995. // Sample with a Person Object
  996. class Person{
  997. constructor(n){
  998. this.name=n;
  999. }
  1000. }
  1001. class Male{
  1002. constructor(s='male'){
  1003. this.sex=s;
  1004. }
  1005. }
  1006. class Child{
  1007. constructor(a=12){
  1008. this.age=a;
  1009. }
  1010. tellAge(){console.log(this.name+' is '+this.age+' years old.');}
  1011. }
  1012. class Boy extends aggregation(Person,Male,Child){}
  1013. let m = new Boy('Mike');
  1014. m.tellAge(); // Mike is 12 years old.
  1015. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement