├── .gitignore ├── _config.yml ├── index.html ├── func-prog └── index.js ├── promises └── index.js ├── README.md ├── bind-in-es5class └── index.js ├── generators └── index.js ├── object-literals └── index.js ├── template-literals └── index.js ├── closures └── index.js ├── default-params └── index.js ├── func-curry └── index.js ├── arrow-func └── index.js ├── async-await └── index.js ├── spread └── index.js ├── destruct └── index.js ├── let-const-var └── index.js ├── proxies └── index.js ├── bind-call-apply └── index.js ├── app.js └── array-func └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | JS Master 8 | 9 | 10 |

Open Browser Page Inspector

11 |

Clicking each of the links will execute the js examples in repository

12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /func-prog/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | function multiplesOf2(x) { 3 | return x % 2 === 0; 4 | } 5 | 6 | function traverse(arr, func) { 7 | const result = []; 8 | for (let i = 0; i < arr.length; i++) 9 | result.push(func(arr[i])); 10 | return result; 11 | } 12 | 13 | function demo() { 14 | console.log('\n\nFUNCTIONAL PROGRAMMING'); 15 | const arr = [1,2,3,4,5,6,7,8]; 16 | let result = traverse(arr, multiplesOf2); 17 | console.log(result); 18 | result = traverse(arr, function (x) { 19 | return x * x; 20 | }); 21 | console.log(result); 22 | result = traverse(arr, (x) => 10 * x ); 23 | console.log(result); 24 | }; 25 | 26 | (context || this).demoLibs['func-prog'] = demo; 27 | })(window); 28 | -------------------------------------------------------------------------------- /promises/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function demo() { 4 | console.log('\n\nPROMISES'); 5 | 6 | // a promise generator function, returning new promise 7 | // which executes a setTimeout resolving after 1 sec 8 | const timeoutPromise = () => new Promise((resolve, reject) => { setTimeout(resolve, 1000) }); 9 | 10 | // simple promise and then 11 | timeoutPromise() 12 | .then(() => console.log('Yo!')); 13 | 14 | // promise chaining 15 | timeoutPromise() 16 | .then(() => timeoutPromise()) 17 | .then(() => console.log('YoYo!')); 18 | 19 | timeoutPromise() 20 | .then(() => timeoutPromise()) 21 | .then(() => timeoutPromise()) 22 | .then(() => console.log('YoYoYo!')); 23 | }; 24 | 25 | (context || this).demoLibs['promises'] = demo; 26 | })(window); 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Art of JS 2 | 3 | > Learn the art of Javascript, with simple, to the point examples 4 | 5 | ### Topics: 6 | 1. [Array functions](array-func/index.js) 7 | 2. [Arrow functions](arrow-func/index.js) 8 | 3. [Async Await](async-await/index.js) 9 | 4. [Bind Call Apply](bind-call-apply/index.js) 10 | 5. [Closures](closures/index.js) 11 | 6. [Default parameters](default-params/index.js) 12 | 7. [Desctructuring](destruct/index.js) 13 | 8. [Function currying](func-curry/index.js) 14 | 9. [Functional programming](func-prog/index.js) 15 | 10. [Generators](generators/index.js) 16 | 11. [Let Const Var](let-const-var/index.js) 17 | 12. [Object literals](object-literals/index.js) 18 | 13. [Promises](promises/index.js) 19 | 14. [Proxies/ Revocable Proxies](proxies/index.js) 20 | 15. [Spread](spread/index.js) 21 | 16. [Template / Tagged Template literals](template-literals/index.js) 22 | -------------------------------------------------------------------------------- /bind-in-es5class/index.js: -------------------------------------------------------------------------------- 1 | (function (context) { 2 | 3 | function Driver(name) { 4 | this.name = name; 5 | } 6 | 7 | Driver.prototype.displayScore = function (score) { 8 | console.log("Score for " + this.name + ": " + score); 9 | }; 10 | 11 | 12 | Driver.prototype.getScore = function () { 13 | setTimeout(function () { 14 | this.displayScore(10); 15 | }.bind(this), 1000); 16 | 17 | // another approach here without using this is: 18 | // var that = this; 19 | // setTimeout(function () { 20 | // that.displayScore(10); 21 | // }, 1000); 22 | 23 | // another approach using arrow operator 24 | //setTimeout(() => this.displayScore(10), 1000); 25 | 26 | }; 27 | 28 | function demo() { 29 | new Driver("Test driver").getScore(); 30 | } 31 | 32 | (context || this).demoLibs['bind'] = demo; 33 | })(window); 34 | -------------------------------------------------------------------------------- /generators/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function *foo(x) { 4 | yield 1; 5 | yield 2; 6 | yield x; 7 | } 8 | 9 | function *bar(x) { 10 | const y = 10 * (yield (x + 2)); 11 | const z = yield (y / 5); 12 | return (x + y + z); 13 | } 14 | 15 | function demo() { 16 | console.log('\n\nGENERATORS'); 17 | 18 | const iter = foo(3); 19 | console.log(iter.next()); // { value:1, done:false } 20 | console.log(iter.next()); // { value:2, done:false } 21 | console.log(iter.next()); // { value:3, done:false } 22 | console.log(iter.next()); // { value:undefined, done:true } 23 | 24 | for (const v of foo(10)) { 25 | console.log(v); 26 | } 27 | 28 | const iterBar = bar(100); 29 | console.log(iterBar.next()); // { value:102, done:false } 30 | console.log(iterBar.next(5)); // { value:10, done:false } 31 | console.log(iterBar.next(30)); // { value:180, done:true } 32 | }; 33 | 34 | (context || this).demoLibs['generators'] = demo; 35 | })(window); 36 | -------------------------------------------------------------------------------- /object-literals/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function demo() { 4 | console.log('\n\nOBJECT LITERALS'); 5 | 6 | const employee = { 7 | id: '1234', 8 | name: { 9 | title: 'Dr.', 10 | firstName: 'Strange', 11 | lastName: '' 12 | }, 13 | address: { 14 | street: '890', 15 | locality: 'Fifth Avenue', 16 | city: 'Manhattan', 17 | state: 'New York', 18 | } 19 | }; 20 | 21 | // Use of object destructuring 22 | const { title, firstName, lastName } = employee.name; 23 | const name = `${title} ${firstName} ${lastName}`; 24 | 25 | const { street, locality, city, state } = employee.address; 26 | const address = `${street} ${locality} ${city} ${state}`; 27 | 28 | // Use of object literals 29 | const employeeShort = { 30 | name, 31 | address, 32 | id: employee.id, 33 | }; 34 | 35 | console.log(employee); 36 | console.log(employeeShort); 37 | } 38 | 39 | (context || this).demoLibs['object-literals'] = demo; 40 | })(window); 41 | -------------------------------------------------------------------------------- /template-literals/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | // tagged literal function receives two parameters 4 | // tokens - string tokens, around the placeholders 5 | // values - list of values to replace in string literal placeholders 6 | function capitalize(tokens = [], ...values) { 7 | return tokens.reduce((acc, x, i) => { 8 | return acc + x + `${values[i] || ''}`.toUpperCase(); 9 | }, ''); 10 | } 11 | 12 | function demo() { 13 | console.log('\n\nTEMPLATE LITERALS'); 14 | const person = { 15 | firstName: 'John', 16 | lastName: 'Doe', 17 | age: 27 18 | } 19 | 20 | const { firstName, lastName, age } = person; 21 | 22 | const output = ` 23 | First Name: ${firstName}\n 24 | Last Name: ${lastName}\n 25 | Age: ${age} 26 | `; 27 | console.log(output); 28 | 29 | const outputTaggedTemplate = capitalize` 30 | First Name: ${firstName}\n 31 | Last Name: ${lastName}\n 32 | Age: ${age} 33 | `; 34 | console.log(outputTaggedTemplate); 35 | }; 36 | 37 | (context || this).demoLibs['template-literals'] = demo; 38 | })(window); 39 | -------------------------------------------------------------------------------- /closures/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | // longRunningTask is a simple function taking url, 4 | // & callbacks for success and failure 5 | function longRunningTask(url, success, failure) { 6 | if(url) { 7 | return success('{\"name\":\"John Doe\",\"age\":27}'); 8 | } else { 9 | return failure(404, 'no resource found'); 10 | } 11 | } 12 | 13 | // successCallback returns another function which can be called later, 14 | // whilst still having access to data param in successCallback 15 | function successCallback(data) { 16 | return function() { 17 | const minimumAge = 21; 18 | data = JSON.parse(data); 19 | if (data.age < minimumAge) { 20 | return `Deny User - Age less than ${minimumAge}`; 21 | } 22 | return 'Allow User'; 23 | } 24 | } 25 | 26 | function failureCallback(error, reason) { 27 | return function() { 28 | console.log(`${error} - ${reason}`); 29 | } 30 | } 31 | 32 | function demo() { 33 | console.log('\n\nCLOSURES'); 34 | // returns function from successCallback 35 | const returnVal = longRunningTask('sample-url', successCallback, failureCallback); 36 | // prints the data 37 | console.log(returnVal()); 38 | }; 39 | 40 | (context || this).demoLibs['closures'] = demo; 41 | })(window); 42 | -------------------------------------------------------------------------------- /default-params/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function greetWithoutDefaultParams(name, language) { 4 | switch(language || 'en') { 5 | case 'en': console.log(`Hello ${name}`); break; 6 | case 'es': console.log(`Hola ${name}`); break; 7 | } 8 | } 9 | 10 | function greetWithoutDefaultParamsCheckWithArguments(name, language) { 11 | // example of strict check 12 | if (arguments.length < 2) return; 13 | switch(language) { 14 | case 'en': console.log(`Hello ${name}`); break; 15 | case 'es': console.log(`Hola ${name}`); break; 16 | } 17 | } 18 | 19 | // function accepts param language with default value 'en' 20 | function greetWithDefaultParams(name, language = 'en') { 21 | switch(language) { 22 | case 'en': console.log(`Hello ${name}`); break; 23 | case 'es': console.log(`Hola ${name}`); break; 24 | } 25 | } 26 | 27 | function demo() { 28 | console.log('\n\nDEFAULT PARAMS'); 29 | 30 | greetWithDefaultParams('John Doe'); 31 | greetWithDefaultParams('John Doe', 'es'); 32 | 33 | greetWithoutDefaultParams('James Bond'); 34 | greetWithoutDefaultParams('James Bond', 'es'); 35 | 36 | greetWithoutDefaultParamsCheckWithArguments('John Wick'); 37 | greetWithoutDefaultParamsCheckWithArguments('John Wick', 'es'); 38 | }; 39 | 40 | (context || this).demoLibs['default-params'] = demo; 41 | })(window); 42 | -------------------------------------------------------------------------------- /func-curry/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function multiply(a, b) { 4 | return a * b; 5 | } 6 | 7 | function greet(language, person) { 8 | const greet = language === 'es' ? 'Hola' : 'Hello'; 9 | console.log(`${greet} ${person.fname} ${person.lname}`); 10 | } 11 | 12 | function goodbye(language) { 13 | return function(person) { 14 | const goodbye = language === 'ru' ? 'Dasvidaniya' : 'Good bye'; 15 | console.log(`${goodbye} ${person.fname} ${person.lname}`); 16 | } 17 | } 18 | 19 | function demo() { 20 | 21 | const johnSnow = { 22 | fname: 'John', 23 | lname: 'Snow' 24 | }; 25 | 26 | // curried function call 27 | goodbye('ru')(johnSnow); 28 | // or 29 | const goodbyeInEnglish = goodbye('en'); 30 | const goodbyeInRussian = goodbye('ru'); 31 | 32 | goodbyeInEnglish(johnSnow); 33 | goodbyeInRussian(johnSnow); 34 | 35 | // regular function call 36 | greet('es', johnSnow); 37 | 38 | // curried using bind 39 | const greetInEnglish = greet.bind(this, 'en'); 40 | const greetInSpanish = greet.bind(this, 'es'); 41 | 42 | greetInEnglish(johnSnow); 43 | greetInSpanish(johnSnow); 44 | 45 | // also few other functions curried with bind 46 | const twice = multiply.bind(this, 2); 47 | const thrice = multiply.bind(this, 3); 48 | 49 | console.log(twice(5)); 50 | console.log(thrice(10)); 51 | } 52 | 53 | (context || this).demoLibs['func-curry'] = demo; 54 | })(window); 55 | -------------------------------------------------------------------------------- /arrow-func/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function printUpperCase() { 4 | const self = this; 5 | console.log(self); 6 | self.string = self.string.toUpperCase(); 7 | return function() { 8 | console.log(this); // window this 9 | console.log(this.string); 10 | console.log(self.string); 11 | } 12 | } 13 | 14 | function printUpperCaseFatArrow() { 15 | console.log(this); 16 | this.string = this.string.toUpperCase(); 17 | return () => console.log(this.string); 18 | } 19 | 20 | function demo() { 21 | console.log('\n\nARROW FUNCTIONS'); 22 | 23 | printUpperCase.call({ string: 'Hello John Doe' })(); 24 | printUpperCaseFatArrow.call({ string: 'Hello John Doe' })(); 25 | 26 | const person = { 27 | firstName: 'John', 28 | lastName: 'Doe', 29 | printNameFatArrow: () => `${this.firstName} ${this.lastName}`, 30 | printNameRegular: function() { return `${this.firstName} ${this.lastName}` }, 31 | printName() { return `${this.firstName} ${this.lastName}` }, 32 | } 33 | 34 | console.log(person.printNameFatArrow()); 35 | console.log(person.printNameFatArrow.bind(person)()); 36 | console.log(person.printNameRegular()); 37 | console.log(person.printName()); 38 | 39 | // remember, Arrow functions 40 | // 1. cannot be used for Generators, 41 | // 2. do not get arguments object, 42 | // 3. cannot be used as constructors, 43 | // 4. call(), apply(), and bind() will not change the value of this 44 | }; 45 | 46 | (context || this).demoLibs['arrow-func'] = demo; 47 | })(window); 48 | -------------------------------------------------------------------------------- /async-await/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | async function asyncFetchDemo() { 4 | console.log('Fetch async initiating'); 5 | const responsePromise = await fetch('https://api.github.com/search/repositories?sort=stars&order=desc&q=art%20o%20fjs') 6 | const responseJSON = await responsePromise.json(); 7 | console.log(responseJSON); 8 | console.log('Fetch async responsed successfully'); 9 | } 10 | 11 | function regularFetchDemo() { 12 | console.log('Fetch regular initiating'); 13 | fetch('https://api.github.com/search/repositories?sort=stars&order=desc&q=art%20o%20fjs') 14 | .then(x => x.json()) 15 | .then(x => console.log(x)); 16 | console.log('Fetch regular responsed successfully'); 17 | } 18 | 19 | function getPromise(value) { 20 | return new Promise((resolve, reject) => 21 | setTimeout(() => 22 | resolve(value), 1000) ); 23 | } 24 | 25 | async function asyncPromise() { 26 | // await can be only used in async functions 27 | console.log('asyncPromise initiated'); 28 | const result1 = await getPromise(100); 29 | console.log('Result 1 recevied'); 30 | const result2 = await getPromise(200); 31 | console.log('Result 2 recevied'); 32 | console.log(result1 + result2); 33 | console.log('After result is printed'); 34 | } 35 | 36 | function demo() { 37 | console.log('\n\nASYNC AWAIT DEMO'); 38 | asyncFetchDemo(); 39 | console.log('After asyncFetchDemo is called'); 40 | regularFetchDemo(); 41 | console.log('After regularFetchDemo is called'); 42 | asyncPromise(); 43 | }; 44 | 45 | (context || this).demoLibs['async-await'] = demo; 46 | })(window); 47 | -------------------------------------------------------------------------------- /spread/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function basicSpread() { 4 | const name = { 5 | name: { 6 | title: 'Dr.', 7 | firstName: 'Strange', 8 | lastName: '', 9 | } 10 | }; 11 | 12 | const address = { 13 | address: { 14 | street: '890', 15 | locality: 'Fifth Avenue', 16 | city: 'Manhattan', 17 | state: 'New York', 18 | } 19 | }; 20 | 21 | // This is object spread 22 | const employee2 = { 23 | ...name, 24 | ...address, 25 | id: 1234, 26 | }; 27 | console.log(employee2); 28 | 29 | // This is object literal and not object spread 30 | const employee = { 31 | name, 32 | address, 33 | id: 1234, 34 | }; 35 | console.log(employee); 36 | 37 | const arr1 = [1, 2, 3, 4]; 38 | const arr2 = [10, 20, 30, 40]; 39 | // spread 40 | const arrMerged = [...arr1, ...arr2]; 41 | 42 | console.log(arrMerged); 43 | } 44 | 45 | function functionSpread() { 46 | // regular stuff 47 | print('John', 'Doe'); 48 | 49 | // function spread 50 | const arrName = ['John', 'Doe']; 51 | print(...arrName); 52 | 53 | const a = 'John'; 54 | const b = 'Doe'; 55 | // now this is interesting, guess the output 56 | print(...[...a,...b]); 57 | } 58 | 59 | function print(firstName, lastName) { 60 | console.log(`Hey ${firstName} ${lastName}`); 61 | } 62 | 63 | function rest() { 64 | const colors = ['red', 'green', 'blue', 'yellow', 'brown']; 65 | // rest 66 | const [ first, second, ...restOfColors ] = colors; 67 | console.log(first); 68 | console.log(second); 69 | console.log(restOfColors); 70 | } 71 | 72 | function demo() { 73 | console.log('\n\nSPREAD'); 74 | basicSpread(); 75 | functionSpread(); 76 | rest(); 77 | }; 78 | 79 | (context || this).demoLibs['spread'] = demo; 80 | })(window); 81 | -------------------------------------------------------------------------------- /destruct/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function printAddress(address) { 4 | const { 5 | street, 6 | locality, 7 | city, 8 | state } = address; 9 | console.log(`${street}, ${locality}, ${city}, ${state}`); 10 | } 11 | 12 | function printName(name) { 13 | const { title, firstName, lastName } = name; 14 | console.log(`${title} ${firstName} ${lastName}`); 15 | } 16 | 17 | // destruct received object param 18 | function printNameDestructParams({ title, firstName, lastName }) { 19 | console.log(`${title} ${firstName} ${lastName}`); 20 | } 21 | 22 | function demo() { 23 | console.log('\n\nDESTRUCTURING'); 24 | 25 | const employee = { 26 | id: '1234', 27 | name: { 28 | title: 'Dr.', 29 | firstName: 'Strange', 30 | lastName: '' 31 | }, 32 | address: { 33 | street: '890', 34 | locality: 'Fifth Avenue', 35 | city: 'Manhattan', 36 | state: 'New York', 37 | } 38 | }; 39 | 40 | const { id, name, address: addr } = employee; 41 | 42 | console.log(id); 43 | printName(name); 44 | printNameDestructParams(name); 45 | printAddress(addr); 46 | 47 | // array destructuring 48 | const arr = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; 49 | // destructs arr[0], arr[1], arr[2] and rest of items into 50 | // mon tue wed and restOfNumbers respectively 51 | const [mon, tue, wed, ...restOfWeek] = arr; 52 | console.log(mon); 53 | console.log(tue); 54 | console.log(wed); 55 | console.log(restOfWeek); 56 | 57 | // destructs [0], [1] and rest of items into 58 | // first second and restOfNumbers respectively 59 | const [first, second, ...restOfNumbers] = [1, 2, 3, 4, 5]; 60 | console.log(first); 61 | console.log(second); 62 | console.log(restOfNumbers); 63 | }; 64 | 65 | (context || this).demoLibs['destruct'] = demo; 66 | })(window); 67 | -------------------------------------------------------------------------------- /let-const-var/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | var globalVar = 'global var'; 4 | let globalLet = 'global let'; 5 | 6 | function demoVsVar() { 7 | console.log(demoVarDeclaredLater); 8 | var demoVarDeclaredLater = 'demo var declared later'; 9 | 10 | // console.log(demoLetDeclaredLater); Uncaught ReferenceError: demoVarDeclaredLater is not defined 11 | let demoLetDeclaredLater = 'demo var declared later'; 12 | 13 | for (var i = 0; i < 5; i ++) { 14 | setTimeout(() => console.log(`value of var i: ${i}`), 100); 15 | } 16 | 17 | for (let j = 0; j < 5; j ++) { 18 | setTimeout(() => console.log(`value of let i: ${j}`), 100); 19 | } 20 | } 21 | 22 | function demo() { 23 | console.log('\n\nLET CONST VAR'); 24 | 25 | globalVar = 'global var changed in method scope'; 26 | console.log(globalVar); 27 | globalLet = 'global let changed in method scope'; 28 | console.log(globalLet); 29 | 30 | /* 31 | If a global let is defined again in child scope, will cause error 32 | Uncaught ReferenceError: globalLet is not defined 33 | let globalLet = 'global Let'; 34 | console.log(globalLet); 35 | */ 36 | 37 | var demoVar = 'demo var'; 38 | let demoLet = 'global let'; 39 | const demoConst = 'I am constant'; 40 | 41 | // let maintains block scope 42 | // var maintains function scope 43 | 44 | // It is a good practice to always declare variables as const 45 | // unless you need to re-assign it with new value later, in such cases use let 46 | 47 | console.log(demoVar); 48 | console.log(demoLet); 49 | console.log(demoConst); 50 | 51 | // demoConst = 'I am constant reassigned'; Uncaught TypeError: Assignment to constant variable. 52 | 53 | demoVsVar(); 54 | }; 55 | 56 | console.log(globalVar); 57 | console.log(globalLet); 58 | 59 | // console.log(demoVar); Uncaught ReferenceError: demoVar is not defined 60 | 61 | (context || this).demoLibs['let-const-var'] = demo; 62 | })(window); 63 | -------------------------------------------------------------------------------- /proxies/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function demoSimpleProxy() { 4 | const target = {}; 5 | const handler = { 6 | get: function(obj, key) { 7 | return obj[key]; 8 | }, 9 | set: function(obj, key, value) { 10 | if (key === 'age' && value < 21) 11 | throw Error('Age cannot be less than 21'); 12 | else 13 | obj[key] = value; 14 | } 15 | }; 16 | const prObj = new Proxy(target, handler); 17 | prObj.name = 'John'; 18 | prObj.age = 21; 19 | // prObj.age = 19; 20 | console.log(prObj.name); 21 | console.log(prObj.age); 22 | 23 | // once in proxy target should not be accessed directly 24 | // here we just want to see what target actually prints 25 | // target is a regular object just accessed via proxy prObj 26 | console.log(target); 27 | 28 | // however, a proxy object wraps actual object in target 29 | // and access proxies in handler 30 | console.log(prObj); 31 | 32 | // does that mean accessing prObj.handler or prObj.target 33 | // will give us target and handler? NO. 34 | console.log(prObj.target); // undefined 35 | console.log(prObj.handler); // undefined 36 | } 37 | 38 | function createProxy(target, handler) { 39 | return new Proxy(target, handler); 40 | } 41 | 42 | function demoProxyCreator() { 43 | const myProxyObj = createProxy({}, { 44 | get: function(obj, key) { return obj[key]; }, 45 | set: function(obj, key, value) { obj[key] = value; } 46 | }); 47 | myProxyObj.name = 'Johny Boy'; 48 | myProxyObj.language = 'English'; 49 | console.log(myProxyObj.name); 50 | console.log(myProxyObj.language); 51 | } 52 | 53 | function demoRevocableProxy() { 54 | const { proxy, revoke } = Proxy.revocable({}, {}); // passing empty object as target and handler 55 | proxy.name = 'Sumeet Sarkar'; 56 | console.log(proxy.name); 57 | revoke(); 58 | console.log(proxy); // works, as Proxy still shows the entire object 59 | console.log(proxy.name); // error! TypeError: Cannot perform 'get' on a proxy that has been revoked 60 | } 61 | 62 | function demo() { 63 | console.log('\n\PROXIES'); 64 | demoSimpleProxy(); 65 | demoProxyCreator(); 66 | demoRevocableProxy(); 67 | }; 68 | 69 | (context || this).demoLibs['proxies'] = demo; 70 | })(window); 71 | -------------------------------------------------------------------------------- /bind-call-apply/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | const personJohnDoe = { 4 | firstName: 'John', 5 | lastName: 'Doe', 6 | age: 28, 7 | getFullName: function() { 8 | console.log(`${this.firstName} ${this.lastName}`); 9 | } 10 | } 11 | 12 | const personJamesBond = { 13 | firstName: 'James', 14 | lastName: 'Bond', 15 | }; 16 | 17 | function print(shouldIndent) { 18 | const lb = shouldIndent ? '\n' : ''; 19 | console.log(`${this.firstName} ${lb}${this.lastName}, ${lb}${this.age}`); 20 | } 21 | 22 | function greet(language, firstName, lastName) { 23 | let greet = 'Hello'; 24 | if (language === 'es') { 25 | greet = 'Hola'; 26 | } 27 | console.log(`${greet}, ${firstName} ${lastName}`); 28 | } 29 | 30 | function bindDemo() { 31 | console.log('\nBIND ----------'); 32 | print.bind(personJohnDoe)(); 33 | personJohnDoe.getFullName(); 34 | personJohnDoe.getFullName.bind(personJamesBond)(); 35 | const printJohnDoeWithIndent = print.bind(personJohnDoe, true); 36 | printJohnDoeWithIndent(); 37 | } 38 | 39 | function callDemo() { 40 | console.log('\nCALL ----------'); 41 | print.call(personJohnDoe); 42 | print.call(personJohnDoe, true); 43 | personJohnDoe.getFullName.call(personJamesBond); 44 | } 45 | 46 | function applyDemo() { 47 | console.log('\nAPPLY ----------'); 48 | print.apply(personJohnDoe); 49 | print.apply(personJohnDoe, [true]); 50 | greet.apply(this, ['es', 'Sumeet', 'Sarkar']); 51 | 52 | const arr1 = [1, 2, 3, 4]; 53 | const arr2 = [5, 6, 7, 8]; 54 | arr1.push.apply(arr1, arr2) 55 | console.log(arr1); 56 | 57 | console.log('name: ', getConfig('name')); 58 | console.log('server timeout: ', getConfig('server', 'timeout')); 59 | } 60 | 61 | function getConfig() { 62 | return getConfigWithCountryCode.apply(this, [countryCode, ...Array.from(arguments)]); 63 | } 64 | 65 | const countryCode = 'uk'; 66 | const config = { 67 | 'us': { 68 | name: 'United States Of America', 69 | server: { 70 | timeout: '300' 71 | }, 72 | }, 73 | 'uk': { 74 | name: 'United Kingdom', 75 | server: { 76 | timeout: '500' 77 | } 78 | }, 79 | } 80 | 81 | function getConfigWithCountryCode(countryCode = 'us', key1, key2) { 82 | const countryConfig = config[countryCode]; 83 | if (key1 && key2) 84 | return countryConfig[key1] && countryConfig[key1][key2]; 85 | return countryConfig[key1]; 86 | } 87 | 88 | function demo() { 89 | console.log('\n\nBIND CALL APPLY'); 90 | bindDemo(); 91 | callDemo(); 92 | applyDemo(); 93 | }; 94 | 95 | (context || this).demoLibs['bind-call-apply'] = demo; 96 | })(window); 97 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | window.demoLibs = {}; 2 | 3 | const ulList = document.createElement('ul'); 4 | ulList.setAttribute('id', 'parent-list'); 5 | ulList.addEventListener("click", function(e) { 6 | if(e.target && e.target.nodeName === 'A') { 7 | window.demoLibs[e.target.id] && window.demoLibs[e.target.id](); 8 | } 9 | }); 10 | 11 | document.body.appendChild(ulList); 12 | 13 | [ 14 | { 15 | key: 'func-prog', 16 | name: 'Functional Programming', 17 | src: './func-prog/index.js', 18 | },{ 19 | key: 'array-func', 20 | name: 'Array Functions', 21 | src: './array-func/index.js', 22 | },{ 23 | key: 'arrow-func', 24 | name: 'Arrow Functions', 25 | src: './arrow-func/index.js', 26 | },{ 27 | key: 'bind-call-apply', 28 | name: 'Bind Call Apply', 29 | src: './bind-call-apply/index.js', 30 | },{ 31 | key: 'bind', 32 | name: 'Bind In Class', 33 | src: './bind-in-es5class/index.js', 34 | },{ 35 | key: 'let-const-var', 36 | name: 'Let Const Var', 37 | src: './let-const-var/index.js', 38 | },{ 39 | key: 'destruct', 40 | name: 'Destructuring', 41 | src: './destruct/index.js', 42 | },{ 43 | key: 'spread', 44 | name: 'Spread', 45 | src: './spread/index.js', 46 | },{ 47 | key: 'promises', 48 | name: 'Promises', 49 | src: './promises/index.js', 50 | },{ 51 | key: 'default-params', 52 | name: 'Default Parameters', 53 | src: './default-params/index.js', 54 | },{ 55 | key: 'template-literals', 56 | name: 'Template Literals', 57 | src: './template-literals/index.js', 58 | },{ 59 | key: 'object-literals', 60 | name: 'Object Literals', 61 | src: './object-literals/index.js', 62 | },{ 63 | key: 'func-curry', 64 | name: 'Function Currying', 65 | src: './func-curry/index.js', 66 | },{ 67 | key: 'closures', 68 | name: 'Closures', 69 | src: './closures/index.js', 70 | },{ 71 | key: 'proxies', 72 | name: 'Proxies', 73 | src: './proxies/index.js', 74 | },{ 75 | key: 'async-await', 76 | name: 'Async Await', 77 | src: './async-await/index.js', 78 | },{ 79 | key: 'generators', 80 | name: 'Generators', 81 | src: './generators/index.js', 82 | }, 83 | ].sort((a, b) => { 84 | const nameA = a.name.toLowerCase(); 85 | const nameB = b.name.toLowerCase(); 86 | if (nameA < nameB) return -1; 87 | else if (nameA > nameB) return 1; 88 | else return 0; 89 | 90 | }).forEach(item => { 91 | const li = document.createElement('li'); 92 | const a = document.createElement('a'); 93 | a.setAttribute('id', item.key); 94 | a.setAttribute('href', '#'); 95 | a.text = item.name; 96 | li.appendChild(a); 97 | ulList.appendChild(li); 98 | if (item.src) { 99 | const script = document.createElement('script'); 100 | script.type = 'text/javascript'; 101 | script.src = item.src; 102 | document.body.appendChild(script); 103 | } 104 | }); 105 | -------------------------------------------------------------------------------- /array-func/index.js: -------------------------------------------------------------------------------- 1 | (function(context) { 2 | 3 | function demoForEach(items, func) { 4 | // Use of Arrow function 5 | items.forEach(func || (item => console.log(item))); 6 | } 7 | 8 | function demoFilter(items, func) { 9 | // Use of Arrow function 10 | return items.filter(func || (item => item.type === 'veg')); 11 | } 12 | 13 | function demoMap(items) { 14 | return items.map(item => { 15 | // Use of template string literals 16 | item.name = `chopped: ${item.name}`; 17 | return item; 18 | }); 19 | } 20 | 21 | function demoReduce(bread, fillings, sauce) { 22 | const initial = { sandwich: { 23 | bread: bread, 24 | sauce: sauce, 25 | fillings: [] 26 | }}; 27 | 28 | return fillings.reduce((res, item) => { 29 | res.sandwich.fillings.push(item.name); 30 | return res; 31 | }, initial); 32 | } 33 | 34 | function demo() { 35 | console.log('\n\nARRAY FUNCTIONS'); 36 | 37 | const breads = [ 38 | 'Wheat bread', 39 | 'Honey oat bread', 40 | ]; 41 | 42 | const sauces = [ 43 | 'Mayo', 44 | 'Mustard', 45 | 'Mint' 46 | ]; 47 | 48 | const fillings = [ 49 | { 50 | 'name': 'Cheese', 51 | 'type': 'veg' 52 | }, 53 | { 54 | 'name': 'Cucumber', 55 | 'type': 'veg' 56 | }, 57 | { 58 | 'name': 'Tomatoes', 59 | 'type': 'veg' 60 | }, 61 | { 62 | 'name': 'Chicken', 63 | 'type': 'non-veg' 64 | }, 65 | { 66 | 'name': 'Lettuce', 67 | 'type': 'veg' 68 | } 69 | ]; 70 | 71 | console.log('Available Ingredients -----------------'); 72 | console.log('Breads -----------------'); 73 | demoForEach(breads); 74 | console.log('Fillings ---------------'); 75 | demoForEach(fillings); 76 | console.log('Sauces -----------------'); 77 | demoForEach(sauces); 78 | 79 | const bread = demoFilter(breads, b => b === 'Wheat bread'); 80 | const sauce = demoFilter(sauces, b => b === 'Mustard'); 81 | 82 | const vegFillings = demoFilter(fillings); 83 | const choppedFillings = demoMap(vegFillings); 84 | 85 | console.log('Final Ingredients -----------------'); 86 | demoForEach(bread); 87 | demoForEach(vegFillings, f => console.log(f.name)); 88 | demoForEach(sauce); 89 | 90 | /** 91 | * Expected output 92 | * { 93 | * sandwich: { 94 | * bread: '...', 95 | * fillings: [ item1, item2, ...] 96 | * sauce: [...] 97 | * } 98 | * } 99 | */ 100 | 101 | const sandwich = demoReduce(bread, choppedFillings, sauce); 102 | 103 | console.log('Here is your Sandwich! -----------------'); 104 | console.log(sandwich); 105 | 106 | reduceExampleExtra(); 107 | 108 | demoSome(); 109 | demoEvery(); 110 | demoFrom('a', 'b', 1, 2, { a: 'a' }); 111 | demoOf(); 112 | }; 113 | 114 | function demoSome() { 115 | const numbers = [1, 2, 3, 4, 5, 6, 7]; 116 | console.log(numbers.some(x => x % 2 === 0)); 117 | } 118 | 119 | function demoEvery() { 120 | const numbers = [1, 2, 3, 4, 5, 6, 7]; 121 | console.log(numbers.every(x => x % 2 === 0)); 122 | } 123 | 124 | function demoFrom() { 125 | console.log(Array.from([1, 2, 3, 4])); 126 | // Uncaught TypeError: arguments.forEach is not a function 127 | // because arguments is not any array 128 | // arguments.forEach(x => console.log(x)); 129 | // instead use Array.from 130 | const arrArgs = Array.from(arguments); 131 | arrArgs.forEach(x => console.log(x)); 132 | 133 | // use case of Array from using optional map function argument 134 | console.log(Array.from([1, 2, 3, 4], x => x * 2)); 135 | } 136 | 137 | function demoOf() { 138 | console.log(Array.of(1, 2, 3, 4, 5, 6)); 139 | } 140 | 141 | function reduceExampleExtra() { 142 | const input = [ 143 | { 144 | id: '1234', 145 | 'name': 'John Doe', 146 | 'age': 27, 147 | },{ 148 | id: '5678', 149 | 'name': 'James Bond', 150 | 'age': 31, 151 | }, 152 | ]; 153 | const output = input.reduce((acc, emp) => { 154 | // Use of object destructuring 155 | const { name, age } = emp; 156 | // Use of object literals 157 | acc[emp.id] = { name, age }; 158 | return acc; 159 | }, {}); 160 | 161 | console.log(input); 162 | console.log(output); 163 | } 164 | 165 | (context || this).demoLibs['array-func'] = demo; 166 | })(window); 167 | --------------------------------------------------------------------------------