Skip to content

Instantly share code, notes, and snippets.

@matt-mcmahon
Forked from bennadel/context.js
Created May 15, 2017 13:44
Show Gist options
  • Save matt-mcmahon/2f685c21fbbd68251dba704564b8f0e4 to your computer and use it in GitHub Desktop.
Save matt-mcmahon/2f685c21fbbd68251dba704564b8f0e4 to your computer and use it in GitHub Desktop.
Method Binding Is An Implicit Part Of Your API Contract (Whether You Like It Or Not)
// Require the core node modules.
var chalk = require( "chalk" );
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// I am a mock zEmbed class.
// --
// NOTE: With a traditional "class", all of the internal references use "this" because
// the methods are all located on the class prototype and do not have a lexical binding
// to any of the other methods or instance variables.
class ZEmbed {
constructor( token ) {
this.token = token;
}
// ---
// PUBLIC METHODS.
// ---
hide() {
console.log( chalk.red( `Hiding widget ${ this.token }.` ) );
// Return this object to facilitate method chaining.
return( this );
}
show() {
console.log( chalk.green( `Showing widget ${ this.token }.` ) );
// Return this object to facilitate method chaining.
return( this );
}
}
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
var zEmbed = new ZEmbed( "9cf6672aaf" );
// Let's detach the methods from the object for extra clarity on binding.
var show = zEmbed.show;
var hide = zEmbed.hide;
// Because the zEmbed methods are part of a traditional class bindings, the following
// calls WILL BREAK. The methods are being executed outside of their expected context.
setTimeout( show, 500 );
setTimeout( hide, 1000 );
// Require the core node modules.
var chalk = require( "chalk" );
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// I am a mock zEmbed object constructor.
function ZEmbed( token ) {
// Return the public API for this object.
// --
// NOTE: The public API is a collection of functions that are using lexical binding
// in order to locate "class variables".
return({
hide: hide,
show: show
});
// ---
// PUBLIC METHODS.
// ---
function hide() {
console.log( chalk.red( `Hiding widget ${ token }.` ) );
}
function show() {
console.log( chalk.green( `Showing widget ${ token }.` ) );
}
}
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
var zEmbed = new ZEmbed( "9cf6672aaf" );
// Let's detach the methods from the object for extra clarity on binding.
var show = zEmbed.show;
var hide = zEmbed.hide;
// Because the zEmbed methods are using lexical binding, the methods can be passed
// around as "naked" references. This feature is an IMPLICIT part of your object API.
setTimeout( show, 500 );
setTimeout( hide, 1000 );
// Require the core node modules.
var chalk = require( "chalk" );
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// I am a mock zEmbed object constructor.
function ZEmbed( token ) {
// Return the public API for this object.
// --
// NOTE: The public API is a collection of functions that are using lexical binding
// in order to locate "class variables". However, the public method do return a
// reference back to the public API (this) for method chaining.
return({
hide: hide,
show: show
});
// ---
// PUBLIC METHODS.
// ---
function hide() {
console.log( chalk.red( `Hiding widget ${ token }.` ) );
// Return this object to facilitate method chaining.
return( this );
}
function show() {
console.log( chalk.green( `Showing widget ${ token }.` ) );
// Return this object to facilitate method chaining.
return( this );
}
}
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
var zEmbed = new ZEmbed( "9cf6672aaf" );
// Let's detach the methods from the object for extra clarity on binding.
var show = zEmbed.show;
var hide = zEmbed.hide;
// Because the zEmbed methods are using lexical binding, the methods can be passed
// around as "naked" references. This feature is an IMPLICIT part of your object API.
setTimeout( show, 500 );
setTimeout( hide, 1000 );
// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //
// Even though the zEmbed class methods are using lexical binding to locate the class
// properties, they are also using the this-binding to return a reference back to the
// public API. This allows for method chaining, but ONLY IF you invoke the methods in
// the context of the public API.
setTimeout(
() => {
// Try method-chaining in the context of the API.
console.log( chalk.bold( "\n== Trying method chaining ==" ) );
zEmbed.show().hide();
// Try method-chaining with the naked method references.
console.log( chalk.bold( "\n== Trying NAKED method chaining ==" ) );
show().hide();
},
2000
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment