JavaScript in-depth

Erick Mendoza

Why JS?

Complex web apps




 "...There isn't any point to diving into new technologies, or using the hottest libraries, if you don't have a proper understanding of the fundamental characteristics of the JavaScript language"

-John Resig, Secrets of the JavaScript Ninja




In short: beware of JS script kiddies

1. So, JavaScript will be relevant forever. 
2. JavaScript lives in other environments outside of browsers (Windows 8, Node Js, Firefox Os, GNOME)

You can program hardware in JavaScript tessel.io



Summary

Javascript enlightment:

* Language Background * Syntax * Primitive values * JavaScript Objects * Function() * Scopes, Environments, Hoisting and Closures * Promises * Functional programming

Additional:

* JSHint * Devtools Debugger

Not covered:

* Frameworks (AngularJS, Backbone, etc) * Modern front-end development tools (grunt, node, requireJS, bower, etc.) * DOM manipulation * High performance applications

COnsole up!


DevTools

Firebug

Node CLI

Assumptions:


  • You already know how to program
  • You already know (at least) OOP
  • You have a slight idea of what JavaScript is for

Background







JavaScript Versus ECMAScript




JavaScript means the programming language.


ECMAScript is the name used by the language specification



* BTW WE'LL TALK ONLY about ECMASCRIPT 5


Brendan eich's influences:



  • Java (syntax, primitive values versus objects)
  • Scheme and AWK (first-class functions)
  • Self (prototypal inheritance)
  •  Perl and Python (strings, arrays, and regular expressions)

Syntax


// Two slashes start single-line comments

var x;  // declaring a variable

x = 3 + y;  // assigning a value to the variable `x`

foo(x, y);  // calling function `foo` with parameters `x` and `y`
obj.bar(3);  // calling method `bar` of object `obj`

// A conditional statement
if (x === 0) {  // Is `x` equal to zero?
    x = 123;
}

// Defining function `baz` with parameters `a` and `b`
function baz(a, b) {
    return a + b;
}

Identifiers and Variable Names


The first character of an identifier can be any Unicode letter, a dollar sign ($), or an underscore (_). Subsequent characters can additionally be any Unicode digit. Thus, the following are all legal identifiers:

arg0
_tmp
$elem
π


Statement vs Expressions


Statements “do things” 
if (condition) {

} 

Expressions produce values

3 + 4 

Primitive values




  • Booleans: true, false 
  • Numbers: 1736, 1.351
  • Strings: 'abc', "abc"
  • Two “nonvalues”: undefined, null (see undefined and null)

Primitives have the following characteristics:



Compared by value

The “content” is compared:
> 3 === 3
true
> 'abc' === 'abc'
true 


ALWAYS IMMUTABLE


Properties can’t be changed, added, or removed:

 > var str = 'abc';

> str.length = 1; // try to change property `length`
> str.length      // ⇒ no effect
3

> str.foo = 3; // try to create property `foo`
> str.foo      // ⇒ no effect, unknown property
undefined

Objects

All nonprimitive values are objects. The most common kinds of objects are:


Plain objects

{
    firstName: 'Jane',
    lastName: 'Doe'
}

Arrays

[ 'apple', 'banana', 'cherry' ] 

Regular expressions

/^a+b+$/



Compared by reference


Identities are compared; every value has its own identity:

> {} === {}  // TWO DIFFERENT EMPTY OBJECTSFALSE
> VAR OBJ1 = {};> VAR OBJ2 = OBJ1;> OBJ1 === OBJ2TRUE


MUTABLE BY DEFAULT



You can normally freely change, add, and remove properties:


> VAR OBJ = {};
> OBJ.FOO = 123; // ADD PROPERTY `FOO`
> OBJ.FOO
123 

Object literal vs constructors



var arr = [1, 2, 3]; //Literal notation

var arr2 = new Array(); //Using contructors
arr2.push(1); 
arr2.push(2);
arr2.push(3); 

undefined and null


 Uninitialized variables are undefined
Missing parameters are undefined
If you read a nonexistent property, you get undefined

...and null


null means “no object.” It is used as a nonvalue whenever an object is expected (parameters, last in a chain of objects, etc.).

Truty and faLsy


The following values are interpreted as false:


  • undefined, null
  • Boolean: false
  • Number: -0, NaN
  • String: ''


i.e. everything else is truty

Type Coercion


Type coercion means the implicit conversion of a value of one type to a value of another type. 


> '3' * '4'
12 

 > 3 + ' times'
'3 times'

Functions for Converting to Boolean, Number, String, and Object



Boolean()
Number()
String()

More stuff


Binary logic operators: &&, ||


Equality operators: ==, ===

Primitives borrow their methods from wrappers:

String methods: split, join, toLowerCase, etc

Function()


Function declaration
function add(param1, param2) {
    return param1 + param2;
}
 


Function expression
var add = function (param1, param2) {
    return param1 + param2;
}; 

Variables Are Function-Scoped


The scope of a variable is always the complete function (as opposed to the current block). For example:

function foo() {
    var x = -512;
    if (x < 0) {  // (1)
        var tmp = -x;
        ...
    }
    console.log(tmp);  // 512
}

Closures

Each function stays connected to the variables of the functions that surround it, even after it leaves the scope in which it was created. For example:


 function createIncrementor(start) {
    return function () {  // (1)
        start++;
        return start;
    }
}


uh?



> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8 

The IIFE



(function () {  // open IIFE
    var tmp = ...;  // not a global variable
}());  // close IIFE 

Useful to:

  • Auto-execute a function
  • Introducing a New Scope
  • Avoid inadvertent sharing via closures

Constructors: Factories for Objects


// Set up instance data
function Point(x, y) {
    this.x = x;
    this.y = y;
}
// Methods
Point.prototype.dist = function () {
    return Math.sqrt(this.x*this.x + this.y*this.y);
}; 

> var p = new Point(3, 5);
> p.x
3
> p.dist()
5.830951894845301 

The Prototype Relationship Between Objects


The prototype relationship between two objects is about inheritance: every object can have another object as its prototype.

Prototype chain


var PersonProto = {
    describe: function () {
        return 'Person named '+this.name;
    }
};
var jane = {
    [[Prototype]]: PersonProto,
    name: 'Jane'
};
var tarzan = {
    [[Prototype]]: PersonProto,
    name: 'Tarzan'
}; 

[[Prototype]] is an invented syntax. In some engines you can use __proto__ (“dunder proto")

> jane.describe()
Person named Jane
> tarzan.describe()
Person named Tarzan 



Constructors—Factories for Instances


function Person(name) {
    this.name = name;
} 

Person.prototype.describe = function () {
    return 'Person named '+this.name;
};


> var jane = new Person('Jane');
> jane.describe()
'Person named Jane' 

OOP?


“Object-oriented programming is an exceptionally bad idea which could only have originated in California.” — Edsger Dijkstra

“object-oriented design is the roman numerals of computing.” — Rob Pike

“The phrase "object-oriented” means a lot of things. Half are obvious, and the other half are mistakes.“ — Paul Graham

Class-oriented 00 vs. Prototypal OO


http://ericleads.com/2013/06/classical-inheritance-is-obsolete-how-to-think-in-prototypal-oo/


Promises!



CALLBACK HELL


var results = doThis(function(data) {
      doThat(data, function(data2) {
          mungeNumbers(data2, function(data3) {
              hideTracks(data3, function(data4) {
                  boostProfits(data4, function(data5) {
                      // On, and on, and on and on...
                  })
              })
          })
      })
  })  

PromiseS


 var promise = new Promise(function(resolve, reject) {
  resolve(1);
});

promise.then(function(val) {
  console.log(val); // 1
  return val + 2;
}).then(function(val) {
  console.log(val); // 3
}); 

Functional programming



IDENTIFICATION DIVISION. 
   PROGRAM-ID. chgmaker.
   DATE-WRITTEN.   1/28/2013. 
  *       AUTHOR    Dr_Legacy
  *       REMARKS   reddit dailyprogrammer challenge #119
   ENVIRONMENT DIVISION. 
   CONFIGURATION SECTION. 
   INPUT-OUTPUT SECTION. 
   FILE-CONTROL. 
   DATA DIVISION. 
   FILE SECTION. 
   WORKING-STORAGE SECTION. 
   01 AMOUNT-IN                        PIC X(10).
   01 NFRAC                            PIC X(5).
   01 NFRAC9 REDEFINES NFRAC           PIC 9(5).
   01 N1                               PIC X(10). 
   01 N2                               PIC X(10) VALUE ZEROS. 
   01 N29 REDEFINES N2                 PIC 9(10).
   01 CHARCOUNT                        PIC 99    VALUE ZERO. 
   01 CC2                              PIC 99    VALUE ZERO. 
   01 AMOUNT-WORKING                   PIC 9(11)V99.
   01 QUARTER-VALUE                    PIC 9V99  VALUE 0.25.
   01 DIME-VALUE                       PIC 9V99  VALUE 0.10.
   01 NICKEL-VALUE                     PIC 9V99  VALUE 0.05.  
   01 PENNY-VALUE                      PIC 9V99  VALUE 0.01.
   01 QUARTER-COUNT                    PIC 9(11) VALUE ZERO.
   01 DIME-COUNT                       PIC 9     VALUE ZERO.
   01 NICKEL-COUNT                     PIC 9     VALUE ZERO.  
   01 PENNY-COUNT                      PIC 9     VALUE ZERO.
   01 AMOUNT-OUT                       PIC Z(10)9.
 *****
   PROCEDURE DIVISION.
 *****
   MAIN-LOGIC SECTION. 
   MAIN-BEGIN. 
       DISPLAY  "CHANGE MAKING PROGRAM".
       DISPLAY "ENTER AMOUNT".
       ACCEPT AMOUNT-IN.
       IF AMOUNT-IN EQUAL SPACE THEN
          GO TO EXIT-PROGRAM.
 ***   old COBOL doesn't have any really fancy string functions 
       UNSTRING AMOUNT-IN
         DELIMITED BY ALL SPACES
                       OR "."
         INTO N1, NFRAC.           
       INSPECT NFRAC REPLACING ALL SPACE BY ZERO.   
       COMPUTE AMOUNT-WORKING ROUNDED = NFRAC9 / 100000 .           
       IF N1 NOT EQUAL SPACE THEN
         PERFORM VARYING CHARCOUNT FROM 10 BY -1
           UNTIL N1(CHARCOUNT:1) NOT = SPACE
 ***     reference modification. YOU KIDS HAVE IT EASY I TELL YOU 
         END-PERFORM             
         COMPUTE CC2 = 10 - CHARCOUNT + 1
         STRING N1(1:CHARCOUNT) DELIMITED SIZE INTO N2 
           POINTER CC2
         ADD AMOUNT-WORKING N29 GIVING AMOUNT-WORKING             
         .
       DISPLAY "".
       DIVIDE AMOUNT-WORKING BY QUARTER-VALUE
         GIVING QUARTER-COUNT
         REMAINDER AMOUNT-WORKING.           
       IF QUARTER-COUNT IS GREATER THAN ZERO
         MOVE QUARTER-COUNT TO AMOUNT-OUT
         DISPLAY "QUARTERS: " AMOUNT-OUT.
       DIVIDE AMOUNT-WORKING BY DIME-VALUE
         GIVING DIME-COUNT
         REMAINDER AMOUNT-WORKING.
       IF DIME-COUNT IS GREATER THAN ZERO
         MOVE DIME-COUNT TO AMOUNT-OUT
         DISPLAY "DIMES: " AMOUNT-OUT.
       DIVIDE AMOUNT-WORKING BY NICKEL-VALUE
         GIVING NICKEL-COUNT
         REMAINDER AMOUNT-WORKING.
       IF NICKEL-COUNT IS GREATER THAN ZERO
         MOVE NICKEL-COUNT TO AMOUNT-OUT
         DISPLAY "NICKELS: " AMOUNT-OUT.
       DIVIDE AMOUNT-WORKING BY PENNY-VALUE
         GIVING PENNY-COUNT
         REMAINDER AMOUNT-WORKING.
       IF PENNY-COUNT IS GREATER THAN ZERO
         MOVE PENNY-COUNT TO AMOUNT-OUT
         DISPLAY "PENNIES: " AMOUNT-OUT.
       IF AMOUNT-WORKING IS GREATER THAN ZERO
         DISPLAY "wtf ".
   MAIN-END-PROGRAM. 
       GO TO EXIT-PROGRAM.
   MAIN-EXIT. 
       EXIT. 
  / 
   DRLEGACY-MISC SECTION.
   EXIT-PROGRAM.
       EXIT PROGRAM. 

...



function coins(amount) {
    return [25, 10, 5, 1].map(function(coin) {
        return [~~(amount / coin), amount %= coin][0];
    });
} 

Recommended readings



"JavaScript Enlightment",  Cody Lindley.  (http://www.javascriptenlightenment.com)

"Secrets of the JavaScript Ninja",  John Resig and Bear Bibeault

"Speaking JavaScript",  Axel Rauschmayer. (http://speakingjs.com/es5/)

JavaScript in-depth

By Erick Mendoza

JavaScript in-depth

  • 1,994