Destructuring is an expression available in ES6 which enables a succinct and convenient way to extract values of Objects or Arrays and place them into distinct variables.
Array Destructuring
// Variable assignment.constfoo=['one','two','three'];const[one,two,three]=foo;console.log(one);// "one"console.log(two);// "two"console.log(three);// "three"// Swapping variablesleta=1;letb=3;[a,b]=[b,a];console.log(a);// 3console.log(b);// 1Object Destructuring
// Variable assignment.consto={p: 42,q: true};const{ p, q }=o;console.log(p);// 42console.log(q);// true1. Template Strings
Template literals are string literals allowing embedded expressions.
Benefits
- String interpolation
- Embedded expressions
- Multiline strings without hacks
- String formatting
- String tagging for safe HTML escaping, localization and more
letgreeting=`Hello World!`;// String Substitutionletname="Alex";console.log(`Hi, ${name}!`);// Output: "Hi, Alex!"// Multiline Stringsletgreeting="Hello \World";// Tagged Templatesfn`Hello ${you}! You're looking ${adjective} today!`2. Spread Operator
Spread operator allows iterables( arrays / objects / strings ) to be expanded into single arguments/elements.
functionsum(x,y,z){returnx+y+z;}constnumbers=[1,2,3];console.log(sum(...numbers));// 6console.log(sum.apply(null,numbers));// 62.1. Copying an array
letfruits=['Apple','Orange','Banana'];letnewFruitArray=[...fruits];console.log(newFruitArray);// ['Apple','Orange','Banana']2.2. Concatenating arrays
letarr1=['A','B','C'];letarr2=['X','Y','Z'];letresult=[...arr1, ...arr2];console.log(result);// ['A', 'B', 'C', 'X', 'Y', 'Z']2.3. Spreading elements together with an individual element
letfruits=['Apple','Orange','Banana'];letnewFruits=['Cherry', ...fruits];console.log(newFruits);// ['Cherry', 'Apple','Orange','Banana']2.4. Spreading elements on function calls
letfruits=['Apple','Orange','Banana'];vargetFruits=(f1,f2,f3)=>{console.log(`Fruits: ${f1}, ${f2} and ${f3}`);};getFruits(...fruits);// Fruits: Apple, Orange and Banana2.5. Spread syntax for object literals
varobj1={id: 101,name: 'Jhon Doe'}varobj2={age: 25,country: 'USA'}constemployee={ ...obj1, ...obj2}console.log(employee);//{ "id": 101, "name": "Jhon Doe", "age": 25, "country": "USA" }3. Sets
Sets are a new object type with ES6 (ES2015) that allow to create collections of unique values. The values in a set can be either simple primitives like strings or integers, but more complex object types like object literals or arrays can also be part of a set.
letanimals=newSet();animals.add('🐷');animals.add('🐼');animals.add('🐢');animals.add('🐿');console.log(animals.size);// 4animals.add('🐼');console.log(animals.size);// 4console.log(animals.has('🐷'));// trueanimals.delete('🐷');console.log(animals.has('🐷'));// falseanimals.forEach(animal=>{console.log(`Hey ${animal}!`);});// Hey 🐼!// Hey 🐢!// Hey 🐿!animals.clear();console.log(animals.size);// 0// Example 02: Pass-In ArrrayletmyAnimals=newSet(['🐷','🐢','🐷','🐷']);myAnimals.add(['🐨','🐑']);myAnimals.add({name: 'Rud',type: '🐢'});console.log(myAnimals.size);// 4myAnimals.forEach(animal=>{console.log(animal);});// 🐷// 🐢// ["🐨", "🐑"]// Object { name: "Rud", type: "🐢" }// Example 03: Strings are a valid iterable so they can also be passed-in to initialize a setconsole.log('Only unique characters will be in this set.'.length);// 43letsentence=newSet('Only unique characters will be in this set.');console.log(sentence.size);// 18// Example 04: On top of using forEach on a set, for…of loops can also be used to iterate over setsletmoreAnimals=newSet(['🐺','🐴','🐕','🐇']);for(letanimalofmoreAnimals){console.log(`Howdy ${animal}`);}// Howdy 🐺// Howdy 🐴// Howdy 🐕// Howdy 🐇Sets: Keys and Values
Sets also have the keys and values methods, with keys being an alias for values, so both methods do exactly the same thing. Using either of these methods returns a new iterator object with the values of the set in the same order in which they were added to the set.
letpartyItems=newSet(['🍕','🍾','🎊']);letitems=partyItems.values();console.log(items.next());console.log(items.next());console.log(items.next());console.log(items.next().done);// Object {// done: false,// value: "🍕"// }// Object {// done: false,// value: "🍾"// }// Object {// done: false,// value: "🎊"// }// true4. Default Parametrs
functionadd(x=10,y=20){console.log(x+y);}add(30,40);// 705. repeat()
The repeat() method constructs and returns a new string which contains the specified number of copies of the string on which it was called, concatenated together.
varcat={meow(times){console.log("meow ".repeat(times));}};cat.meow(2);// meow meow 6. Arrow Function (=>)
varadd=(x,y)=>x+y;console.log(add(10,20));// 30;7. Arrow function with this
varperson={first: "Alex",actions: ["bike","hike","ski","surf"],printActions: function(){var_this=this;this.actions.forEach(function(action){varstr=_this.first+" likes to "+action;console.log(str);});}};person.printActions();//ES-6varperson={first: "Alex",actions: ["bike","hike","ski","surf"],printActions(){this.actions.forEach(action=>{varstr=this.first+" likes to "+action;console.log(str);});}};8. Destructing Assignment
varphone={title: "iPhone",price: 800,description: "The iPhone is a smartphone developed by Apple"};console.log(phone.title);//ES-6var{ title, price, description }={title: "iPhone",price: 800,description: "The iPhone is a smartphone developed by Apple"};console.log(title);// iPhone9. Generators
A generator is a function that can stop midway and then continue from where it stopped. In short, a generator appears to be a function but it behaves like an iterator.
function*generator(num){yieldnum+1;yieldnum+2;yieldnum+3;yieldnum+4;yieldnum+5;}vargen=generator(10);console.log(gen.next().value);// 11console.log(gen.next().value);// 12console.log(gen.next().value);// 13console.log(gen.next().value);// 14console.log(gen.next().value);// 159.1. Implementing Iterables
function*iterableObj(){yield'This';yield'is';yield'iterable.'}for(constvalofiterableObj()){console.log(val);}// This// is // iterable.9.2 Infinite Data Streams
function*naturalNumbers(){letnum=1;while(true){yieldnum;num=num+1}}constnumbers=naturalNumbers();console.log(numbers.next().value)// 1console.log(numbers.next().value)// 2Advantages of Generators
a) Lazy Evaluation: Lazy Evaluation is an evaluation model which delays the evaluation of an expression until its value is needed.
b) Memory Efficient: We generate only the values that are needed. With normal functions, we needed to pre-generate all the values and keep them around in case we use them later. However, with generators, we can defer the computation till we need it.
10. Symbols()
They are tokens that serve as unique IDs. We create symbols via the factory function Symbol()
constsymbol1=Symbol();constsymbol2=Symbol(42);constsymbol3=Symbol('foo');console.log(typeofsymbol1);// symbolconsole.log(symbol3.toString());// Symbol(foo)console.log(Symbol('foo')===Symbol('foo'));// falseUsage
Symbols primary use case is for making private object properties, which can be only of type String or Symbol (Numbers are automatically converted to Strings).
constsym=Symbol()constprivateObject={[sym]: 'Hello World'}privateObject[sym]// 'Hello World'10.1 Global Symbols
A Global Symbol Registry exists where we can store and access Global Symbols. We can use the Symbol.for(key) method to both create and access Global Symbols.
constsym1=Symbol.for('hello')// If the Symbol does not exist, it's createdconstsym2=Symbol.for('hello')// The Symbol exists, so it is returnedsym1===sym2// true11. Iterator
The iterable is a interface that specifies that an object can be accessible if it implements a method who is key is [symbol.iterator].
vartitle='ES6';variterateIt=title[Symbol.iterator]();console.log(iterateIt.next().value);//output: Econsole.log(iterateIt.next().value);//output: Sconsole.log(iterateIt.next().value);//output: 6Template literals help make it simple to do string interpolation, or to include variables in a string. Before ES2015, it was common to do something like this:
varperson={name: 'Tyler',age: 28};console.log('Hi, my name is '+person.name+' and I am '+person.age+' years old!');// 'Hi, my name is Tyler and I am 28 years old!'With template literals, you can now create that same output like this instead:
constperson={name: 'Tyler',age: 28};console.log(`Hi, my name is ${person.name} and I am ${person.age} years old!`);// 'Hi, my name is Tyler and I am 28 years old!'Note that you use backticks, not quotes, to indicate that you are using a template literal and that you can insert expressions inside the ${} placeholders.
A second helpful use case is in creating multi-line strings. Before ES2015, you could create a multi-line string like this:
console.log('This is line one.\nThis is line two.');// This is line one.// This is line two.Or if you wanted to break it up into multiple lines in your code so you didn't have to scroll to the right in your text editor to read a long string, you could also write it like this:
console.log('This is line one.\n'+'This is line two.');// This is line one.// This is line two.Template literals, however, preserve whatever spacing you add to them. For example, to create that same multi-line output that we created above, you can simply do:
console.log(`This is line one.This is line two.`);// This is line one.// This is line two.Another use case of template literals would be to use as a substitute for templating libraries for simple variable interpolations:
constperson={name: 'Tyler',age: 28};document.body.innerHTML=` <div> <p>Name: ${person.name}</p> <p>Name: ${person.age}</p> </div>`The main advantage of using an arrow function as a method inside a constructor is that the value of this gets set at the time of the function creation and can't change after that. So, when the constructor is used to create a new object, this will always refer to that object.
constPerson=function(firstName){this.firstName=firstName;this.sayName1=function(){console.log(this.firstName);};this.sayName2=()=>{console.log(this.firstName);};};constjohn=newPerson('John');constdave=newPerson('Dave');john.sayName1();// Johnjohn.sayName2();// John// The regular function can have its 'this' value changed, but the arrow function cannotjohn.sayName1.call(dave);// Dave (because "this" is now the dave object)john.sayName2.call(dave);// Johnjohn.sayName1.apply(dave);// Dave (because 'this' is now the dave object)john.sayName2.apply(dave);// Johnjohn.sayName1.bind(dave)();// Dave (because 'this' is now the dave object)john.sayName2.bind(dave)();// JohnvarsayNameFromWindow1=john.sayName1;sayNameFromWindow1();// undefined (because 'this' is now the window object)varsayNameFromWindow2=john.sayName2;sayNameFromWindow2();// JohnThe main takeaway here is that this can be changed for a normal function, but the context always stays the same for an arrow function. So even if you are passing around your arrow function to different parts of your application, you wouldn't have to worry about the context changing.
An arrow function is a shorter syntax for a function expression and does not have its own this, arguments, super, or new.target. These function are best suited for non-method functions, and they cannot be used as constructors.
Arrow functions in ES6 has two limitations:
- Don't work with new
- Fixed this bound to scope at initialisation
When should not use Arrow Functions
1. Object methods
When you call cat.jumps, the number of lives does not decrease. It is because this is not bound to anything, and will inherit the value of this from its parent scope.
varcat={lives: 9,jumps: ()=>{this.lives--;}}2. Callback functions with dynamic context
If we click the button, we would get a TypeError. It is because this is not bound to the button, but instead bound to its parent scope.
varbutton=document.getElementById('press');button.addEventListener('click',()=>{this.classList.toggle('on');});- Promises
constdelay=seconds=>{returnnewPromise(resolve=>{setTimeout(resolve,seconds*1000)});};console.log("Zero seconds wait");delay(1).then(()=>console.log('One seconds wait'));delay(5).then(()=>console.log('Five seconds wait'));- Loading data with fetch()
constgetPeopleInSpace=()=>fetch('http://api.open-notify.org/astros.json').then(res=>res.json());getPeopleInSpace().then(console.log);- Async() and await()
constdelay=seconds=>{returnnewPromise(resolve=>setTimeout(resolve,seconds*1000))};constcountToFive=async()=>{console.log('zero seconds wait');awaitdelay(2);console.log('Two seconds wait');awaitdelay(5);console.log('Five seconds wait');}countToFive();- Async with fetch
constgithubRequest=async(loginName)=>{try{varresponse=awaitfetch(`http://api.github.com/users/${loginName}/followers`);varjson=awaitresponse.json();varfollowerList=json.map(user=>user.login);console.log(followerList);}catch(e){console.log("Data didn't load",e);}};//githubRequest('eveporcello');githubRequest('pradeepkumar2');Arrow functions
Arrows is a new syntax for functions, which brings several benefits:
- Arrow syntax automatically binds
thisto the surrounding code’s context - The syntax allows an implicit return when there is no body block, resulting in shorter and simpler code in some cases
- Last but not least,
=>is shorter and simpler thanfunction, although stylistic issues are often subjective
//arrow function with no parametersvara1=()=>1;//arrow with one parameter can be defined without parenthesesvara2=x=>1;vara3=(x)=>1;//arrow with multiple params requires parenthesesvara4=(x,y)=>1;//arrow with body has no implicit returnvara5=x=>{return1;};// ES5 Function ConstructorfunctionPerson(name){this.name=name;}// ES6 ClassclassPerson{constructor(name){this.name=name;}}For simple constructors, they look pretty similar.
The main difference in the constructor comes when using inheritance. If we want to create a Student class that subclasses Person and add a studentId field, this is what we have to do in addition to the above.
// ES5 Function ConstructorfunctionStudent(name,studentId){// Call constructor of superclass to initialize superclass-derived members.Person.call(this,name);// Initialize subclass's own members.this.studentId=studentId;}Student.prototype=Object.create(Person.prototype);Student.prototype.constructor=Student;// ES6 ClassclassStudentextendsPerson{constructor(name,studentId){super(name);this.studentId=studentId;}}It's much more verbose to use inheritance in ES5 and the ES6 version is easier to understand and remember.
ES6's spread syntax is very useful when coding in a functional paradigm as we can easily create copies of arrays or objects without resorting to Object.create, slice, or a library function. This language feature is used often in Redux and Rx.js projects.
functionaddCookiesInArray(arr){return[...arr,'Cookies'];}constresult=addCookiesInArray(['I','really',"don't",'like']);console.log(result);// ["I", "really", "don't", "like", "Cookies"]constperson={name: 'Todd',age: 29,};constcopyOfPerson={ ...person};console.log(copyOfPerson);// {name: "Todd", age: 29}ES6's rest syntax offers a shorthand for including an arbitrary number of arguments to be passed to a function. It is like an inverse of the spread syntax, taking data and stuffing it into an array rather than unpacking an array of data, and it works in function arguments, as well as in array and object destructuring assignments.
functionaddFiveToABunchOfNumbers(...numbers){returnnumbers.map(x=>x+5);}constresult=addFiveToABunchOfNumbers(4,5,6,7,8,9,10);// [9, 10, 11, 12, 13, 14, 15]const[a,b, ...rest]=[1,2,3,4];// a: 1, b: 2, rest: [3, 4]const{ e, f, ...others}={e: 1,f: 2,g: 3,h: 4,};// e: 1, f: 2, others: { g: 3, h: 4 }Variables declared using the var keyword are scoped to the function in which they are created, or if created outside of any function, to the global object. let and const are block scoped, meaning they are only accessible within the nearest set of curly braces (function, if-else block, or for-loop).
functionfoo(){// All variables are accessible within functions.varbar='bar';letbaz='baz';constqux='qux';console.log(bar);// barconsole.log(baz);// bazconsole.log(qux);// qux}console.log(bar);// ReferenceError: bar is not definedconsole.log(baz);// ReferenceError: baz is not definedconsole.log(qux);// ReferenceError: qux is not definedif(true){varbar='bar';letbaz='baz';constqux='qux';}// var declared variables are accessible anywhere in the function scope.console.log(bar);// bar// let and const defined variables are not accessible outside of the block they were defined in.console.log(baz);// ReferenceError: baz is not definedconsole.log(qux);// ReferenceError: qux is not definedvar allows variables to be hoisted, meaning they can be referenced in code before they are declared. let and const will not allow this, instead throwing an error.
console.log(foo);// undefinedvarfoo='foo';console.log(baz);// ReferenceError: can't access lexical declaration 'baz' before initializationletbaz='baz';console.log(bar);// ReferenceError: can't access lexical declaration 'bar' before initializationconstbar='bar';Redeclaring a variable with var will not throw an error, but 'let' and 'const' will.
varfoo='foo';varfoo='bar';console.log(foo);// "bar"letbaz='baz';letbaz='qux';// Uncaught SyntaxError: Identifier 'baz' has already been declaredlet and const differ in that let allows reassigning the variable's value while const does not.
// This is fine.letfoo='foo';foo='bar';// This causes an exception.constbaz='baz';baz='qux';- for in: loops over enumerable property names of an object.
- for of: (new in ES6) does use an object-specific iterator and loops over the values generated by that.
Both for..of and for..in statements iterate over lists; the values iterated on are different though, for..in returns a list of keys on the object being iterated, whereas for..of returns a list of values of the numeric properties of the object being iterated.
Example:
letlist=[4,5,6];for(letiinlist){console.log(i);// "0", "1", "2",}for(letioflist){console.log(i);// "4", "5", "6"}In ES6, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a “temporal dead zone” from the start of the block until the initialization is processed.
console.log(aVar);// undefinedconsole.log(aLet);// causes ReferenceError: aLet is not definedvaraVar=1;letaLet=2;Map
It is used to associate a key to a value irrespective of the datatype such as strings, numbers, objects etc. To assign values to a map you need to use the set method:
window.obj={}varmap=newMap()map.set(window.obj,123)Then, to retrieve the object call get:
map.get(window.obj)// => 123WeakMap
WeakMap accepts only objects but not any primitive values (strings, numbers)
functionObj(){this.val=newArray(10000000).join("---")}window.obj=newObj();varmap=newWeakMap()map.set(window.obj,123)deletewindow.objDifferences between Map and WeakMap
- A WeakMap accepts only objects as keys whereas a Map,in addition to objects, accepts primitive datatype such as strings, numbers etc.
- WeakMap objects doesn't avert garbage collection if there are no references to the object which is acting like a key. Therefore there is no method to retrieve keys in WeakMap, whereas in Map there are methods such as Map.prototype.keys() to get the keys.
- There is no size property exists in WeakMap.
Browser support for Map and WeakMap
The latest Chrome, Firefox, Edge and Safari support Map and WeakMap on desktop. It's supported only in IE11 but not IE10 and below. On mobile, newer browsers also have support, but IE Mobile doesn't.
A variable can be assigned a default value when the value unpacked from the array or object is undefined during destructuring assignment. It helps to avoid setting default values separately for each assignment.
Array Destructuring
varx,y,z;[x=2,y=4,z=6]=[10];console.log(x);// 10console.log(y);// 4console.log(z);// 6Object Destructuring
var{x=2, y=4, z=6}={x: 10};console.log(x);// 10console.log(y);// 4console.log(z);// 6varx=10,y=20;[x,y]=[y,x];console.log(x);// 20console.log(y);// 10[...'John']Output: ['J', 'o', 'h', 'n']
Explanation: The string is an iterable type and the spread operator with in an array maps every character of an iterable to one element. Hence, each character of a string becomes an element within an Array.
Making objects, functions, classes or variables available to the outside world is as simple as exporting them, and then importing them where needed in other files.
Benefits
- Code can be split into smaller files of self-contained functionality.
- The same modules can be shared across any number of applications.
- Ideally, modules need never be examined by another developer, because they’ve has been proven to work.
- Code referencing a module understands it’s a dependency. If the module file is changed or moved, the problem is immediately obvious.
- Module code (usually) helps eradicate naming conflicts. Function
x()in module1 cannot clash with function x() in module2. Options such as namespacing are employed so calls becomemodule1.x()andmodule2.x().
Exporting
exportconstmyNumbers=[1,2,3,4];constanimals=['Panda','Bear','Eagle'];// Not available directly outside the moduleexportfunctionmyLogger(){console.log(myNumbers,animals);}exportclassAlligator{constructor(){// ...}}Exporting with alias
export{myNumbers,myLoggerasLogger,Alligator}Default export
exportconstmyNumbers=[1,2,3,4];constanimals=['Panda','Bear','Eagle'];exportdefaultfunctionmyLogger(){console.log(myNumbers,pets);}exportclassAlligator{constructor(){// ...}}The trampoline is just a technique to optimize recursion and prevent stack-overflow exceptions in languages that don't support tail call optimization like Javascript ES5 implementation. However, ES6 will probably have support for tail call optimization.
The problem with regular recursion is that every recursive call adds a stack frame to the call stack, which you can visualize as a pyramid of calls. Here is a visualization of calling a factorial function recursively:
(factorial 3)
(* 3 (factorial 2))
(* 3 (* 2 (factorial 1)))
(* 3 (* 2 (* 1 (factorial 0)))) (* 3 (* 2 (* 1 1)))
(* 3 (* 2 1))
(* 3 2)
6
Here is a visualization of the stack where each vertical dash is a stack frame:
---|---
---| |---
---| |--- --- ---
The problem is that the stack has limited size, and stacking up these stack frames can overflow the stack. Depending on the stack size, a calculation of a larger factorial would overflow the stack. That is why regular recursion in Javascript could be considered dangerous.
An optimal execution model would be something like a trampoline instead of a pyramid, where each recursive call is executed in place, and does not stack up on the call stack. That execution in languages supporting tail call optimization could look like:
(fact 3)
(fact-tail 3 1)
(fact-tail 2 3)
(fact-tail 1 6)
(fact-tail 0 6)
6
You can visualize the stack like a bouncing trampoline:
---|--- ---|--- ---|---
--- --- --- This is clearly better since the stack has always only one frame, and from the visualization you can also see why it is called a trampoline. This prevents the stack from overflowing.
Since we don't have the luxury of tail call optimization in Javascript, we need to figure out a way to turn regular recursion into an optimized version that will execute in trampoline-fashion.
One obvious way is to get rid of recursion, and rewrite the code to be iterative.
When that is not possible we need a bit more complex code where instead of executing directly the recursive steps, we will utilize higher order functions to return a wrapper function instead of executing the recursive step directly, and let another function control the execution.
In your example, the repeat function wraps the regular recursive call with a function, and it returns that function instead of executing the recursive call:
functionrepeat(operation,num){returnfunction(){if(num<=0)returnoperation()returnrepeat(operation,--num)}}The returned function is the next step of recursive execution and the trampoline is a mechanism to execute these steps in a controlled and iterative fashion in the while loop:
functiontrampoline(fn){while(fn&&typeoffn==='function'){fn=fn()}}So the sole purpose of the trampoline function is to control the execution in an iterative way, and that ensures the stack to have only a single stack frame on the stack at any given time.
Using a trampoline is obviously less performant than simple recursion, since you are "blocking" the normal recursive flow, but it is much safer.
Set
Using the Set() class we can create an array like heterogeneous iterable object, which will contain only unique values in it. Unique is not just unique by values but also by types. i.e. it will consider "2" and 2 separate or different.
Syntax:
varmySet=newSet([iterable]);Example:
varmySet=newSet([0,1]);mySet.add(2);// 0, 1, 2mySet.add(2);// 0, 1, 2mySet.add("Hello");// 0, 1, 2, 'Hello'mySet.add({a:1,b:2});// 0, 1, 2, 'Hello', {a:1, b:2}mySet.add(function(){});// 0, 1, 2, 'Hello', {a:1, b:2}, [Function]mySet.has("Hello");// turemySet.delete("Hello");// 'Hello' deletedmySet.has("Hello");// falsemySet.size;// 5mySet.clear();// Set ClearedWeakSet
A WeakSet() is a collection similar to Set, which holds unique values; but it only holds Objects and nothing else. If an object which is there in your WeakSet object has no other reference variable left, it will automatically be deleted.
Syntax:
varmyWeakSet=newWeakSet([iterablewithonlyobjects]);Example:
varmyWeakSet=newWeakSet([{a:1}]);varobj1={o:1};varobj2={o:2};myWeakSet.add(obj1);myWeakSet.has(obj1);// truemyWeakSet.has(obj2);// falsemyWeakSet.add(obj2);myWeakSet.has(obj2);// truedeleteobj2;// Don't take it literally - you can't delete objects like that. Use scope to execute this.myWeakSet.has(obj2);// false, because you deleted obj2, so WeakSet releases it automaticallymyWeakSet.delete(obj1);// obj1 deleted from the setmyWeakSet.add(2);// ERROR, no primitive value| Set | WeakSet |
|---|---|
| Can contain any type of values | Can only contain objects |
| To find number of elements use .size | To find elements count use .length |
| .forEach() is available to iterate | No .forEach() to iterate |
| Nothing is auto destroyed | If an element object has no other reference left, it will be auto released to garbage collector |
XMLHttpRequest
XMLHttpRequest() is a built-in browser object that allows to make HTTP requests in JavaScript. XMLHttpRequest has two modes of operation: synchronous and asynchronous.
if(window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safarixhr=newXMLHttpRequest();}else{// code for IE6, IE5xhr=newActiveXObject('Microsoft.XMLHTTP');}xhr.onreadystatechange=function(){if(this.readyState==4&&this.status==200){console.log(this.responseText);}};xhr.open('GET','https://jsonplaceholder.typicode.com/posts',true);// this makes asynchronous true or falsexhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');xhr.send();Fetch
Fetch allows to make network requests similar to XMLHttpRequest. Fetch makes it easier to make asynchronous requests and handle responses better than with the older XMLHttpRequest. It is an improvement over the XMLHttpRequest API. The main difference between Fetch() and XMLHttpRequest() is that the Fetch API uses Promises, hence avoiding callback hell.
Fetch Interfaces
- fetch(): The fetch() method used to fetch a resource.
- Headers: Represents response/request headers, allows to query them and take different actions depending on the results.
- Request: Represents a resource request.
- Response: Represents the response to a request.
Making a request using fetch()
A fetch() function is available in the global window object. The fetch() function takes one mandatory argument, the path to the resource you want to fetch. It returns a Promise, whether it is successful or not. If request is successful .then() function will receive Response object, if request fails then .catch() function will receive an error object
fetch('https://api.github.com/users/learning-zone').then(function(response){returnresponse.json();}).then(function(data){console.log(data);}).catch(function(err){console.log("Something went wrong!",err);});Headers Object
The Headers interface allows to create own headers object via the Headers() constructor. A headers object is a collection of name-value pairs.
letreqHeader=newHeaders();reqHeader.append('Content-Type','text/json');letinitObject={method: 'GET',headers: reqHeader,};fetch('https://api.github.com/users/learning-zone',initObject).then(function(response){returnresponse.json();}).then(function(data){console.log(data);}).catch(function(err){console.log("Something went wrong!",err);});Request Object
The Request Object represents a resource request. Instead of passing an URL of the resource into the fetch() call, you can create a request object using the Request() constructor, and pass that as an argument to fetch(). By passing Request object to the fetch(), you can make customised requests.
letreqHeader=newHeaders();reqHeader.append('Content-Type','text/json');letinitObject={method: 'GET',headers: reqHeader,};varuserRequest=newRequest('https://api.github.com/users/learning-zone',initObject);fetch(userRequest).then(function(response){returnresponse.json();}).then(function(data){console.log(data);}).catch(function(err){console.log("Something went wrong!",err);});Promises are a tool for managing asynchronous operations. They keep track of when asynchronous operations complete and what their results are and let you coordinate that completion and those results (including error conditions) with other code or other asynchronous operations. They aren't actually asynchronous operations in themselves. An Ajax call is a specific asynchronous operation that can be used with with a traditional callback interface or wrapped in a promise interface.
An Ajax call is a specific type of asynchronous operation. We can make an Ajax call either with a traditional callback using the XMLHttpRequest() interface or we can make an Ajax call (in modern browsers), using a promise with the fetch() interface.
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
There are 3 key terms we need to define before we proceed:
- handler — the placeholder object which contains the trap(s)
- traps — the method(s) that provide property access
- target — object which the proxy virtualizes
Syntax
constp=newProxy(target,handler)Example:
consthandler={get: function(obj,prop){returnpropinobj ?
obj[prop] :
37;}};constp=newProxy({},handler);p.a=1;p.b=undefined;console.log(p.a,p.b);// 1, undefinedconsole.log('c'inp,p.c);// false, 37There are many real-world applications for Proxies
- validation
- value correction
- property lookup extensions
- tracing property accesses
- revocable references
- implementing the DOM in javascript