confusion over how "softBind" function works

Viewed 684

I'm currently studying javascript by following the "you dont know js" series.

In section "this & object prototype", the author came up with an way to soft bind this.

However, I am extremely confused by the code. So I was wondering if someone could kindly explain it to me, steps by steps, what the code really does?

//step 1: if "softBind" property does not exist on `Function.prototye`

if (!Function.prototype.softBind) {

    //step 2: create a property named "softBind" on "Function.prototype" and assign to "softBind" the following function 

    Function.prototype.softBind = function(obj) {

        //step 3: what is the point of assigning "this" to the variable "fn"?
        //what does "this" represent at this point in time?

        var fn = this,

            //step 4: I understand that "arguments" is an array-like object, i.e. "arguments" is not a true array. 
            //But you can convert "arguments" to an true array by using "[].slice.call(arguments)". 
            //The thing I dont understand here is, why the 1? 
            //I understand it tells "slice" method to start slicing at index 1, but why 1? 
            //And what is the purpose of "curried" variable? 

            curried = [].slice.call( arguments, 1 ),

            bound = function bound() {

                //step 5: I understand what "apply" function does

                return fn.apply(

                    //step 6: I dont really understand how "!this" works. 

                    (!this ||

                        //step 7: utterly confused...   
                         
                        (typeof window !== "undefined" &&
                            this === window) ||
                        (typeof global !== "undefined" &&
                            this === global)

                    //step 8: if the above statements evaluates to "true", then use "obj", 
                    //otherwise, use "this"

                    ) ? obj : this,

                    //step 9: can't I write "curried.concat(arguments)" instead?
                    //why the convoluted syntax?

                    curried.concat.apply( curried, arguments )
                );
            };

        //step 10: Why assign the "fn.prototype" as the prototype to "bound.prototype"?

        bound.prototype = Object.create( fn.prototype );
        return bound;
    };
}

I'm very sorry for the long question, but I thought instead of dividing the question into several posts, it is more convenient if they are put into one place.

1 Answers
Related