Javascript

The Real Bad Parts

By @johnkpaul

johnkpaul.com/empirejs

What's bad but not so bad?

from Bad Parts: Appendix B - JavaScript: The Good Parts

  • with
  • eval
  • void
  • type coersion
  • continue/switch

How often do these issues come up?

how many with bugs have you wrangled?

The real bad parts

  • difficult concepts to grasp in the javascript language
  • high blog post to understanding ratio
  • what we might understand, but can't easily explain to others

The real bad parts

  • How does this work?
  • How does prototypal inheritance work?
  • How does scope and hoisting work?

5 different ways to set this

  • "method" call
  • baseless function call
  • using call
  • using apply
  • constructor with new
  • => fat arrow

"method" call


        var obj = {
            fullName:"John K. Paul",
            alertName:function(greeting){
                alert(greeting + " " + this.fullName);    
            }
        };

        obj.alertName("Hey"); // Hey John K. Paul
                                                

baseless function call


        var obj = {
            fullName:"John K. Paul",
            alertName:function(greeting){
                alert(greeting + " " + this.fullName);    
            }
        };

        var alertName = obj.alertName;
        alertName("Hey"); // Hey undefined
        // this is set to the global object unless in strict mode
                                                

using call


        var obj = {
            fullName:"John K. Paul",
            alertName:function(greeting){
                alert(greeting + " " + this.fullName);    
            }
        };

        var alertName = obj.alertName;
        var newContext = {
            fullName:"John Doe"
        };
        alertName.call(newContext, "Hey"); // Hey John Doe
                                            

using apply


        var obj = {
            fullName:"John K. Paul",
            alertName:function(greeting){
                alert(greeting + " " + this.fullName);    
            }
        };

        var alertName = obj.alertName;
        var newContext = {
            fullName:"John Doe"
        };
        alertName.apply(newContext, ["Hey"]); // Hey John Doe
                                            

constructor with new


        var Constructor = function(){
                this.sayHey = function(){
                     alert("Hey");    
                }
             }

        //this is a newly created object
        var newObject = new Constructor(); 
        newObject.sayHey() // Hey 
                                            

Fat Arrow =>

In ES6


// with fat arrow inner function
var myObj = {
  longOuter: function() {
    console.log(this); // this is myObj
    var fatInner = () => 
      console.log(this); // this is also myObj
    fatInner(); 
  }
}

myObj.longOuter(); 
                                        

What on earth is prototypal inheritance

What is inheritance...really?

Is it classes?

Is it blueprints?

Is it super?

No, none of these

Code Reuse

This is what we really care about

Write code once, use in multiple situations

prototypal inheritance makes this easy

don't think about new, super, and extends

don't even think about javascript's prototype property

Prototypal inheritance is about fallbacks

How does prototypal inheritance work?


      var base = {
          firstName:"John",
          lastName:"Paul",
          getFullName:function(){
             return this.firstName + " " + this.lastName; 
          },
      }; // base is the fallback

      var obj = Object.create(base); // where the magic happens
      obj.alertName = function(){
              alert(this.getFullName());    
      };

      obj.alertName(); // John Paul

      // this is code reuse!
      alert("getFullName" in obj) //true
      alert(obj.getFullName === base.getFullName)  //true
                                                

Caveat

Not all js environments have Object.create

But we have a solution for < IE9


    Object.closeToCreate = function (o) { 
        //as close to Object.create's functionality in old IEs
        function F() {}
        F.prototype = o;
        return new F();
    };
                                                    

prototype is double speak

  • prototype #1 - property on a function
  • fallbackOfObjectsCreatedWithNew would be better
  • prototype #2 - internal reference of every object
  • ES6 now calls this dunderproto (__proto__)

Scoping: breaking the principle of least surprise


   var arr = [1,2,3];
   var out = [];
   for(var i = 0; i<arr.length;i++) {
      var item = arr[i];
      out.push(function(){ alert(item); });
   }
   
   out.forEach(function(func){ func(); });
                                                    

Only functions can create scope


   var arr = [1,2,3];
   var out = [];
   for(var i = 0; i<arr.length;i++) {
      (function(valueToAlert){
        var item = valueToAlert;
        out.push(function(){ alert(item); });
      })(arr[i]);
   }
   
   out.forEach(function(func){ func(); });
                                                    
  • Coffeescript has do keyword

ES6 adds let


   var arr = [1,2,3];
   var out = [];
   for(var i = 0; i<arr.length;i++) {
      let item = arr[i];  // block scoped 
      out.push(function(){ alert(item); });
   }
   
   out.forEach(function(func){ func(); });
                                                    

one of these is not like the other


    testFunc(); 
    var testFunc = function(){ alert("hey!"); };
                                                    

    testFunc(); 
    (function testFunc(){ alert("hey!"); });
                                                    

    testFunc();
    function testFunc(){ alert("hey!"); }; 
                                                    

How does hoisting work?


    (function(){
        var hello = "world";
        //some other code
        var expression = function(){ alert("expression!"); };
        var foo = "bar";
        function declaration(){ alert("declaration!"); }; 
    })();                                                    

    (function(){
        var foo, hello, expression;
        function declaration(){ alert("declaration!"); }; 
        hello = "world";
        //some other code
        expression = function(){ alert("expression!"); };
        foo = "bar";
    })();                                                     

    function declaration(){}

    (function expression(){
        function declaration(){}
    }())

    var expression = function(){}; // assignment expression

    var expression = function expression(){};

    (function expression(){})(); // () is the grouping operator 

    new function expression(){}; // new expression

    0, function expression(){}; // the comma is an operator

    void function expression(){}
    +function expression(){}
                                                    

Only easy rule - if there's no name, it's a expression

If there is a name, it depends on context

Takeaways

;

Javascript

The Real Bad Parts

By @johnkpaul

johnkpaul.com