Things I Learned from You Don’t Know JS: this & Object Prototypes, Appendix A

Here are some things I learned from Appendix A: ES6 class of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

class

Let’s revisit the Widget / Button example from Chapter 6:

class Widget {
	constructor(width, height) {
		this.width = width || 50;
		this.height = height || 50;
		this.$elem = null;
	}
	render($where) {
		if (this.$elem) {
			this.$elem.css( {
				width: this.width + "px",
				height: this.height + "px"
			} ).appendTo( $where );
		}
	}
}

class Button extends Widget {
	constructor(width, height, label) {
		super( width, height );
		this.label = label || "Default";
		this.$elem = $( "<button>" ).text( this.label );
	}
	render($where) {
		super.render( $where );
		this.$elem.click( this.onClick.bind( this ) );
	}
	onClick(evt) {
		console.log( "Button '" + this.label + "' clicked!" );
	}
}

Beyond this syntax looking nicer, what problems does ES2015 solve?

  1. There’s no more references to .prototype cluttering the code.
  2. Button is declared directly to “inherit from” (aka extends) Widget, instead of having to use Object.create(..) or Object.setPrototypeOf(..).
  3. super(..) gives us a relative polymorphism capability, so that any method at one level of the chain can refer relatively one level up the chain to a method of the same name.
  4. class literal syntax can’t specify properties (only methods). In most cases, a property existing elsewhere but the end-chain “instances” is very likely a mistake, so the class syntax in a way is protecting you from mistakes.
  5. extends lets you extend even built-in object (sub)types, like Array or RegExp. This used to be very complex before ES2015.

class Gotchas

The class syntax may convince you a new “class” mechanism exists in JS as of ES2015. Not so. class is mostly just syntactic sugar on top of the existing [[Prototype]] mechanism.

That means class is not actually copying definitions statically at declaration time the way it does in traditional class-oriented languages.

For example:

class C {
	constructor() {
		this.num = Math.random();
	}
	rand() {
		console.log( "Random: " + this.num );
	}
}

var c1 = new C();
c1.rand(); // "Random: 0.304132..."

C.prototype.rand = function() {
	console.log( "Random: " + Math.round( this.num * 1000 ));
};

var c2 = new C();
c2.rand(); // "Random: 587"

c1.rand(); // "Random: 304" -- oops!!!

The question to ask yourself is: why are you choosing class syntax for something fundamentally different from classes?

class syntax does not provide a way to declare class member properties (only methods). If you need to do that to track shared state among instances, you end up going back to the ugly .prototype syntax:

class C {
	constructor() {
		// make sure to modify the shared state, not set a
		// shadowed property on the instances!
		C.prototype.count++;

		// here, `this.count` works as expected
		// via delegation
		console.log( "Hello: " + this.count );
	}
}

// add a property for shared state directly to
// prototype object
C.prototype.count = 0;

var c1 = new C();
// Hello: 1

var c2 = new C();
// Hello: 2

c1.count === 2; // true
c1.count === c2.count; // true

The biggest problem here is that it betrays the class syntax by exposing .prototype as an implementation detail.

Using this.count++ would implicitly create a shadowed .count property on both c1 and c2 objects, rather than updating the shared state. class offers no consolation from that issue, except presumably to imply that you shouldn’t be doing that at all.

Accidental shadowing is still a hazard:

class C {
	constructor(id) {
		// oops, gotcha, we're shadowing `id()` method
		// with a property value on the instance
		this.id = id;
	}
	id() {
		console.log( "Id: " + this.id );
	}
}

var c1 = new C( "c1" );
c1.id(); // TypeError -- `c1.id` is now the string "c1"

You might assume that super would always be bound to one level higher than whatever the current method’s position in the [[Prototype]] chain is. However, for performance reasons, super is not bound dynamically. It’s bound sort of “statically”, at declaration time.

If you assign functions around to different objects (which came from class definitions), the super mechanism under the covers is having to be re-bound each time. Depending on your syntactic approaches, super may not be properly bound (at least, not where you suspect).

class P {
	foo() { console.log( "P.foo" ); }
}

class C extends P {
	foo() {
		super.foo();
	}
}

var c1 = new C();
c1.foo(); // "P.foo"

var D = {
	foo: function() { console.log( "D.foo" ); }
};

var E = {
	foo: C.prototype.foo
};

// Link E to D for delegation
Object.setPrototypeOf( E, D );

E.foo(); // "P.foo"

For performance pragmatism reasons, super is derived at call-time from [[HomeObject]].[[Prototype]], where [[HomeObject]] is statically bound at creation time.

In this particular case, super.foo() is still resolving to P.foo(), since the method’s [[HomeObject]] is still C and C.Prototype is P.

Static > Dynamic?

The biggest problem of class is that it opts you into a syntax which seems to imply that once you declare a class, it’s a static definition of a future instantiated thing. You lose sight of the fact that C is an object, a concrete thing, which you can directly interact with.

In traditional class-oriented languages, you never adjust the definition of a class later, so the class design pattern doesn’t suggest such capabilities. However, the definition of any JS object is a fluid and mutable thing (unless you make it immutable).

ES2015 class is actually making things worse for JS and for clear and concise understanding.

Note: If you use the .bind(..) utility to make a hard-bound function, the function created is not subclassable with ES2015 extends like normal functions are.

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 6

Here are some things I learned from Chapter 6: Behavior Delegation of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

Towards Delegation-Oriented Design

We need to try to change our thinking from the class/inheritance design pattern to the behavior delegation design pattern.

Class Theory

Let’s say we have several similar tasks (“XYZ”, “ABC”, etc) that we need to model in our software.

With classes, we would define a general parent (base) class like Task, defining shared behavior for all the “alike” tasks. Then, you define child classes XYZ and ABC, both of which inherit from Task, and each of which adds specialized behavior.

To get the most out of inheritance, you would override some general Task method in your XYZ task, perhaps even using super to call to the base version of that method while adding more behavior to it.

After that, you can instantiate one or more copies of the XYZ child class, and use those instances to perform task “XYZ”. These instances have copies both of the general Task defined behavior and the specific XYZ behavior. After construction, you will only interact with these instances (and not the classes), as the instances have copies of all the behavior you need.

Delegation Theory

With behavior delegation, you will first define an object (not a class nor a function) called Task, and it will have methods on it that various tasks can use (read: delegate to). For each task (“XYZ”, “ABC”), you define an object to hold that task-specific data/behavior. You link your task-specific objects to the Task utility object, allowing them to delegate to it.

For example:

var Task = {
	setID: function(ID) { this.id = ID; },
	outputID: function() { console.log( this.id ); }
};

// make `XYZ` delegate to `Task`
var XYZ = Object.create( Task );

XYZ.prepareTask = function(ID, label) {
	this.setID( ID );
	this.label = label;
};

XYZ.outputTaskDetails = function() {
	this.outputID();
	console.log( this.label );
};

In the code above, Task and XYZ are not classes (or functions), they’re just objects. Let’s call this type of coding “OLOO” (Objects Linking to Other Objects) and the class-oriented approach “OO” (Object Oriented).

Some key points to notice:

  • Both id and label are data properties directly on XYZ, not on Task. In general, with [[Prototype]] delegation, you want state to be on the delegator (XYZ), not on the delegate (Task).
  • We avoid naming things the same at different levels of the [[Prototype]] chain because we want to avoid explicit pseudo-polymorphism. This design pattern also calls for more descriptive method names that can create easier to understand/maintain code.
  • The general utility methods on Task are available to us while interacting with XYZ,
    because XYZ can delegate to Task. Furthermore, implicit call-site this binding rules make sure that this in delegated Task methods points to XYZ.

Rather than organizing the objects in your mind vertically, with parents flowing down to children, think of objects side-by-side, as peers.

Note: Delegation is more properly used as an internal implementation than exposed directly in the API design.

Mutual Delegation (Disallowed)

You cannot create a cycle where two or more objects are mutually delegated to each other. If you make B linked to A, and then try to link A to B, you will get an error.

In theory, if all references you make were strictly present on one of the objects, mutual delegation would work. However, engine implementors have observed that it’s more performant to reject the possible infinite loops once at set-time than during run-time.

Debugged

In general, JS specification doesn’t control how browser developer tools should represent specific values/structures to a developer. As such, browsers/tools don’t always agree.

For example:

function Foo() {}

var a1 = new Foo();

a1;
// `Foo {}` on Chrome,
// `Object {  }` on Firefox

Chrome is saying “{} is an empty object that was constructed by a function named `Foo`”. Firefox is saying “{} is an empty object of general construction from Object”. The difference is that Chrome is actively tracking, as an internal property, the name of the actual function that did the construction, whereas other browsers don’t track that information.

Even if you change Foo.prototype.constructor to another function, Chrome will still output Foo. However, using OLOO-style code (Object.create(..) instead of new) and changing the Foo constructor would make Chrome refer to the new function! This is actually a bug that’s not a big deal in OLOO-style code because the constructor (which function was called with new?) is irrelevant.

Mental Models Compared

Let’s write an example program in both OO and OLOO style.

OO:

function Foo(who) {
	this.me = who;
}

Foo.prototype.identify = function() {
	return "I am " + this.me;
};

function Bar(who) {
	Foo.call( this, who );
}

Bar.prototype = Object.create( Foo.prototype );

Bar.prototype.speak = function() {
	alert( "Hello, " + this.identify() + "." );
};

var b1 = new Bar( "b1" );
var b2 = new Bar( "b2" );

b1.speak(); // "Hello, I am b1."
b2.speak(); // "Hello, I am b2."

OLOO:

var Foo = {
	init: function(who) {
		this.me = who;
	},
	identify: function() {
		return "I am " + this.me;
	}
};

var Bar = Object.create( Foo );

Bar.speak = function() {
	alert( "Hello, " + this.identify() + "." );
};

var b1 = Object.create( Bar );
b1.init( "b1" );
var b2 = Object.create( Bar );
b2.init( "b2" );

b1.speak(); // "Hello, I am b1."
b2.speak(); // "Hello, I am b2."

We take exactly the same advantage of [[Prototype]] delegation from b1 to Bar to Foo in the OLOO example as we do between b1, Bar.prototype and Foo.prototype in the OO example. In other words, we have the same three objects linked together.

But, importantly, we’ve greatly simplified all the other stuff going on. We don’t make things look like (but not behave) like classes, with constructors, prototypes and new calls.

If you can get the same functionality with OLOO style code as with “class” style code, but OLOO is simpler and has less things to think about, isn’t OLOO better?

Note: There’s an amazing amount of internal consistency in JS’s mechanisms. For instance, the ability of a JS function to access call(..), apply(..) and bind(..) is because functions themselves are objects, and function-objects also have a [[Prototype]] linkage, to the Function.prototype object.

Classes vs. Objects

Let’s look at more concrete code scenarios. We’ll first examine creating UI widgets (buttons, drop-downs, etc.).

Widget “Classes”

The OO design pattern would imply creating a parent class (perhaps called Widget) with all the common base widget behavior, and then child derived classes for specific widget types (like Button).

Let’s examine how we’d implement the “class” design in pure JS without any “class” helper library or syntax:

// Parent class
function Widget(width, height) {
	this.width = width || 50;
	this.height = height || 50;
	this.$elem = null;
}

Widget.prototype.render = function($where) {
	if (this.$elem) {
		this.$elem.css( {
			width: this.width + "px",
			height: this.height + "px"
		} ).appendTo( $where );
	}
};

// Child class
function Button(width, height, label) {
	// "super" constructor call
	Widget.call( this, width, height );
	this.label = label || "Default";

	this.$elem = $( "<button>" ).text( this.label );
}

// make `Button` "inherit" from `Widget`
Button.prototype = Object.create( Widget.prototype );

// override base "inherited" `render(..)`
Button.prototype.render = function($where) {
	// "super" call
	Widget.prototype.render.call( this, $where );
	this.$elem.click( this.onClick.bind( this ) );
};

Button.prototype.onClick = function(evt) {
	console.log( "Button '" + this.label + "' clicked!" );
};

$( function documentReady() {
	var $body = $( document.body );
	var btn1 = new Button( 125, 30, "Hello" );
	var btn2 = new Button( 150, 40, "World" );

	btn1.render( $body );
	btn2.render( $body );
} );

OO design patterns tell us to declare a base render(..) in the parent class, then override it in our child class, but not to replace it. This way, it can augment the base functionality with button-specific behavior.

Notice the ugliness of explicit pseudo-polymorphism with Widget.call and Widget.prototype.render.call references for faking “super” calls from the child “class” methods.

ES6 class sugar

We’d implement the same code using ES2015 class like this:

class Widget {
	constructor(width, height) {
		this.width = width || 50;
		this.height = height || 50;
		this.$elem = null;
	}
	render($where) {
		if (this.$elem) {
			this.$elem.css( {
				width: this.width + "px",
				height: this.height + "px"
			} ).appendTo( $where );
		}
	}
}

class Button extends Widget {
	constructor(width, height, label) {
		super(width, height);
		this.label = label || "Default";
		this.$elem = $( "<button>" ).text( this.label );
	}
	render($where) {
		super.render( $where );
		this.$elem.click( this.onClick.bind( this ) );
	}
	onClick(evt) {
		console.log( "Button '" + this.label + "' clicked!" );
	}
}

$( function documentReady() {
	var $body = $( document.body );
	var btn1 = new Button( 125, 30, "Hello" );
	var btn2 = new Button( 150, 40, "World" );

	btn1.render( $body );
	btn2.render( $body );
} );

This syntax is more elegant than the previous one (especially the presence of super(..)) but still these are not real classes, as they operate on top of the [[Prototype]] mechanism.

Using any type of class-like syntax with JavaScript is a choice that is likely to cause extra headache.

Delegating Widget Objects

Finally, here’s the OLOO style implementation:

var Widget = {
	init: function(width, height) {
		this.width = width || 50;
		this.height = height || 50;
		this.$elem = null;
	},
	insert: function($where) {
		if (this.$elem) {
			this.$elem.css( {
				width: this.width + "px",
				height: this.height + "px"
			} ).appendTo( $where );
		}
	}
};

var Button = Object.create( Widget );

Button.setup = function(width, height, label) {
	// delegated call
	this.init( width, height );
	this.label = label || "Default";

	this.$elem = $( "<button>" ).text( this.label );
};
Button.build = function($where) {
	// delegated call
	this.insert( $where );
	this.$elem.click( this.onClick.bind( this ) );
};
Button.onClick = function(evt) {
	console.log( "Button '" + this.label + "' clicked!" );
};

$( function documentReady() {
	var $body = $( document.body );

	var btn1 = Object.create( Button );
	btn1.setup( 125, 30, "Hello" );

	var btn2 = Object.create( Button );
	btn2.setup( 150, 40, "World" );

	btn1.build( $body );
	btn2.build( $body );
} );

Now we don’t think of Widget as a parent and Button as a child. They’re both just objects.

We didn’t share the same method name render(..) in both objects, but instead chose different names insert(..) and build(..) that were more descriptive of what task each does specifically.

This also allows simple, relative and delegated calls to this.init(..) and this.insert(..) instead of explicit pseudo-polymorphic Widget.call and Widget.prototype.render.call.

Syntactically, we also don’t have any constructors, .prototype or new present, as they are unnecessary.

What was previously one call (var btn1 = new Button(..)) is now two calls (var btn1 = Object.create(Button) and btn1.setup(..). This is actually a good thing because you can do the construction and initialization of objects separately. This supports the principle of separation of concerns.

Simpler Design

Behavior delegation as a pattern can actually lead to simpler code architecture. Let’s examine an example of handling authentication on a web page.

Here’s the OO version:

// Parent class
function Controller() {
	this.errors = [];
}
Controller.prototype.showDialog = function(title, msg) {
	// display title & message to user in dialog
};
Controller.prototype.success = function(msg) {
	this.showDialog( "Success", msg );
};
Controller.prototype.failure = function(err) {
	this.errors.push( err );
	this.showDialog( "Error", err );
};
// Child class
function LoginController() {
	Controller.call( this );
}
// Link child class to parent
LoginController.prototype = Object.create( Controller.prototype );

LoginController.prototype.getUser = function() {
	return document.getElementById( "login_username" ).value;
};
LoginController.prototype.getPassword = function() {
	return document.getElementById( "login_password" ).value;
};
LoginController.prototype.validateEntry = function(user, pw) {
	user = user || this.getUser();
	pw = pw || this.getPassword();

	if (!(user && pw)) {
		return this.failure( "Please enter a username & password!" );
	}
	else if (pw.length < 5) {
		return this.failure( "Password must be 5+ characters!" );
	}

	// got here? validated!
	return true;
};
// Override to extend base `failure()`
LoginController.prototype.failure = function(err) {
	// "super" call
	Controller.prototype.failure.call( this, "Login invalid: " + err );
};
// Child class
function AuthController(login) {
	Controller.call( this );
	// in addition to inheritance, we also need composition
	this.login = login;
}
// Link child class to parent
AuthController.prototype = Object.create( Controller.prototype );

AuthController.prototype.server = function(url, data) {
	return $.ajax( {
		url: url,
		data: data
	} );
};
AuthController.prototype.checkAuth = function() {
	var user = this.login.getUser();
	var pw = this.login.getPassword();

	if (this.login.validateEntry( user, pw )) {
		this.server( "/check-auth", {
			user: user,
			pw: pw
		} )
		.then( this.success.bind( this ) )
		.fail( this.failure.bind( this ) );
	}
};
// Override to extend base `success()`
AuthController.prototype.success = function() {
	// "super" call
	Controller.prototype.success.call( this, "Authenticated!" );
};
// Override to extend base `failure()`
AuthController.prototype.failure = function(err) {
	// "super" call
	Controller.prototype.failure.call( this, "Auth Failed: " + err );
};
var auth = new AuthController(
	// in addition to inheritance, we also need composition
	new LoginController()
);
auth.checkAuth();

We have base behaviors that all controllers share, which are success(..), failure(..) and showDialog(..). Our child classes LoginController and AuthController override failure(..) and success(..) to augment the default base class behavior.

There's also some composition: AuthController needs to know about LoginController, so we instantiate it and keep a class member property this.login to reference it.

Note: We could've made AuthController inherit from LoginController, or vice versa. However, this would've made little sense because neither of them are specializing base behavior of the other. This is the reason we chose to use composition instead.

De-class-ified

Here's the OLOO version of the example:

var LoginController = {
	errors: [],
	getUser: function() {
		return document.getElementById( "login_username" ).value;
	},
	getPassword: function() {
		return document.getElementById( "login_password" ).value;
	},
	validateEntry: function(user, pw) {
		user = user || this.getUser();
		pw = pw || this.getPassword();

		if (!(user && pw)) {
			return this.failure( "Please enter a username & password!" );
		}
		else if (pw.length < 5) {
			return this.failure( "Password must be 5+ characters!" );
		}

		// got here? validated!
		return true;
	},
	showDialog: function(title, msg) {
		// display success message to user in dialog
	},
	failure: function(err) {
		this.errors.push( err );
		this.showDialog( "Error", "Login invalid: " + err );
	}
};
// Link `AuthController` to delegate to `LoginController`
var AuthController = Object.create( LoginController );

AuthController.errors = [];
AuthController.checkAuth = function() {
	var user = this.getUser();
	var pw = this.getPassword();

	if (this.validateEntry( user, pw )) {
		this.server( "/check-auth", {
			user: user,
			pw: pw
		} )
		.then( this.accepted.bind( this ) )
		.fail( this.rejected.bind( this ) );
	}
};
AuthController.server = function(url, data) {
	return $.ajax( {
		url: url,
		data: data
	} );
};
AuthController.accepted = function() {
	this.showDialog( "Success", "Authenticated!" );
};
AuthController.rejected = function(err) {
	this.failure( "Auth Failed: " + err );
};

Since AuthController is just an object (so is LoginController), we don't need to instantiate it to perform our task. All we need is:

AuthController.checkAuth();

AuthController and LoginController are just objects, horizontal peers of each other. We chose to have AuthController delegate to LoginController, and it would've been just as valid to choose the other way around.

We only have two entities, not three as before. We didn't need a base Controller class to "share" behavior between the two. We also don't need to instantiate our classes, because there are no classes, just the objects. Furthermore, there's no need for composition as delegation gives the two objects the ability to cooperate differentially as needed.

Lastly, we avoided the polymorphic pitfalls of class-oriented design by not having the names success(..) and failure(..) be the same on both objects.

Bottom line: we end up with the same capability, but a significantly simpler design.

Nicer Syntax

One of the things that makes ES2015's class so attractive is the short-hand syntax for declaring class methods:

class Foo {
	methodName() { /* .. */ }
}

As of ES2015, we can use concise method declarations in any object literal, like this:

var LoginController = {
	errors: [],
	getUser() { // no `function`!
		// ...
	}, // <-- note the comma as opposed to the `class` syntax
	getPassword() {
		// ...
	}
	// ...
};

In addition, the clunkier syntax (like for the AuthController definition) where you're assigning properties individually and not using an object literal can be re-written like this:

// use nicer object literal syntax w/ concise methods!
var AuthController = {
	errors: [],
	checkAuth() {
		// ...
	},
	server(url, data) {
		// ...
	}
	// ...
};

// NOW, link `AuthController` to delegate to `LoginController`
Object.setPrototypeOf( AuthController, LoginController );

You don't have to opt for class complexity to get nice clean object syntax.

Unlexical

There is one drawback to concise methods. Consider:

var Foo = {
	bar() { /*..*/ },
	baz: function baz() { /* .. */ }
};

This is equal to:

var Foo = {
	bar: function() { /*..*/ },
	baz: function baz() { /*..*/ }
};

The bar() short-hand became an anonymous function expression. Compare that to the manually specified named function expression function baz() which has a lexical name identifier baz.

Lack of a name identifier on an anonymous function:

  1. makes debugging stack traces harder
  2. makes self-referencing (recursion, event (un)binding, etc) harder
  3. makes code harder to understand

Items 1 and 3 don't apply to concise methods, but item 2 is a problem. Consider:

var Foo = {
	bar: function(x) {
		if (x < 10) {
			return Foo.bar( x * 2 );
		}
		return x;
	},
	baz: function baz(x) {
		if (x < 10) {
			return baz( x * 2 );
		}
		return x;
	}
};

A manual Foo.bar( x * 2 ) type of reference wouldn't be possible in many cases, such as when the function is being shared in delegation across different objects, using this binding, etc.

If you run into such issues, forgo the concise method syntax just for that declaration in favor of the manual named function expression declaration form.

Introspection

In class oriented programming, type introspection means inspecting an instance to find out what kind of object it is, or how it was created.

Consider:

function Foo() {
	// ...
}
Foo.prototype.something = function() {
	// ...
};

var a1 = new Foo();

// later

if (a1 instanceof Foo) {
	a1.something();
}

Because Foo.prototype (not Foo!) is in the [[Prototype]] chain of a1, the instanceof operator confusingly pretends to tell us that a1 is an instance of the Foo "class".

Of course, there is no Foo class, only a normal function Foo, which happens to have a reference to an arbitrary object Foo.prototype that a1 happens to be delegation-linked to. instanceof is actually telling us whether a1 and (the arbitrary object referenced by) Foo.prototype are related.

This means that you have to have a function that holds a reference to that object; you can't just directly ask if the two objects are related.

For type introspection, here are the various checks you might need to perform:

function Foo() { /*..*/ }
Foo.prototype.something = function() { /*..*/ };

function Bar() { /*..*/ }
Bar.prototype = Object.create( Foo.prototype );

var b1 = new Bar( "b1" );

// relating `Foo` and `Bar` to each other
Bar.prototype instanceof Foo; // true
Object.getPrototypeOf( Bar.prototype ) === Foo.prototype; // true
Foo.prototype.isPrototypeOf( Bar.prototype ); // true

// relating `b1` to both `Foo` and `Bar`
b1 instanceof Foo; // true
b1 instanceof Bar; // true
Object.getPrototypeOf( b1 ) === Bar.prototype; // true
Foo.prototype.isPrototypeOf( b1 ); // true
Bar.prototype.isPrototypeOf( b1 ); // true

Another common pattern for type instrospection is called "duck typing". This term comes from the adage, "if it looks like a duck, and it quacks like a duck, it must be a duck".

Example:

if (a1.something) {
	a1.something();
}

Rather than inspecting for a relationship between a1 and an object that holds the delegatable something() function, we test whether a1 has the capability to call .something() (regardless of if the method is directly on a1 or delegated to some other object).

One problem comes with ES2015 Promises. Testing whether any object reference is a Promise relies on whether it has a then() function on it. If you have any non-Promise object that happens to have a then() method on it, you should keep away from the ES2015 Promise mechanism to avoid broken assumptions.

Let's take a look at type introspection with OLOO-style code:

var Foo = { /*..*/ };
var Bar = Object.create( Foo );
var b1 = Object.create( Bar );

// relating `Foo` and `Bar` to each other
Foo.isPrototypeOf( Bar ); // true
Object.getPrototypeOf( Bar ) === Foo; // true

// relating `b1` to both `Foo` and `Bar`
Foo.isPrototypeOf( b1 ); // true
Bar.isPrototypeOf( b1 ); // true
Object.getPrototypeOf( b1 ) === Bar; // true

We're not using instanceof anymore, because it's pretending to have something to do with classes. We just ask the question, "are you a prototype of me?" These checks are less complicated and confusing than the previous set of introspection checks, so OLOO wins once again.

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 5

Here are some things I learned from Chapter 5: Prototypes of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

[[Prototype]]

Objects in JavaScript have an internal property [[Prototype]], which is a reference to another object. Almost all objects are given a non-null value for this property at the time of their creation.

If the [[Get]] operation doesn’t find a value inside an object, it will follow the [[Prototype]] link of that object, and the [[Prototype]] link of that object etc. until it either finds a matching property name or the chain ends. If no matching property is ever found, the operation returns undefined.

The for..in loop works similarly over all enumerable:true properties on the object and its [[Prototype]] chain.

Object.prototype

The top-end of every normal [[Prototype]] chain is the built-in Object.prototype. This includes a variety of common utilities, because all built-in (not host-specific) objects “descend from” the Object.prototype object.

Setting & Shadowing Properties

Consider myObject.foo = 'bar'.

If foo is found on myObject, the value is changed and that’s it.

If foo doesn’t exist on myObject, the [[Prototype]] chain is traversed. If foo isn’t found anywhere in the chain, a new property is created in myObject.

However, if foo is found higher up in the chain, one of three things happen:

  1. If foo is a normal data accessor and writable:true, then a new property foo is added to myObject.
  2. If foo is writable:false, the setting of the property will fail silently (or if in strict mode, cause a TypeError).
  3. If foo is a setter, then the setter will always be called.

Case #1 is called shadowing: the foo property on myObject shadows any foo property higher up in the chain.

If you want to shadow foo in cases #2 and #3, you cannot use = assignment, but must instead use Object.defineProperty(..).

The reason for case #2 is primarily to imitate class-inherited properties in other languages.

Shadowing with methods leads to ugly explicit pseudo-polymorphism. Try to avoid shadowing if possible. (See a better alternative in Chapter 6.)

Shadowing can also occur implicitly:

var anotherObject = {
	a: 2
};

var myObject = Object.create( anotherObject );

myObject.hasOwnProperty( 'a' ); // false

myObject.a++; // <-- implicit shadowing

myObject.hasOwnProperty( 'a' ); // true

The myObject.a++ operator corresponds to myObject.a = myObject.a + 1 and implicitly adds a new property a to myObject.

"Class"

JavaScript is one of the only languages where objects are created directly, without a class. The object defines its own behavior directly.

"Class" Functions

All functions by default get a public, non-enumerable property called prototype, which points at an object.

function Foo() {
  // ..
}

Foo.prototype; // { }

Each object created from calling new Foo() will end up [[Prototype]]-linked to this "Foo dot prototype" object.

var a = new Foo();

Object.getPrototypeOf( a ) === Foo.prototype; // true

a is not an instantiation of a Foo "class". They both are simply objects that are internally linked to each other. No copying of properties takes place.

What's in a name?

JavaScript's linking between objects is often called "prototypal inheritance" or "differential inheritance". However, these names are misleading because inheritance implies a copy operation, and JavaScript doesn't copy object properties. Instead, JS creates a link between two objects, where one object can delegate property access to another object. Delegation is a much more accurate term for JavaScript's object-linking mechanism.

"Constructors"

function Foo() {
  // ...
}

Foo.prototype.constructor === Foo; // true

var a = new Foo();
a.constructor === Foo; // true

The Foo.prototype object by default (at declaration time) gets a public, non-enumerable property called .constructor, and this property is a reference back to the function that the object is associated with. Moreover, object a seems to also have a property on it called .constructor which similarly appears to point to the function that created it.

However, a has no .constructor property on it, and .constructor doesn't mean "was constructed by"! This confusion comes from the class-oriented world but JavaScript works differently.

Constructor Or Call?

In the example above, it's tempting to think that Foo is a "constructor". In reality, functions themselves are not constructors. However, when you put the new keyword in front of a normal function call, that makes that function call a "constructor call". The new keyword calls any normal function in a way that constructs an object, in addition to whatever else it was going to do.

In other words, functions aren't constructors, but function calls are "constructor calls" if and only if new is used.

Mechanics

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

Foo.prototype.myName = function() {
  return this.name;
}

var a = new Foo( 'a' );

a.myName(); // 'a'

Although the syntax looks a lot like class-oriented languages, no copying of properties takes place.

a ends up with an internal [[Prototype]] linkage to Foo.prototype. When myName is not found on a, it's instead found on Foo.prototype.

"Constructor" Redux

Even though a.constructor by default points to Foo, it's just an arbitrary property. There's nothing to stop you from modifying it.

For this reason, avoid using .constructor in your code.

"(Prototypal) Inheritance"

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

Foo.prototype.myName = function() {
	return this.name;
}

function Bar(name, label) {
	Foo.call( this, name );
	this.label = label;
}

Bar.prototype = Object.create( Foo.prototype );
// ES2015 alternative (modifies existing `Bar.prototype`):
// Object.setPrototypeOf( Bar.prototype, Foo.prototype );

Bar.prototype.myLabel = function() {
	return this.label;
};

var a = new Bar( 'a', 'obj a' );

a.myName(); // 'a'
a.myLabel(); // 'obj a'

Using Bar.prototype = Foo.prototype won't work because Bar.prototype gets linked to the existing Foo.prototype. This means that all the changes made to Bar.prototype will actually show up in Foo.prototype, which is not wanted. Or if it is, why have Bar in the first place?

Using Bar.prototype = new Foo() will actually create a new object that is linked to Foo.prototype but it also calls Foo which may not be wanted at this point.

Inspecting "Class" Relationships

function Foo() {
  // ...
}

var a = new Foo();

a instanceof Foo; // true

The instanceof operator takes a plain object as its left-hand operand and a function as its right-hand operand. The question instanceof answers is: in the entire [[Prototype]] chain of a, does the object arbitrarily pointed to by Foo.prototype ever appear?

If you want to check if two objects are related through a [[Prototype]] chain, we can use b.isPrototypeOf( c ). This checks if b appears anywhere in c's [[Prototype]] chain.

We can directly retrieve the [[Prototype]] of an object. As of ES5, the standard way to do this is Object.getPrototypeOf( a ). Many browsers also support a non-standard (pre-ES2015) alternate way a.__proto__.

Just like constructor, .__proto__ doesn't actually exist on the object you're inspecting, but on the built-in Object.prototype. Moreover, .__proto__ looks like a property, but it's more appropriate to think of it as a getter/setter.

.__proto__ is a settable property, just like using ES2015's Object.setPrototypeOf(..). However, generally you shouldn't change the [[Prototype]] of an existing object.

There are two exceptions to this rule: using the class keyword to approximate "subclassing" of built-ins like Array (see Appendix A), and setting the [[Prototype]] of a default function's .prototype object to reference some other object (besides Object.prototype). That would avoid replacing that default object entirely with a new linked object. [I don't really quite understand what this means, so any help would be appreciated!]

Note: the unofficial way to pronounce __proto__ is "dunder proto".

Object links

The [[Prototype]] linkage is primarily exercised when a property/method reference is made against the first object, and no such property/method exists. In that case, the [[Prototype]] linkage tells the engine to look for the property/method on the linked-to object. If that object cannot fulfill the look-up, its [[Prototype]] is followed, and so on. This series of links forms what is called the "prototype chain".

Create()ing Links

Instead of going to so much effort trying to emulate classes, the simple and effective way to create [[Prototype]] links is Object.create(..).

var foo = {
	something: function() {
		console.log( 'Tell me something good...' );
	}
};

var bar = Object.create( foo );

bar.something(); // Tell me something good...

This gives us all the power (delegation) of the [[Prototype]] mechanism, but without any of the unnecessary complication of new functions acting as classes and constructor calls, confusing .prototype and .constructor references etc.

Note: Object.create(null) creates an object that has an empty [[Prototype]] linkage, and thus the object can't delegate anywhere. These special objects are often called "dictionaries" as they are typically used purely for storing data in properties, without possible surprise effects from any delegated properties/functions on the [[Prototype]] chain.

Object.create() Polyfilled

Object.create(..) was added in ES5. To support pre-ES5 environments (like older IE's), here's a simple partial polyfill:

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

There's an additional set of functionality that the standard ES5 built-in provides, which is not polyfillable for pre-ES5:

var anotherObject = {
	a: 2
};

var myObject = Object.create( anotherObject, {
	b: {
		enumerable: false,
		writable: true,
		configurable: false,
		value: 3
	},
	c: {
		enumerable: true,
		writable: false,
		configurable: false,
		value: 4
	}
} );

myObject.hasOwnProperty( "a" ); // false
myObject.hasOwnProperty( "b" ); // true
myObject.hasOwnProperty( "c" ); // true

myObject.a; // 2
myObject.b; // 3
myObject.c; // 4

The second argument specifies property names to add to the newly created object, via declaring each new property's property descriptor. Because polyfilling property descriptors into pre-ES5 is not possible, this additional functionality cannot be polyfilled.

Since the vast majority of usage of Object.create(..) uses the polyfill-safe subset of functionality, most developers are fine with using the partial polyfill in pre-ES5 environments. However, some developers take a stricter view that no function should be polyfilled unless it can be fully polyfilled and you should use a custom utility, staying away from using the name Object.create entirely.

If you only use the common functionality, the polyfill shoud be ok.

Links as fallbacks?

var anotherObject = {
	cool: function() {
		console.log( 'cool!' );
	}
};

var myObject = Object.create( anotherObject );

myObject.cool(); // 'cool!'

The above code will work by virtue of [[Prototype]], but if you wrote it that way so that anotherObject was acting as a fallback just in case myObject couldn't handle some property/method that some developer may try to call, odds are that your software is going to be a bit more "magical" and harder to understand and maintain.

Note: In ES6, an advanced functionality called Proxy is introduced which can provide something of a "method not found" type of behavior (see a later book in the series).

You can design an API with less "magic" to it as follows:

myObject.doCool = function() {
	this.cool(); // internal delegation!
};

myObject.doCool(); // 'cool!'

We call myObject.doCool(), which is a method that actually exists on myObject. This makes our API design more explicit and less "magical".

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 4

Here are some things I learned from Chapter 4: Mixing (Up) “Class” Objects of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

Class Theory

It might not make sense to define certain behavior over and over again. That’s why organizing similar parts of software into parent and child classes makes better code.

Polymorphism describes the idea that a general behavior from a parent class can be overridden in a child class. Relative polymorphism lets us reference the base behavior from the overridden behavior.

Class theory suggests that the parent and child share the same method name for a certain behavior so that the child overrides the parent. However, doing so in JavaScript wouldn’t be a good idea.

“Class” Design Pattern

Procedural/functional programming only consists of functions calling other functions, without any higher abstractions.

In some languages (like Java), everything is a class. Other languages (like C/C++ and PHP) give you both procedural and class-oriented syntaxes, and it’s left to the developer to find a balance between these two.

JavaScript “Classes”

JS has some class-like syntactic elements like new and instanceof, and with ES2015, the class keyword. However, JavaScript doesn’t have classes.

You can imitate class-like functionality in JavaScript, and many developers do, but as JavaScript isn’t a class-oriented language, that doesn’t come without its pain points.

Class Mechanics

In many class-oriented languages, the “standard stack” provides a “stack” data structure (push, pop etc.) as a Stack class. This class would have private data and public methods to interact with that data.

But in such languages, you don’t really operate directly on Stack. The Stack class is merely an abstraction of what any “stack” should do, but it’s not itself a “stack”. You must instantiate the Stack before you can have a concrete data structure thing to operate against.

Building

Classes and objects can be compared to a building: The architect designs the building and creates the blue-print (class), and the builder creates the actual building (object) based on that blue-print.

A class is instantiated into object form by a copy operation.

Constructor

Instances of classes are constructed by a special method of the class, usually the same name as the class, called a constructor. This method’s job is to initialize any information (state) the instance will need.

The cosntructor of a class belongs to the class. Also, constructors pretty much always need to be called with new to let the language engine know you want to construct a new class instance.

Class Inheritance

Polymorphism

A child class can override a method of its parent. This technique is called polymorphism or virtual polymorphism. Relative polymorphism means that the child class doesn’t absolutely define which class it wants to access, but instead says: “look one level up”.

Note: In many languages, the keyword super is used to reference the parent/ancestor of the current class. super also gives the child class the ability to reference the constructor of its parent. That’s possible because the constructor belongs to the class. In JavaScript, however, it’s the reverse: it’s more appropriate to think of the “class” belonging to the constructor! Since in JS the relationship between child and parent exists only between the two .prototype objects, the constructors themselves are not directly related. This means that there’s no simple way to relatively reference one from the other. (ES6 “solves” this with class and super, see Appendix A.)

An interesting implication of polymorphism happens when a method from the child calls an inherited method of its parent that calls another method that has been overridden by the child. Which method is used, the one from the parent or the one from the child? The answer is the latter. The definition for the method in question polymorphs (changes) depending on which class (level of inheritance) you are referencing an instance of.

In reality, the child class is given a copy of the inherited behavior from the parent class. If the child “overrides” a method it inherits, both the original and overridden versions of the method are maintained and accessible.

In short: child class is not linked to its parent class. It instead gets a copy of what it needs from the parent class.

Multiple Inheritance

Some class-oriented languages allow you to specify more than one parent class to inherit from. However, some complicating questions arise. For example, if both classes have a method of the same name, which version should the child resolve to?

JavaScript is simpler: there’s no native mechanism for “multiple inheritance”. However, some developers keep trying to fake it.

Mixins

There are no “classes” in JavaScript to instantiate, only objects. And objects don’t get copied to other objects, they get linked together (see Chapter 5).

JS developers sometimes fake the missing copy behavior of classes in JavaScript by using mixins, either explicit or implicit.

Explicit Mixins

It’s possible to create a utility that manually copies properties from one object to another. Such a utility is often called extend(..) by many libraries/frameworks.

Technically, functions are not copied, but instead references to them are.

“Polymorphism” Revisited

When referencing an “inherited” method from a “child” object, you would need to explicitly call the method with Parent.method.call( this ). This is because JavaScript doesn’t have (prior to ES2015, see Appendix A) a facility for relative polymorphism.

We need to bind the method to the “child” object with this, so that it would access the “child’s” properties (not the “parent’s”).

You would need to create such explicit pseudo-polymorphism in every single function you need such a reference. The ability to “inherit” from multiple objects only increases the complexity.

The result is usually more complex, harder-to-read and harder-to-maintain code. This is why you should avoid explicit pseudo-polymorphism wherever possible!

Mixing Copies

Copying contents from one object to another (or creating a “mixin”) isn’t very effective. It’s pretty much the same as defining the same properties twice: once for each object. After the mixin, the objects aren’t related to each other.

Note: If the objects share a reference to the same object (function, array), modifying that object will show up on both these objects, so they can be kind of related.

If it starts to get harder to properly use mixins than before you used them, you should probably stop using mixins. (There’s also a better way, see Chapter 6).

Parasitic Inheritance

There’s a variation of the explicit mixin pattern called “parasitic inheritance”, popularized by Douglas Crockford. It’s in some ways explicit and in other ways implicit.

Here’s an example:

function Vehicle() {
  this.engines = 1;
}
Vehicle.prototype.ignition = function() {
  console.log( 'igniting' );
};
Vehicle.prototype.drive = function() {
  this.ignition();
  console.log( 'driving' );
};

function Car() {
  var car = new Vehicle();
  car.wheels = 4;

  var vehDrive = car.drive;

  car.drive = function() {
    vehDrive.call( this );
    console.log( 'rolling on ' + this.wheels + ' wheels' );
  };

  return car;
}

var myCar = new Car();

myCar.drive();
// igniting
// driving
// rolling on 4 wheels

We initially make a copy of the Vehicle “parent class” (object), then mixin our “child class” (object) definition, and pass off this composed object car as our child instance.

Note: When we call new Car(), a new object is created and referenced by Car‘s this reference. But since we don’t use that object, and instead return our own car object, the initially created object is discarded. So, Car() could be called without the new keyword, and the functionality would be identical, but without the wasted object creation and garbage-collection.

Implicit Mixins

Example:

var Something = {
	cool: function() {
		this.greeting = 'Hello World';
		this.count = this.count ? this.count + 1 : 1;
	}
};

Something.cool();
Something.greeting; // Hello World
Something.count; // 1

var Another = {
	cool: function() {
		Something.cool.call( this );
	}
};

Another.cool();
Another.greeting; // Hello World
Another.count; // 1

We “borrow” the function Something.cool() and call it in the context of Another via its this binding, instead of Something.

However, we still need the absolute reference Something.cool.call( this ), which cannot be made into a relative and more flexible reference. You should avoid such constructs where possible to keep cleaner and more maintainable code.

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 3

Here are some things I learned from Chapter 3: Objects of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

Syntax

With constructed-form objects (created with new Object()), you must add its properties one-by-one. It’s extremely uncommon to use the constructed form.

Type

There are six primary types (called language types in the specification) in JS:

  • string
  • number
  • boolean
  • null
  • undefined
  • object

The first five are called simple primitives and they are not objects. Note: typeof null returns object but that’s a bug. null is its own primitive type.

function is a sub-type of object, with callable behavior semantics bolted on.

Arrays are also objects, with extra behavior regarding the organization of contents.

Built-in Objects

There are several object sub-types, usually referred to as built-in objects:

  • String
  • Number
  • Boolean
  • Object
  • Function
  • Array
  • Date
  • RegExp
  • Error

These are not actual types nor classes like in some other languages. They are just built-in functions. Each of them can be used as a constructor, with the result being a newly constructed object of the same type.

Strings, numbers and booleans have both the primitive and the object wrapper form. You should always use the primitive form when possible.

You can call the constructor object’s methods and properties directly from the primitive value. JavaScript automatically coerces primitive values to their object wrapper form.

null and undefined have no object wrapper form, only their primitive values. By contrast, Date values can only be created with their constructor object form.

Objects, Arrays, Functions and RegExps are always objects regardless of whether the literal or constructed form is used. In some cases, the constructed form offers more options in creation but unless you need them, you should always use the literal form.

Error objects are rarely created explicitly. They are usually created automatically when exceptions are thrown.

Contents

Object contents may not be physically stored in some object container. Instead, the object’s properties are references to where the values are stored.

When accessing an object’s properties, the . operator requires an Identifier compatible property name, whereas the [".."] syntax can take any UTF-8/unicode compatible string as the property name.

In objects, property names are always strings. Any other values will first be converted to a string. These include numbers, so don’t confuse the use of numbers between objects and arrays.

Computed Property Names

ES2015 adds computed property names that work like this:

var prefix = 'foo';

var myObject = {
  [prefix + 'bar']: 'hello'
};

myObject['foobar']; // hello

The most common usage of computed property names are probably ES2015 Symbols. They are a new primitive data type that has an opaque unguessable (string) value. You shouldn’t use their actual value, so you’ll use the name of the Symbol. This is where computed property names become handy.

Property vs. Method

Some developers make a distinction between property access when the value happens to be a function, and call that a method. The specification makes this distinction, too.

However, JavaScript objects don’t “own” their properties. They only have a reference to a value that’s “independent” from the object. This means that whether the value of a property is a function or not, it’s a property nevertheless.

Arrays

Because arrays are objects, you can add properties to them. However, that doesn’t affect the length of the array. If the property name looks like a number (as in arr['3'] = 'baz'), it will be coerced to a numeric index.

Duplicating Objects

There are two kinds of duplication: shallow and deep. A shallow copy would copy all primitive values and reference to any other values. A deep copy would copy everything. However, if the object has a circular reference pattern, a deep copy would cause an infinite loop. That’s why only JSON-safe objects (in other words, objects that can be serialized to a JSON string and then re-parsed to an object) can be deep-copied.

ES2015 has defined Object.assign( targetObj, sourceObj ) for shallow copying. It takes a target object and iterates over all the enumerable, owned keys on one or more source objects and copies them to the target object (via = assignment). It then returns the target object. Any special characteristics of a property (like writable, see below) on a source object are not preserved.

Property Descriptors

As of ES5, all properties are described in terms of a property descriptor. In addition to the property value, it includes three other characteristics: writable, enumerable and configurable, each of which default to true.

You can use Object.getOwnPropertyDescriptor( obj, prop ) to view the descriptor characteristics and Object.defineProperty( obj, prop, options ) to add a new property or modify an existing one. However, you shouldn’t use this manual way unless you want to modify one of the descriptor characteristics from its normal behavior.

Writable

If writable is false, modification of that value will silently fail, or if in strict mode, throw a TypeError.

Configurable

If configurable is false and you try to modify the descriptor characteristics of that property, a TypeError is thrown regardless of the strict state. The only exception is changing writable from true to false (but not the other way around). Another thing is that it prevents the ability to use the delete operator to remove an existing property.

In other words, changing configurable to false is a one-way action, and cannot be undone.

Note: delete is only an object property removal operation, not a tool to free up allocated memory like in C/C++.

Enumerable

If enumerable is false, the property won’t show up in certain object-property enumerations, such as the for..in loop.

Immutability

ES5 added support for making properties or objects that cannot be changed. All of these approaches create shallow immutability. That is, the affect only the object and its direct property characteristics. If the object has a reference to another object, the contents of that object are not affected, and remain mutable.

Note: If you find yourself wanting to seal or freeze all your objects, there might be something wrong with your program design.

Object Constant

By combining writable:false and configurable:false, you can create a constant (cannot be changed, redefined or deleted) as an object property.

Prevent Extensions

If you want to prevent an object from having new properties added to it, but otherwise leave the rest of its properties alone, call Object.preventExtensions( obj ). In non-strict mode, trying to extend the object fails silently, and in strict mode, it throws a TypeError.

Seal

Object.seal( obj ) creates a “sealed” object: it calls Object.preventExtensions( obj ) and also marks all its existing properties as configurable:false.

So, you can’t add any more properties nor reconfigure or delete any existing ones. However, you can still modify existing values.

Freeze

Object.freeze( obj ) creates a frozen object: it calls Object.seal( obj ) and also marks all properties as writable:false, so that their values cannot be changed.

This approach is the highest level of immutability for an object itself, but other referenced objects are not affected. You could “deep freeze” an object by calling Object.freeze( obj ) recursively for the object and all its children but that can cause unwanted behavior.

[[Get]]

The { a: 2 }.a property access performs a [[Get]] operation on the object. It first inspects the object for a property of the requested name, and if it finds it, returns it. If it doesn’t find the value, it attempts traversal of the [[Prototype]] chain. If it can’t find any value, it returns undefined.

This differs from a lexical-scope look-up as the latter throws a ReferenceError if the identifier can’t be found.

If the property happens to have a value of undefined, the [[Get]] operation will also return undefined, so the value returned doesn’t tell whether the property was found or not.

[[Put]]

When assigning a value to an object property, a [[Put]] operation takes place.

If the property to be modified is present, the algorithm will roughly check:

  1. Is the property an accessor descriptor? If so, call the setter, if any (see below).
  2. Is the property a data descriptor with writable:false? If so, silently fail in non-strict mode,
    or throw a TypeError in strict mode.
  3. Otherwise, set the value to the existing property as normal.

If the property is not yet present, the operation is more complex. See Chapter 5.

Getters & Setters

ES5 introduced a way to override part of the default [[Put]] and [[Get]] operations on a per-property level, through getters and setters. Getters are properties that call a hidden function to retrieve a value, and setters are properties that call a hidden function to set a value.

When you define a property to have a getter or a setter or both, its definition becomes an accessor descriptor (as opposed to a data descriptor). For accessor descriptors, the value and writable characteristics are ignored, and JS considers the set and get characteristics, as well as configurable and enumerable.

Accessor descriptors can be created either through object-literal syntax or through explicit definition:

var myObject = {
  get a() {
    return this._a_;
  },

  set a(val) {
    this._a_ = val * 2;
  }
};

Object.defineProperty( myObject, 'b', {
  get: function(){ return this._b_; },
  set: function(val){ this._b_ = val + 4; },

  enumerable: true
} );

myObject.a = 3;
myObject.b = 1;

myObject.a; // 6
myObject.b; // 5

The names _a_ and _b_ are purely by convention, and there’s nothing special: they are normal properties like any other.

If a property doesn’t have a setter, the assignment operation fails silently (or if in strict mode, throws a TypeError). You should almost always declare both getter and setter in order to avoid unexpected behavior.

Existence

You can check if an object has a certain property:

var myObject = {
  a: 2
};

('a' in myObject); // true
('b' in myObject); // false

myObject.hasOwnProperty( 'a' ); // true
myObject.hasOwnProperty( 'b' ); // false

The in operator checks if the property is in the object or at any higher level of the [[Prototype]] chain object traversal (see Chapter 5).

By contrast, hasOwnProperty(..) checks if the property is in myObject and will not consult the [[Prototype]] chain. This method is accessible for all normal objects via delegation to Object.prototype. However, it’s possible to create an object that doesn’t link to Object.prototype via Object.create(null). In this case, we would need to use Object.prototype.hasOwnProperty.call( myObject, 'a' ) that uses explicit this binding to myObject.

Note: The in operator checks for the existence of a property name, not value:

4 in [2, 4, 6]; // false
1 in [2, 4, 6]; // true
Enumeration

Properties with enumerable:false show up in the in operator check but not in for..in loops. Conclusion: enumerable means “will be included if the object’s properties are iterated through”.

Applying a for..in to an array will include not only the numeric indices but also any additional enumerable properties. Don’t use for..in loops for arrays. Prefer traditional for loops instead.

obj.propertyIsEnumerable( prop ) tests whether prop exists directly on obj and is enumerable:true.

Object.keys( obj ) returns an array of all enumerable properties.

Object.getOwnPropertyNames( obj ) returns an array of all properties, enumerable or not.

All three inspect only the direct object specified. There’s currently no built-in way to get a list of all properties, traversing the entire [[Prototype]] chain. However, you can create a custom utility that recursively traverses the [[Prototype]] chain and captures a list from Object.keys(..) or Object.getOwnPropertyNames(..).

Iteration

ES5 added several iteration helpers for arrays, including forEach(..), every(..) and some(..). Each of these accepts a function callback to apply to each element in the array.

forEach will iterate over all values in the array. every(..) keeps going until the end or the callback returns a falsy value. some(..) keeps going until the end or the callback returns a truthy value.

Note: When iterating over an object’s properties, the order is not guaranteed and may vary between different JS engines.

ES2015 adds a for..of loop syntax for iterating over arrays:

var myArray = [1, 2, 3];

for (let v of myArray) {
  console.log( v );
}
// 1
// 2
// 3

The for..of loop asks for an iterator object of the array to be iterated from a default internal function known as @@iterator. The loop then iterates over the successive return values from calling that iterator object’s next() method, once for each loop iteration.

We can replicate the process manually:

var myArray = [1, 2, 3];
var it = myArray[Symbol.iterator]();

it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { value:undefined, done:true }

Note: We get the @@iterator internal property of an object using Symbol.iterator. You’ll always want to reference such special properties by Symbol name reference instead of by the special value it may hold. Also, @@iterator is not the iterator object itself, but a function that returns the iterator object.

The return value from an iterator’s next() call is an object of the form { value: .. , done: .. }, where value is the current iteration value, and done is a boolean that indicates if there’s more to iterate.

The value 3 was returned with a done:false. You have to call the next() a fourth time to get done:true and know you’re truly done iterating. This comes from the semantics of ES2015 generator functions.

Regular objects don’t have a built-in @@iterator. The reasons are complex but in general it was better to not include some implementation that could prove troublesome for future types of objects.

It is possible to define your own default @@iterator for any object. You can define arbitrarily complex iterations for your custom data structures. These combined with for..of loop are a powerful new syntactic tool.

You can even generate “infinite” iterators which never finish and always return a new value. However, you must remember to break from any for..of loop of such iteration so that your program won’t hang.

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 2

Here are some things I learned from Chapter 2: this All Makes Sense Now! of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

Call-site

Call-site means the location in code where a function is called (not where it’s declared).

Call-stack means the stack of functions that have been called to get us to the current moment in execution.

You can use Chrome debugger to find out the call-stack at any given line. The call-site is the second item from the top of the stack.

Nothing But Rules

There are four rules that determine where this is bound:

Default Binding

This is the default rule when none of the other rules apply.

When there’s a standalone function invocation, this refers to the global object and has the global identifiers as its properties.

If strict mode is in effect in the function that was called, this binding is not made and this becomes undefined. Whether or not the call-site is in strict mode is irrelevant.

You shoudn’t mix strict and non-strict mode in your code. Either make all your code strict (recommended) or none. However, some third-party libraries may have different strict rules than the overall code.

Implicit Binding

If the function is referenced from an object property and invoked through that object, this refers to that object. When there are multiple objects chained, this always refers to the last one (where it was invoked from).

Implicitly Lost

If you assign your object.function to another variable before executing, this will lose its binding to the object and most likely refer to the global object, or undefined if in strict mode. This also applies to passing the function as a function parameter, for example in setTimeout.

Some libraries intentionally change the this for the call. This might be useful or confusing, depending on the situation.

Explicit Binding

You can use func.call( obj ) or func.apply( obj ) to explicitly bind this to obj.

If you use a primitive value, it’s wrapped in its object-form. This is called boxing.

Both .call() and .apply() are identical with respect to this binding.

Unfortunately, explicit binding doesn’t solve the problem of a library messing with the this value.

Hard Binding

You can create another function and manually invoke a func.call( obj ) from inside it. Anywhere you pass this new function, this won’t be re-bound. This is called hard binding.

ES5 introduced a built-in utility Function.prototype.bind( obj ) that makes hard binding not hard at all. It returns a new function that is hard-coded to call the original function with the this context set as you specified.

As of ES2015, the hard-bound function produced by bind(..) has a .name property that derives from the original target function. For example, bar = foo.bind(..) has a bar.name value of "bound foo".

API Call “Contexts”

Many built-in and external functions provide an external parameter, usually called context that acts as a work-around for you not having to use bind(..). One example is Array.prototype.forEach( func, obj ) that lets you specify where to bind this in func as an optional second parameter. Internally, these functions most likely use call(..) or apply(..).

new Binding

In traditional class-oriented programming languages, constructors are special methods that run when a class is called with the new operator. In JavaScript, however, there are no constructor functions. Constructors are just functions that are called with the new operator in front of them. This is called a constructor call.

A constructor call causes four things to happen:

  1. A brand new object is created out of thin air.
  2. The newly created object is [[Prototype]]-linked.
  3. The newly created object is set as the this binding for that function call.
  4. Unless the function returns its own alternate object, the new-invoked function will automatically return the newly constructed object.

Everything In Order

The order of precedence to these rules is as follows:

  1. new binding
  2. Explicit binding
  3. Implicit binding
  4. Default binding

The reason why new takes precedence over explicit binding lies in the technical implementation of the .bind() method. Basically, the utility recognizes new and gives it precedence.

This feature is useful when we want to create a function that can be used to construct objects and preset some or all of its arguments. This is called partial application which is a subset of currying. For example:

function foo(p1, p2) {
  this.val = p1 + p2;
}

var bar = foo.bind( null, 'p1' );
var baz = new bar( 'p2' );

baz.val; // p1p2

Binding Exceptions

Ignored this

If you pass null or undefined as a this binding parameter to call, apply or bind, those values are ignored, and instead the default binding rule applies to the invocation.

You can use func.apply( null, arr ) for spreading out an array of values as parameters to a function call. Similarly, you can use func.bind( null, pre-set_values ) to curry parameters.

For the first case, there’s an ES2015 substitute called the ... spread operator. You would use it like this: func(...arr). However, there’s no substitute for the latter yet.

There’s a danger in using null: if the function makes a this reference, it can reference or mutate the global object.

Safer this

Instead of null, it might be safer to pass an empty object. This way, the code can’t accidentally modify the global scope. A recommended way is to create an empty variable ø = Object.create( null ). This is similar to { }, but without the delegation to Object.prototype, so it’s “more empty”. The variable name ø is a stylistic choice and its shortcut is Alt + 0248.

Indirection

You can (intentionally or not) create indirect references to functions, and when that function reference is invoked, the default binding rule applies.

One of the most common ways this can happen is from an assignment:

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

var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };

o.foo(); // 3
(p.foo = o.foo)(); // 2

The result value of the assignment expression above is a reference to just the underlying function object foo(), not p.foo() or o.foo().

Reminder: only the strict mode status of the contents of the invoked function making the this reference determines the default binding value. The function call-site status is irrelevant.

Softening Binding

It's possible to create a "soft-binding" function that checks if this gets a reference to the global scope and falls back to a soft-bound default object. This way, default binding won't happen but you get the possibility to bind to other objects; the best of both worlds.

Lexical this

An arrow function inside another function lexically captures whatever its parent's this is at its call-time. This can't be overridden, even with new.

However, arrow functions (or using var self = this) are fleeing from this instead of embracing it. You should understand this and use bind(..) where necessary. This improves maintainability and is a more elegant solution overall.

Things I Learned from You Don’t Know JS: this & Object Prototypes, Chapter 1

Here are some things I learned from Chapter 1: this Or That? of You Don’t Know JS: this & Object Prototypes by Kyle Simpson.

Why this?

Consider these two code snippets:

Snippet 1:

function identify() {
  return this.name.toUpperCase();
}

var me = {
  name: 'Joonas'
};

identify.call( me ); // JOONAS

Snippet 2:

function identify(context) {
  return context.name.toUpperCase();
}

var me = {
  name: 'Joonas'
};

identify( me ); // JOONAS

Both snippets are functionally identical. However, the first one is a more elegant way to pass along an object reference. It leads to cleaner API design and easier re-use, especially in complex programs.

Confusions

There are two common misconceptions of what this refers to:

Itself

No, this doesn’t refer to the function object itself unless you tell it so:

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

foo.num = 5;

foo.call( foo ); // 5 because foo.call( foo ) sets this to foo

Its Scope

No, this doesn’t refer to the function’s lexical scope, either. In fact, lexical scope isn’t an object that’s accessible to JavaScript code. It’s an inner part of the engine’s implementation.

You can’t form a lexical bridge between two functions by using this.

What’s this?

this is not an author-time binding but a runtime binding. It has nothing to do with where the function is declared but everything to do with how it is called.

When a function is invoked, an activation record, or execution context, is created. It contains information about where the function was called from, how it was invoked, what parameters were passed etc. One of these properties is the this reference which will be used for the duration of the function’s execution.