Thursday, 24 November 2016

Javascript: check undefined/null

If you are sure the variable has been declared (i.e var a;), simply use
if (a != null){
    ...
}
If a can be undeclared, then use


if (typeof a != 'undefined' && a != null){
    ...
}

Javascript: softbind

Excerpted from You Don't Know JS: this & Object Prototypes

I couldn't fully understand the code below.
  
if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
        var fn = this,
            curried = [].slice.call( arguments, 1 ),
            bound = function bound() {
                return fn.apply(
                    (!this ||
                        (typeof window !== "undefined" &&
                            this === window) ||
                        (typeof global !== "undefined" &&
                            this === global)
                    ) ? obj : this,
                    curried.concat.apply( curried, arguments )
                );
            };
        bound.prototype = Object.create( fn.prototype );
        return bound;
    };
}

function foo() {
   console.log("name: " + this.name);
}

var obj = { name: "obj" },
    obj2 = { name: "obj2" },
    obj3 = { name: "obj3" };

var fooOBJ = foo.softBind( obj );

fooOBJ(); // name: obj

obj2.foo = foo.softBind(obj);
obj2.foo(); // name: obj2   <---- look!!!

fooOBJ.call( obj3 ); // name: obj3   <---- look!

setTimeout( obj2.foo, 10 ); // name: obj   <---- falls back to soft-binding
  1. What does [].slice.call(...) do? 
  2. Are the two 'this' referring to the same thing? 
  3. What does bound.prototype = Object.create(fn.prototype) do?
Let's go through the code step by step by inserting some console output code. And for the sake of demonstrating the purpose of curried, I also rewrote the foo() function.
if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
        var fn = this;
        console.log("Outer this = "+ fn);
        var curried = [].slice.call( arguments, 1 );
        console.log("Outer curry = "+curried);
        var bound = function bound() {
            console.log("Inner this = " + this);
            console.log("Inner curry = "+curried.concat.apply( curried, arguments ));
            return fn.apply(
                (!this ||
                    (typeof window !== "undefined" &&
                        this === window) ||
                    (typeof global !== "undefined" &&
                         this === global)
                ) ? obj : this,
                curried.concat.apply( curried, arguments )
            );
        };
        bound.prototype = Object.create( fn.prototype );
        console.log("return bound");
        return bound;
    };
}

function foo(a1, a2) {
   console.log(a1 + ' ' +a2 + " name: " + this.name);
}

var obj = { name: "obj" },
    obj2 = { name: "obj2" },
    obj3 = { name: "obj3" };

var fooOBJ = foo.softBind( obj, 'A1');
fooOBJ('A2'); // name: obj

//obj2.foo = foo.softBind(obj, 'A1');
//obj2.foo('A2'); // name: obj2   <---- look!!!

//fooOBJ.call( obj3 ); // name: obj3   <---- look!
Here is the output.
Outer this = function foo(a1, a2) {
   console.log(a1 + ' ' +a2 + " name: " + this.name);
}
Outer curry = A
return bound
Inner this = [object Object]
Inner curry = A,A2
A A2 name: obj2

[].slice.call(arguments, 1)
is semantically equal to
arguments.slice(1)
except the latter is syntactically incorrect because the variable arguments is not a real array. It's an 'array-like' object.

The outer this refers to the foo function while the inner this refers to the window (global) variable. It's worth noting that by the time foo.softBind(obj) completes execution, the bound() function hasn't been invoked. It's only invoked when the line fooOBJ('A2') is executed.

bound.prototype = Object.create( fn.prototype );
copies all the properties of foo to bound, essentially ensuring that after softbind the function foo doesn't lose any properties.

Wednesday, 23 November 2016

Javascript: dabble in 'new'

The code snippet below demonstates the difference between invoking a function with and without new.
function foo(a) {
    this.a = a;
}

var bar = new foo( 2 );
var bar2 = foo( 2 );

console.log( bar); // foo {a: 2}
console.log( bar.a); // 2
console.log( bar2); // undefined 
console.log( bar2.a); // TypeError
Why bar2 is undefined? Because there is no return statement in foo(). What if there is?
function foo(a) {
    this.a = a;
    return this;
}

var bar = new foo( 2 );
var bar2 = foo( 2 );

console.log( bar); // foo {a: 2}
console.log( bar.a); // 2
console.log( bar2); // Window {top: Window, location: Location, document: document, window: Window, external: Object…}
console.log( bar2.a); // 2
Why bar2.a = 2 while bar2 itself is the Window object? Because this refers to the Window object and this.a essentially creates an 'a' variable in global scope (Window object). Now what if returning something other than this?
function foo(a) {
    this.a = a;
    return 3;
}

var bar = new foo( 2 );
var bar2 = foo( 2 );

console.log( bar); // foo {a: 2}
console.log( bar.a); // 2
console.log( bar2); // 3
console.log( bar2.a); // undefined
Oh, it turns out that having a 'new' precede a function ignores the return statement all together. Although the author of stresses that 'new' in Javascript has nothing to do with the constructor concept in class-oriented languages, I, with a Java background, am still inclined to interpret it as:
class foo{
    var a;
 
    public foo(a){
        this.a = a;
    }
}

var bar = new foo(2);

Tuesday, 22 November 2016

Javascript: 'this' and call

In this post, my assertion that

impl.apply(impl, deps) = impl.apply(null, deps);

just shows how naive I was due to the lack of understanding of 'this' mechanism.

From You Don't Know JS: this & Object Prototypes

function foo(num) {
    console.log( "foo: " + num );

    // keep track of how many times `foo` is called
    // Note: `this` IS actually `foo` now, based on
    // how `foo` is called (see below)
    this.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
    if (i > 5) {
        // using `call(..)`, we ensure the `this`
        // points at the function object (`foo`) itself
        foo.call( foo, i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 4 
The first parameter foo essentially makes 'this' point to the foo object.
Now replace the line with

foo.call( null, i );

It prints out '0' because this refers to window object now.

I am tempted to boldly make this assertion that the following two pairs of method invocation can always be used interchangeably.

foo.call( foo, i ) = foo.bind(foo)(i)
foo.call( null, i) = foo(i)  

Let's see when I can be proved wrong.


Javascript: dabble in 'this'

It is probably going to take me a while to fully grasp the 'this' concept in Javascript. Today I just dabble in the topic and present my shallow understandings.

It still comes from You Dont Know Js Scope and Closure, Appendix C: Lexical this.

var obj = {
    id: "awesome",
    cool: function coolFn() {
        console.log( this.id );
    }
};

var id = "not awesome";

obj.cool(); // awesome

setTimeout( obj.cool, 100 ); // not awesome

It looks like when invoked from setTimeout(), this refers to the window object. Then the author introduced various solutions, including self, bind(), and a new feature of ES6: arrow function. These are all cool stuff. But how to address the original problem -- that is, to get setTimeout() function to print 'awesome' as well?

The simplest solution is replace this with obj

console.log( obj.id );

Then I attempt to use bind().

cool2: function coolFn2() {
    console.log( this.id );
}.bind(obj)
It doesn't work because obj cannot be referenced within itself, well, unless it is referenced within a function. Therefore the 2nd attempt.

cool3: function coolFn3() {
    (function(){
        console.log(this.id); 
    }.bind(obj))();
} 
Hey it works. I wouldn't have come up with this solution if I hadn't read the previous chapters of 'You Dont Know Js'. So once again, kudos to the author.

Javascript: apply

In You Dont Know JS Chapter 5: Scope Closure, there is following code snippet to illustrate the power of module pattern.

var MyModules = (function Manager() {
    var modules = {};

    function define(name, deps, impl) {
        for (var i=0; i<deps.length; i++) {
            deps[i] = modules[deps[i]];
        }
        modules[name] = impl.apply(impl, deps);
        console.log("module "+modules[name]);
    }

    function get(name) {
        return modules[name];
    }

    return {
        define: define,
        get: get
    };
})();

MyModules.define( "bar", [], function(){
    function hello(who) {
        return "Let me introduce: " + who;
    }

    return {
        hello: hello
    };
} );

MyModules.define( "foo", ["bar"], function(bar){
    var hungry = "hippo";

    function awesome() {
        console.log( bar.hello( hungry ).toUpperCase() );
    }

    return {
        awesome: awesome
    };
} );

var bar = MyModules.get( "bar" );
var foo = MyModules.get( "foo" );

console.log(bar.hello( "hippo" )); // Let me introduce: hippo

foo.awesome(); // LET ME INTRODUCE: HIPPO

What does this line do?
modules[name] = impl.apply(impl, deps);

It is another way of invoking a function, sort of like Java reflection. And we get to pass an array variable in the second argument to replace a list of parameters. What is the first argument for?

According  to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

fun.apply(thisArg, [argsArray])

Parameters

thisArg
The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
I don't quite understand this definition. As far as I am concerned,

fun.apply(thisArg, [argsArray]) = thisArg.fun(arg1, arg2....)

In this case, I also don't understand why the first parameter is 'impl'. But I have proved it can be replaced with 'null'.

The next question is why the function needs to be called in such a unconventional way. Could it be called normally?

If we put

modules[name] = impl(deps);

bar.hello() executes OK, but foo.awsome() throws TypeError: bar.hello is not a function.

Then try

modules[name] = impl(deps[0]);

It does work. But obviously it's not a universal solution. Hence the use of apply().

Thursday, 17 November 2016

Javascript: Closure + Loop

What does this program print out?
for (var i=1; i<=5; i++) {
    setTimeout( function timer(){
        console.log( i );
    }, i*1000 );
}
At first glance, it seems to print 1,2,3,4,5, at 1 second interval. But in fact, it prints 6,6,6,6,6 at 1 second interval. What is going on?

At second glance, it does make sense. The timer() function is invoked after the waiting period (i*1000). By the time it starts to execute, the for loop has long finished. And at this point of time, i = 6.

So how to fix it? 

By wrapping the setTimeout() with a function makes the variable j local to the enclosing function.

for (var i=1; i<=5; i++) {
    (function(){
        var j = i;
 setTimeout( function timer(){
     console.log(j);
        }, i*1000 );
    })();
}
A neater variation.
for (var i=1; i<=5; i++) {
    (function(j){
 setTimeout( function timer(){
     console.log(j);
        }, i*1000 );
    })(i);
}
Even better is replace var with let (ES6 feature)
for (let i=1; i<=5; i++) {
    setTimeout( function timer(){
 console.log(i);
    }, i*1000 );
}
This is most surprising. It turns out let not only restrain the variable within the for loop but also each iteration!