AddThis

Showing posts with label ecmascript. Show all posts
Showing posts with label ecmascript. Show all posts

Monday, March 21, 2016

Arrow Functions

I love the new arrow function in EcmaScript 6.  I use it for everything, pretty much all the time :)

Quick Rundown


Basic Form


var add = (numberOne, numberTwo) => {
  return numberOne + numberTwo;
};
add(1, 2);
//returns 3

Here I'm creating a function named add that takes two parameters, numberOne and numberTwo.  This function will return the two numbers added together.  When the body of the function is a single expression, we can write this even more concisely.


var add = (numberOne, numberTwo) => numberOne + numberTwo;

At first glance, this looks just like a different syntax for creating a function.  But there's more to it than that.  Inside of the arrow function, there is no new 'this' pointer defined.

Let's look at an example (taken from MSDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions):

function Person() {
  var self = this; // Some choose `that` instead of `self`.
                   // Choose one and be consistent.
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}

Notice the strange self variable we had to create in order to access age.  This is because the function growUp gets a brand new 'this' pointer that is quite different than the 'this' pointer inside of Person.  That means that when growUp is called, calling this.age will not work, because there is no 'age' variable inside of the growUp function.  The new fat arrow fixes this:


function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

Notice that 'this' can correctly find and use the age variable.  This is very nice and just feels much better overall.


Gotchas

1.  Returning an object literal needs to be wrapped in parens.


const gimmeFoo = () => {  foo: 1  };
//will not work!  calling gimmeFoo() returns undefined

instead do this:

const gimmeFoo = () => ({  foo: 1  }); 

2.  You also cannot override the 'this' inside of an arrow function.  That means that bind is useless here, so don't try it.  Same thing for call and apply.  You can still pass in arguments, but you cannot override 'this'.

3.  You also don't have access to the 'arguments' variable, but a good workaround is to use rest parameters (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), which we won't cover here.

var f = (...args) => args[0];

4.  Even if you don't have arguments, you still need the parens:

const gimmeHi = () => 'hi';

but you can also do this:

const gimmeHi = _ => 'hi';
That's pretty much it! Go forth and start using it :)

Thursday, October 30, 2014

JavaScript Generators

Intro

One of the things people are really excited about that is coming in EcmaScript6 (Harmony) are generators.  There is a lot of writing out there today on generators but for the most part, I found the writing to be too quick to skip over the fundamental question of what they are.  Basically I was looking for a tl;dr.  Cuz ain't nobody got time for that.






Definition

I actually really like Mozilla's definition.  Short and sweet:
"Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances."

Allow me to paraphrase:
tl;dr Generators are special functions that save their variable state between calls.






Example

Now that you got the basic idea, let's look at an example.

First notice that the function definition has an asterick *.

//will double the number passed in
function* doubler(i){
  var doubled = i;
  while(true){
    doubled *= 2;
    yield doubled;
  }
}


Next notice the yield keyword.  We'll come back to that.  Let's take a look at the usage.

var gen = doubler(1);


The interesting thing is that calling doubler doesn't actually invoke the function.  A special object called an iterator is returned.  So gen holds an iterator, so lets see how to use that:

var result = gen.next();


Calling the next method on the iterator actually runs the doubler function, but stops when it hits the keyword yield (told you we'd come back to it).  And whatever you pass to yield (in this case the variable doubled), the iterator returns that.  So line by line:

var doubled = i;
//remember from above that i is 1, var gen = doubler(1);

while(true) {
 //nothing says that the iterator has to terminate. 
 //it can go on forever like this one does

  doubled *= 2;
  //doubled was 1, now its 2, b/c well 1*2 is 2

  yield doubled;
  //the iterator will stop here for now and return 2
}


So there you go, result should be 2.  Conceptually, that's sufficient to say, but in practice, the iterator takes 'doubled' and wraps it inside of a result object.  The result object has two attributes:

1.  The 'value' attribute which holds the value of 'doubled'.
2.  An attribute called 'done' that tells us if the iterator is done, which of course it isn't b/c we have a forever loop there.

{value: 2, done: false}


So what happens if we call next() again?

result = gen.next();


If you said

{value: 4, done: false}


Then congrats!  This is just the surface of how we can use generators, but once you understand this, the rest is cake.




Further Reading

If you would like to dive deeper into generators, check out this guide.  It's pretty detailed and explains some of the many ways you can use generators.

I also recommend the Mozilla documentation:




Using It Today

Great, you love generators now and want to use them today.  Unfortunately, the spec isn't officially finalized yet and not all browsers support it today.  To see who supports it, check out this table here.

You could also use transpilers like Traceur to turn it into regular JavaScript.

Or you can do what I did, and that's to use node.  Let's say all your JavaScript code is in generators.js.  Then just install node and run:

node --harmony generators.js