Wednesday, March 29, 2017

ES6: Proxies

Proxies

Proxies allow you to overwrite the default behavior of certain operations such as get, set, etc. called ‘traps’. We can intercept certain functions and alter their default behavior using proxies.

const person = {name:’AK’, age: 26};

First it takes a target, which is what object you would like to proxy
Second, a handler which contains all the operations you wish to rewrite

const personProxy = new Proxy(person, {
get(target, name){
console.log(“Someone is requesting”, target, name);
return target[name].toUpperCase();
});
set(target, name,value){
if(typeof value === ‘string’) {
target[name] = value.trim().toLowerCase();
}
}

personProxy.name = “Arjun”; //setter saves lowercase trimmed value
personProxy.name; //getter returns uppercase Arjun




ES6: Generators

Generators

It is a function that you can start and stop, play and pause

Put an asterisk after function 

Uses yield keyword

function* listPeople(){
yield ‘AK’;
yield ‘BK’;
yield ‘CK’;
}

const people = listPeople();
-Returns a generator

Call .next() on it
Returns an Object

people.next();
-Returns AK object
people.next();
-Returns BK object

The generator has a ‘done’ property
After all yields are done, it gets set to true.


ES6: Maps and WeakMaps

Maps

If sets are to an array, maps are to an object

It has a key and a value instead of just values

const dogs = new Map();

- Call .set() to add something

dogs.set('Woofer',3);
dogs.set('Bowwower',5);

- .has() to check key
dogs.has('Woofer');
-true

- .get() to get value
dogs.get('Woofer');
-3

- .delete() to remove item
dogs.delete('Woofer');

You can iterate over Maps in 2 ways:
1.Use a forEach loop
dogs.forEach((val,key)=>console.log(val,key));
-Gives us all dogs
2.Use a for of loop
for(const dog of dogs){
    console.log(key,val);
}
//Can use destructing here
for(const [key,val] of dogs){
    console.log(key,val);
}
-Gives us an array of dogs

dogs.clear();

Useful for Meta-data tracking

We can use the object itself to get values instead of key strings

const clickCounts = new Map;
const buttons = document.querySelectorAll(‘button’);

buttons.forEach(button => clickCounts.set(button,0
button.addEventListener(‘click’, function(){
const val = clickCounts.get(this);
console.log(val);
clickCounts.set(this,val+1);
console.log(clickCounts);
});

));

WeakMap

Setting to null gets garbage collected, just like WeakSet

ES6: Sets and WeakSets

Set

A set is a unique array whose properties you can set only once.

You can’t access the items individually,
and it is not index based.

It is a list of items which we can add to, remove from and loop over

const people = new Set();
people.add(‘AK’);
people.add(‘BK’);
people.add(‘CK’);

>people.size
gives the length of the set

>people.delete(‘BK’);
deletes the item from the set without needing an index

>people.clear();
empties the set

>people.values();
We get a setIterator, which we can .next() over

const it = people.values();
it.next()
it.next()
You can also set a for of loop
for (const person of people){
console.log(person);
}

Declaring a set

1.Normal array like declaration
const students = new Set([‘AK’,’BK’,’CK’]);
2.Convert to set from an existing array
const dogs = [‘Woofer’,’Bowwower’];
const dogSet = new Set(dogs);

.has property
students.has(‘AK’);
-true

Set properties:
add
delete
clear
size
values

Example

Imagine you offer brunch in your restaurant and there is a line for it.
You can handle the line using Set.

const brunch = new Set();
brunch.add(‘AK’);
brunch.add(‘KB’)’
const line = brunch.values();
console.log(line.next().value); //line.next gives us the generator and .value gives us the value

When you call next on a Set, the item removes itself from the Set

You can still add people to the Set after using next

Weak Set

WeakSets can only contain an object type.
You can’t loop over it
There is no .clear() method
WeakSets clean themselves up. When the reference to an item is deleted, it garbage collects automatically

const weakSauce = new WeakSet([dog1, dog2]);

dog1 = null; //dog1 disappears after a few seconds automatically


Thursday, March 9, 2017

ES6 Classes and Extending Classes

1.class declaration

class Dog { //No paratheses after Dog

constructor(name,breed){
this.name=name;
this.breed=breed;
//Notice how we did not have to create const name and const breed

} //no comma here
//I repeat.. no comma after the function, just add on a new function below
bark(){
console.log(“Bark!”);
}
cuddle(){
console.log(“Love you owner”);
}
static info(){   //static method.
/*
Static method calls are made directly on the class and are not callable on instances of the class. Static methods are often used to create utility functions.
*/
console.log(“Dogs are nice”);
}
//getter 
//A getter is not a method. It is a property
get description(){
return(`${this.name} is breed ${this.breed}`);
}
//This getter would be called as dogObjectVariable.description;
//setter
set nicknames(value){
this.nick = value.trim(); //removes whitespaces
/*Setter note
Accessing the property setter by its own name inside the setter creates an infinite recursive function call.
So 
set nickname(valule){
this.nickname=value.trim();
would call setter nickname which calls setter nickname recursively causing a stack overflow
}
*/
}
//This setter would be set as dogObjectVariable.nicknames = "Snicky";
//getter for nicknames
get nicknames(){
return this.nick.toUpperCase(); 
}

}


const scooby = new Dog(“Scooby”,”Beagle”);


2.class expression

const Dog = class {

}

3.Extending classes and super

  class Animal {
    constructor(name) {
      this.name = name;
      this.thirst = 100;
      this.belly = [];
    }
    drink() {
      this.thirst -= 10;
      return this.thirst;
    }
    eat(food) {
      this.belly.push(food);
      return this.belly;
    }
  }

  class Dog extends Animal {
    constructor(name, breed) {
      super(name); //super initializes the class that this class is based off of
      this.breed = breed;
    }
    bark() {
      console.log('Bark bark I\'m a dog');
    }
  }

  const rhino = new Animal('Rhiney');
  const snickers = new Dog('Snickers', 'King Charles');

4.Extending arrays
We can create our own classes that are based on arrays.

  class MovieCollection extends Array {
    constructor(name, ...items) {
      super(...items);
      this.name = name;
    }
    add(movie) {
      this.push(movie);
    }
    topRated(limit = 10) {
      return this.sort((a, b) => (a.stars > b.stars ? -1 : 1)).slice(0, limit);
    }
  }

  const movies = new MovieCollection('Wes\'s Fav Movies',
    { name: 'Bee Movie', stars: 10 },
    { name: 'Star Wars Trek', stars: 1 },
    { name: 'Virgin Suicides', stars: 7 },
    { name: 'King of the Road', stars: 8 }
  );

  movies.add({ name: 'Titanic', stars: 5 });


*Whenever you extend a class, you need to create the thing that you’re extending first before you create a class of what you want. Just  call:
super();

*for…of loop only loops over iterable items

Saturday, March 4, 2017

ES6 Symbols

Primitive types:
Number
string
object
boolean
null
undefined

7th primitive type is symbol

Symbols are unique
We can’t loop over them

  const classRoom = {
    
    'Ganesh':{grade:50, gender:'male'},
    'Bunty':{grade:60, gender:'male'},
    'Bunty':{grade:70, gender:'female'},

  };
  //Instead of doing the above, we could use symbols

  const symbolRoom = {
    
    [Symbol('Ganesh')]:{grade:50, gender:'male'},
    [Symbol('Bunty')]:{grade:60, gender:'male'},
    [Symbol('Bunty')]:{grade:70, gender:'female'},

  };

//symbols are not enumerable
 //but we can grab all the symbols contained by symbolRoom

  const syms=Object.getOwnPropertySymbols(symbolRoom);
  //syms.forEach(sym=>{console.log(sym.value)});
  //forEach doesn't work here
  //But we can map over the symbols
  //symbols here are keys for the array symbolRoom, so we can access them
  const symbolData=syms.map(sym=> symbolRoom[sym]);
  console.table(symbolData);
  //Remember that Symbol starts with a capital S!

ES6 Promises

To begin with, fetch is an inbuilt method built into the browser and it works like ajax.
fetch() returns a promise, not immediate data.
A promise promises data that is not going to come immediately, but sometime in the future.

The ‘then’ function is a callback. It runs only when data comes back
‘then’ only runs when data successfully comes back
‘catch’ runs when there is an error

const postPromise = fetch(http://stuff);
postPromise //It doesn’t yet know that we expect json data
.then(data=>data.json()) //Converts to json
.then(data=>console.log(data) //prints the actual data
.catch(err=>{console.error(err);})

Manually creating a promise

const prom=new Promise((resolve,reject)=>{
resolve(“i am cool”); //Immediately resolves the promise
});
prom
.then(data=>{console.log(data);})
.catch(err=>console.error(err));
//prints “I am cool”

const prom=new Promise((resolve,reject)=>{
reject(Error(“i ain\’t cool”)); //Immediately rejects the promise
//**Wrap the error message in an ‘Error’ object
//to ensure that the error thrown shows the line no.
}); **/
prom
.then(data=>{console.log(data);})
.catch(err=>console.error(err));

//.all waits for all promises passed to complete
//.all is not on the prototype, it is in the class
Promise
.all([promise1,promise2])
.then(data=>{console.log(data);});


*It is nice to use arrow functions in setTimeout, so that it inherits ‘this’ from the parent element.

Spread and Rest

If we have to combine arrays, spread could come in handy.

const pizzas=["A","B","C"];
const special=["F","G","H"];

If we had to put "D" and "E" between those, we'd have to perform several concat() functions.
With spread, this becomes easy

const combined=[...pizzas,"D","E",...special]; //voila!

Spread takes the elements of an array and separately places those elements where the array was, i.e, inside the container!

Rest is the opposite of spread. While spread unpacks items in a container, rest can pack items into a variable. This can come in handy when we are using the arguments of an array and we want to address only say, the first two arguments first and then deal with the remaining 13 later.

sumJustTwo(12,51,16,27,515);

function sumJustTwo(a,b,...otherNumbers){
console.log("The sum of first two arguments is ",a+b);
}

ES6 Array: From, of, find and findIndex

Array.from - turns array-ish things into arrays
Array.of - creates arrays from arguments
These 2 are not on the prototype, they are a part of the Array class itself.

Array.from might be useful if we need to use something like a map function on a nodelist
We know that document.querySelectorAll(); returns a nodelist and not an array.
Thus, it is array-ish.

Array.from takes in a second argument which gives us the ability to map over that array
const peopleArray = Array.from(people, person=>person.textContent);

Another case would be if we have a function like 
sumAll(1,2,3,4,5,5,63,2,4,39);
We can handle its arguments like 
function sumAll(){
const nums=Array.from(arguments);
}
and then perform a reduce on it like
const total= nums.reduce((prev,next)=>{return prev+next;},0)

posts.find(post=> post.code===code);//returns the entry itself
posts.findIndex(post=> post.code===code);//returns the array's index # of the first entry that satisfies the condition


const doSomeSatisfy = ages.some(age=>age>10);
const doAllSatisty = ages.every(age=>age>10);