JS Quick Restart for the Impatient

When you, an old polyglot, need to get started quickly. After a long break from Javascript

1 Synopsis

When you switch languages, and come back to an old friend after a long time, it’s generally nice to first catch-up. Else, you end up displaying ignorance and thus telling your old friend that you don’t actually care!

Well, you do care, but there’s only so much your head can hold. And while you know the basics of programming languages in general, the quirks often bite you. Hard. This is about doing a quick catch-up with Javascript, so that you can get started with the other stuff quickly.

Note – In no way does this page attempt to either introduce you to Javascript, or teach you how to do it right! It’s only a collection of thoughts I find useful when coming back to Javascript after a good, long break.

And, as of this writing, Javascript.info is a pretty handy collection of explanations and code.

2 Javascript. The Beauty. And the Beast.

2.1 Quick reminders

  • It’s functional.
  • It’s imperative.
  • It’s mutable all over the place.
  • It’s object oriented.
  • It’s class-oriented. Not!

2.2 Quick bites.

2.2.1 Forget the var and you get industrial-strength pollution


function foo() {
    // disaster! Hoisted to the top.
    bar = 10;

    // Safe-r
    var baz = 20;
    console.log("The value of bar is " + bar);
}

foo();

// 10. The bar is so low, you'll run into it here.
bar;

// Yay! We can clean up.
delete bar;

2.2.2 Make let, not var

Choose your modifier wisely.

  • var is global scope, or if within a function, all of the function-scope.
  • let is safer. It’s always block scope. And let is also not hoisted to the top of the block, unlike var.
function noop() {
    // ok, though undefined
    console.log(bar);

    // blow up! ReferenceError
    console.log(blow);
    var bar = 10;
    let blow = 0;
}

2.2.3 Prefer const

const some = {}
// Now you can NOT reassign some to anything else

// But!
some.attribute = "hey there!"; // ok
// some is NOT immutable.

2.2.4 Functions are objects too. And can be used as constructors.

function Foo() {
    this.bar = 10;
}

// foo got no bar.
var foo = Foo();

// But, bar is a thing. Top level.
bar;

// foo got the bar!
var foo = new Foo();
console.log(foo.bar); // 10

It’s the this keyword that needs attention, under the influence of new.

2.2.5 Modify Objects. The Formal Way.

// Boring stuff
// But look up
Object.defineProperty(...);

const o = {};

Object.defineProperty(o, 'immutableProperty', {
    value: 0,
    writable: false
});

o.immutableProperty; // 0
// You can't assign a new value to
// o.immutableProperty. Yay!

// and
Object.defineProperties(...);

2.2.6 Accessor properties

Make function call (getter/setter) appear like attribute access

let foo = {
    _val: 'foo',
    get val() { return this._val; },
    set val(new_val) {
        this._val = new_val + '-' + new_val;
    }
}

foo.val; // 'foo'
foo.val = 'bar'; // _val is now 'bar-bar'

Gives you a nice way to create objects that appear to be not mutable.

2.2.7 prototype and __proto__ are different things

__proto__ was a non-standard property until ECMAScript 2015, although widely defined in various implementations. prototype is typically available on objects like, well, Object, Function, Array, Date – that are used to set the __proto__ objects on newly constructed instances. The correct way to access the prototype of any object are

  • Object.getPrototypeOf() / Reflect.getPrototypeOf(), and
  • Object.setPrototypeOf() / Reflect.setPrototypeOf()

And the use of __proto__ is discouraged in favour of the above - See this.

The prototype property on various kinds of objects are used to set the __proto__ on the new-ly created objects. The prototype is essentially referred to by the __proto__ of derived objects. So, you may modify the prototype on the parent to have its effect reflect on all derived instances. Concretely,

var F = function() { this.name = "f" }
var f = new F();
f.__proto__ == F.prototype // true
f.prototype // undefined

I did not look enough to be sure, but __proto__ is an accessor property - meaning, it is a getter and a setter that exposes the internal Prototype object. For want of the right symbol to represent this object, the standard way is [[Prototype] ]

2.2.8 Setting up hierarchies

Object.create – this creates another object, given a prototype. Without going through the constructor. So, when setting up hierarchies, you may do

Derived.prototype = Object.create(Base.prototype)

But, there are other ways. You can set the prototype to another actual instance of the Base. Or, directly to the prototype. The takeaway, though, is that there’s no one way and the right way is context dependent. Just don’t worry much. JS is Perl-like and TIMTOWTDI

More below.

2.2.9 Asynchronous. All the way down.

Well, this is a lie. But a very useful one. Javascript is single-threaded in its execution. So, there’s a proliferation of styles and libraries that do other things during blocking calls. Other useful things. Blocking calls are many. Network and disk IO, database calls. So too, in the browser world, the programmer does not deal with a linear flow. The user on the web-page has no fixed pattern or order of interaction. There are asynchronous user-events all over the place, and these are mapped to DOM events.

So, with the combination of the single-threaded nature of Javascript and the evented behavior in browsers, the Javascript ecosystem is heavily about asynchronous styles and callbacks. This is something to hold strongly in your head as you deal with code in the large, and especially when you come (back) from most other programming languages.

3 Objects. Modules.

There are various styles. It’s a matter of choice and needs. Some are easy to write, but less memory efficient. Some are a bit involved to code, but end up being more memory efficient. (You guessed it - using the prototype for common methods!)

3.1 Object.create

Object.create(anyExistingObjectUsedAsPrototype);

// More interestingly
var statelessLogicContainer = {
    someFunc: function() {
        // assumes presence of this.stateVar
        // and operates with/on it
    }
}

var someInstance = Object.create(statelessLogicContainer, {
    "stateVar": {
        value: "Full state honors",
        writable: false // default
        configurable: false // default
        enumerable: true // depends
    },
    "moarStateVars" : {
        //
    }
});

// someInstance shares underlying logic (and even state - bad idea?)
// from statelessLogicContainer and adds its own 'stateVar' and
// 'moreStateVars'

3.2 Function based constructors


function Contact(name, phone) {
    return {
        whatsYourName() { return name; },
        call() {
            console.log("Calling " + name + " at " + phone);
        }
    }
}
// The data in the above case is available in a closure.
// But not for outside modification.
// Of course, the usual pass-by-reference/value semantics apply.

function EfficientContact(name, phone) {
    this._name = name;
    this._phone = phone;
}
// Everyone has access to the name and phone.

EfficientContact.prototype.whatsYourName = function() {
    return this._name;
}
EfficientContact.prototype.call = funtion() {
    console.log("Calling " + this._name + " at " + this._phone);
}
// But the above methods are shared across derived instances.

new EfficientContact('Rama', 108);

3.3 The Object literal

{
    attribute: 10,
    someFunction: function() {
        // Can access attributes
        return this.attribute;
    }
}

3.4 The Module Pattern

var someModule = (function (arg) {
    var somePrivate = '??';
    var someOtherPrivateFunction() {
        // I also have access to the arg, okay?
    }
    // Possibly some initializer code

    return {
        // An object that captures the results
        // of initialization, local variables in this
        // scope via the closure, as well as access
        // to the argument 'arg'
    };
})(myExternalArg);

3.5 CommonJS

This is a convention used for packaging modules used in certain environments. Like nodejs.

3.6 AMD - Asynchronous Module Definition

This is another convention for packaging modules, with dependency declarations. As the name suggests, this is geared towards enabling asynchronous loading of libraries/modules. Useful when you are executing within the browser and JS sources could exist at different locations, and network latencies with linear loading will make the process slow. Especially when browsers can load in parallel.

Implementations which deal with the AMD format include libraries like RequireJS and Dojo.

3.7 Asidebrowserify and webpack

browserify can process node-like module definitions, combine sources from various files, and prepare them for use within the browser. webpack helps in creating complex source-code transformation pipelines.

3.8 ES2015 Modules

Only mentioned here for the sake for completeness (as of this writing.) The Auth0 article (mentioned in the reference) is a very good read.

4 Bindings and Closures

Javascript being dynamic, with its functions being exotic, bindings and closures are used for good effect.

function foo() {
    // greeting is in the closure
    let greeting = "Hello";
    console.log(greeting + ", " + this.name + "!");
}
foo(); // Hello, undefined!

let nameContext = { name: "Jedi" };
// We bind the 'this' in foo to nameContext
let jediCaller = foo.bind(nameContext);
jediCaller(); // Hello, Jedi!

5 Callbacks

There’s not much to be said here. All asynchronous calls will expect callback functions. And generally, because you can have either a successful execution or a failure, you pass a callback (or callbacks) to deal with both. It’s only a matter of style as to whether a callback deals with both kinds of results, or you use different ones for error and success.

6 Asynchronous Code

This is too big a topic by itself. But apart from the fact that you deal with the asynchronous nature of various calls by way of passing callbacks, you can also make use of some constructs/libraries that allow you to lay out your code in a more serial manner.

Use Promise objects, if you’d like to avoid the usual callback style. But remember that Promise objects don’t let the computation outcomes escape easy. In a way, it reminds of the core.async way of Clojurescript - only, a bit different and more involved. But it has clear semantics about differentiating between success and error conditions.

To make it a bit easy for you to consume asynchronous computation, there’s a more complicated async-await route to structuring your code.

const slowIdentity =
      (x) => new Promise(resolve => {
          setTimeout(() => {
              resolve(x);
          }, 10000);
      });

async function awaiter() {
    console.log("I'll wait...");
    console.log("And the value is - " +
                await slowIdentity(10));
    console.log("Ciao!");
}

awaiter();

7 References