Saturday, March 28, 2015

Understanding Javascript's this keyword

Funny thing happened the other day. I'm talking to a developer who is designing a project using a MEAN stack, and we're discussing some best practices in JS. We're on the subject of Angular controllers when he says something to the effect of, "I don't really get why we always have to alias this as var self in out controllers. Isn't this always just a reference to that current class object?".
Uh-oh. This developer is a good friend of mine, and a very smart guy and an even sharper software engineer, but this underscores just how few people understand just what the keyword this actually means in Javascript. To be fair, it can have like four different bindings, so let's jump into how this actually works in Javascript:

Quick disclaimer, if you want to really understand the keyword this in JS, look no further than Kyle Simpson's excellent book here.

Ok, onto this. But first, there was something even more subtle in my fellow developer's confusion. Internally, Javascript doesn't have any notion of a class, at all. And it's dynamic, not static, so that whole thought pattern of  "In Java or C++, this is a reference to the object itself bound at compile time" isn't going to serve you well.

Basically, in Javascript this is bound at runtime, and can point to one of four things, depending on how it is called:

1. if the new keyword is used, this points to the newly constructed object. As in:

function Person(name){
   this.name = name;
}

var bob = new Person("bob");
bob.name; //bob

2. If there is any sort of explicit or hard-binding going on as evidenced by the use of call, apply, or bind, then this will point to the specified object. For example (taken from Kyle Simpson's book):

function foo(){
 console.log(this.a); 
}

var obj = {
  a:2 
};

var bar = function(){
 foo.call(obj);
};

bar(); //2
setTimeout(bar,100); //2

bar.call(window); //2

With call(), bind(), etc the first parameter is basically the object to which this bound. So when bar calls foo() via call() and passes it obj, it is forcibly binding its internal call to foo with obj. This cannot be overwritten at a later time, as we see when we invoke bar.call(window) in the last line. In this case, we say that the binding of obj to the this reference in foo() is both explicit and strong, hence, hard-binding.

3. If there is an object that makes or "owns" the call, it is said to set the context for that object. In this case, this will look to that object for binding. For example:
var obj = {
a:2,
f:foo    //hoisting, if you are curios why this works
};

var obj2 = {
 a:4,
 f:foo
};

function foo(){
  console.log(this.a);
}

obj.foo(); //2
obj2.foo(); //4

4. The last case is when there is no other way to provide context to the object. In this case, the global scope is used. Unless we are using strict mode, in which case it is undefined.

function foo(){
  console.log(this.a);
}

var a = 5;

foo(); // 5. Unless 'use strict'; at which point undefined

That's about it, just follow this checklist when you need to resolve a this binding issue. It's worth the time to study how binding can be forced, as in example 2, which will probably be the subject of a future blog post. Until then, happy Javascripting!




Friday, March 27, 2015

Extending Native Types in JS

Saw this as an interview question the other day, and thought it was pretty interesting.
The question, in its original form is:

Define a repeatify function on the String object. The function accepts an integer that specifies how many times the string has to be repeated. The function returns the number of times specified. For example:

console.log('hello'.repeatify(3)); 

prints hellohellohello


The first step in attacking this problem is to realize what it is asking us to do. We need to define a property on the String object that we can use on native string types like 'hello'. More to the point, we need to define this on the prototype object of String so that 'hello' can find it via [[prototype]] delegation. This, we want something like:

String.prototype.repeatify = function(n){
 var ret = '';
 for(var i = 0; i < n; i++){
  ret += this;
 }
 return ret;
}

console.log('hello'.repeatify(3)); //hellohellohello

This is great, and does what we want. But there is something missing here - can you spot it?

What if we are trying to polyfill this repeatify function, but it already exists (or may exist) on String? Our above code would simply overwrite the existing functionality, which is probably bad. Thus, we add an extra step:

String.prototype.repeatify = String.prototype.repeatify || function(n){
 var ret = '';
 for(var i = 0; i < n; i++){
  ret += this;
 }
 return ret;
}

console.log('hello'.repeatify(3)); //hellohellohello

And that's it!

Thursday, March 26, 2015

Polyfilling Object.create in pre-ES5 Environments

As you might be aware, there are two primary ways of creating a [[prototype]] link between two objects in Javascript:

Using Object.create()

var obj1 = {
  a:2
};

var obj2 = Object.create(obj1);

console.log(obj2.a); //2

Using a function as a constructor

function Obj1(){
  this.a = 2;
}

var obj2 = new Obj1();

console.log(obj2.a); //2

In both cases, obj2.a will return a value of 2, although in the first case the property 'a' actually lives on obj1 and is found through [[prototype]] delegation, whereas in the second, "constructed" case, the property 'a' actually lives on obj2.

Generally speaking, it is somewhat cleaner to use Object.create() to link an object to another as opposed to making a function call as a construction (imagine if Obj1() had some sort of side effects in addition to just returning an object). However, in some older environments it is necessary to create a partial polyfill of Object.create(), which can be accomplished very easily with the following code snippet:

if( !Object.create ){
  Object.create = function(o){
    function F(){};
    F.prototype = o;
    return new F();
  };
}

In line one we check to see if the function already exists, if not, we begin defining it in line two by creating the 'create' property on Object and assigning it a function that takes an object as its argument. in line three, we create a throw-away function called F, and set its prototype object to the parameter 'o'. We then return a new instance of F(), which will be linked to 'o', since that is what we reassigned F's prototype object to reference.

Pretty simple polyfill hack. Some developers argue that this isn't a best practice since we haven't technically completely polyfilled Object.create. Object.create an also take an option object of arguments that will be assigned to the object that it creates, such as:

var obj2 = Object.create(obj1, { b:{},c:{} });

In this case, we have to define each of these properties by hand, such as setting b's enumerable, writable, configurable descriptors, etc. This is not supported in pre ES5 browsers, but this form is very rarely used, so most developers are okay with the partial polyfill, but if it bothers you, it's okay to simply create a different function that handles the partial polyfill, such as:

function object_create_link(o){
  function F(){};
  F.prototype = o;
  return new F();
}

var obj1 = {
  a:2
};

var obj2 = object_create_link(obj1);

obj2.a; //2

That's a wrap. I like this example because it provides a nice discussion of how Object.create() and functions as constructors differ in creating an object.

Thanks for reading!
-nate