• 'bare function' is when it is not a method function of an object - that means it does not need or use a this context - and gets variable parts - if needed - as parameters. But since there is always a context, it is somehow cobbled up by the interpreter. For this reason this is often NOT what we expect to be, undefined, or does not understand what we ask it for - for state or for behavior. See MDN https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Function/apply

    That this functionXyz.apply(thisArg, argArray) works is a core nature of JavaScript. To give you examples:

    Think of two objects that have both a width and a length in rectangular form that defines their foot print, in addition to other things, that can be totally different - for example shipping container (8 feet wide, 8.5 feet tall and of different length (or flooring tiles) and you need to know the total surface - footprint - these objets cover (can cover) when not stacked.

    Btw, while reading this, paste the code pieces into the console... and you will see the results right away.

    var obj1 = {"w":8, "h":8.5, "length":20,  "name":"object1",  "propertyFoo":"Foo"};
    var obj2 = {"w":8, "h":8.5, "length":40, "name":"object2",  "propertyBaz":"Baz"};
    var objects = [ obj1, obj2 ];
    

    Now you can define a function that, when applied to any of these objects delivers you the footprint in square feet:

    function footPrint() { // for example, container foot print
       var area = this.w * this.length;
      console.log(this.name+' covers '+area+'sf.');
      return area;
    }
    

    Question: how in the world does this footPrint know what this means - refers to. If you invoke the bare function, you will get an error - probably, this.w, .length and .name not defined, because this is not what you expect it to be, and it may throw different errors when called in different contexts... some they may have a property w, length and name, but with a totally different meaning.

    footPrint();
    

    When applying this function to an object that it can handle or can be handled by it, we get what we want:

    footPrint.apply(obj1);
    footPrint.apply(obj2);
    

    And when we want the total we do this:

    objects.reduce(function(sum, object){ return sum + footPrint.apply(object); }, 0);
    

    and get 480.

    Now, we make it a bit more elaborated: We want to know what the volume is these container objects can store: how many cubic feet of what ever they can store. It is easy to understand that the longer container have a stronger structure - beams, walls, etc. and may therefore have less storage volume. Therefore we create a volume() function for both lengths, conveniently named:

    function volume20() {
       var volume = (this.w - 2*0.5) * (this.length - 2*0.6) * (this.h - 0.8 - 0.4);
      console.log(this.name+' stores '+volume+'cf.');
      return volume;
    }
    function volume40() {
       var volume = (this.w - 2*0.7) * (this.length - 2*8) * (this.h - 0.8 - 0.4);
      console.log(this.name+' stores '+volume+'cf.');
      return volume;
    }
    

    Fort the total volume we use:

    objects.reduce(function(sum, object){
       var volumeFunction = global['volume'+object.length];
       return sum + volumeFunction.apply(object); }, 0);
    

    and get 2116.9999999999995

    Now, you say, why all this mess, because we could define a Container class and have a constructor that takes values, and then instance methods for .footPrint() and .volume() and what ever we need for convenience... and we can make it even inheriting: Container is the super class and entry class for constructor invocation and we pass a length and get instances of Container20 or Container40 sub class instances es back.

    Exactly, this is what ES6 gives us. Deep under the hood though, exactly what we so cumbersome experienced, happens, even ES6 does under the hood the XyzConstructorFunction.prototype.abc = pattern... at least logical. But that is not the full truth, because we can use these mechanism for all kinds of dynamic things...

    In this context belongs also the .bind().... see MDN https://developer.mozilla.org/en-US/docs­/Web/JavaScript/Reference/Global_Objects­/Function/bind.

    This allows us to invoke a bare function, but because it was bound before to an object, it is as if we invoke it as a method on the bound object. This is helpful for all cases where we can only pass a (callback) function, such as in setTimeout, setInterval, setWatch, and in many modules where things happen asynchronously or time deferred and we do not want to block the processor.

    var boundFootPrintObj1 = footPrint.bind(obj1);
    setTimeout(boundFootPrintObj1,1000);
    

    Executed we get delayed 160 as expected.

    What .bind() does is returning a new anonymous function that knows to apply the function mentioned to the bound object.

    Sane is for the an ES6 created object, that would have the method .footPrint().

    What we then say (in pre ES6) is:

    function Obj(name) { this.w=8; this.length=20; this.name=name; }
    Obj.prototype.footPrint=function(){var f = this.w*this.length; 
       console.log(this.name+' covers '+ f+'sf');}
    var obj = new Obj("obj");
    var boundFootPrintObj = obj.footPrint.bind(obj);
    setTimeout(boundFootPrintObj,1000);
    

    The first part of the right side in first line obj.footPrint provides as the reference to the method definition, which is actually only a function (attached with the .prototype to the constructor function in ES5, and ES6 tersed and sugar coated or us). The bind then returns - again - a new anonymous function that knows to apply the 'method' function to the bound object, thru which we even found the actual method in the first place.

    The ES6+ version I leave up to you to do... ;-) piece of cake... and I can have the cake and eat it.

About

Avatar for allObjects @allObjects started