Javascript for Dummies

Basic I

"use strict";

// Non-strict code...

(function(){
  "use strict";

  // Define your library strictly...
})();

// Non-strict code...

Guide here

"Can't have "with" in strict mode"

Examples

(function($) {

    "use strict";  

    //Your code using jQuery

})(jQuery);
var MyLibraryName = MyLibraryName || {};

MyLibraryName.invalidElements = (function($) {
    
    "use strict";
    
    var _nameClass = "myLibraryInvalidElement"; //Private Property

    var _getnameClass = function() { //Private Method
        // Do private stuff, or build internal.
        return _nameClass;
    };
    var _getElementsByClass = function() {
        return $("."+ _getnameClass());
    };

    return {
        version: "1.0.0", //constant
        getElementsByClass: _getElementsByClass
    };
})(jQuery);


//Extend namespace in other files...
//MyLibraryName.otherfunction = (function(){ ... })();

MyLibraryName.invalidElements.getElementsByClass()
void function(){

    "use strict";

    //Your code

};

Loops, Arrays and Objects

for (i = 0; i < users.length; i++) { 
    console.log(users[i]);
}
var person = {fname:"John", lname:"Doe", age:25};
for (var x in person) {
    console.log(x);
}
while (i < 10) {
    console.log("The number is " + i);
    i++;
}
do {
    console.log("The number is " + i);
    i++;
}
while (i < 10);

[ ]

{}

Guide here

Booleans

Falsy values

if(undefined){ // => false
if(null){      // => false
if(false){     // => false
if(0){         // => false
if(""){        // => false
if(NaN){       // => false

Truthy values

if (true)          // => true
if ({})            // => true
if ([])            // => true
if (42)            // => true
if ("foo")         // => true
if (new Date())    // => true

But...

if(new Array() == false) {   // => true
if(false == 0) {             // => true
if(false == "") {            // => true
if(0 == "") {                // => true
if("0")                      // => true
if(NaN == NaN) {             // => false            
if(undefined == null)        // => true
if(new Array() === false) {   // => false
if(false === 0) {             // => false
if(false === "") {            // => false
if(0 === "") {                // => false
if("0" === true)              // => false
if(NaN === NaN) {             // => false o.O            
if(undefined === null)        // => false

=== to the rescue

this, scope and closures

Functions

Link:  J avascript The Good Parts - Page 26

"every function receives two additional parameters: this and arguments..."

function demo(name, year){
    return arguments;
}

demo("Nicholls", 1991); // => ["Nicholls", 1991]
demo("Anonymous"); // => ["Anonymous"]


Exceptions

Link: Javascript The Good Parts - Page 32

var tryCatch = function (fn) {
    try {
        fn.apply(this, Array.prototype.slice.call(arguments, 1));
    }
    catch (ex) { /* eat please */ }
};

tryCatch(demo, "Juan", 1991); //https://gist.github.com/equisoide/de0acd127b4ecc2698eb
throw {
 name: 'TypeError',            //Type of the exception
 message: 'Horribleee human!'  //Descriptive message
 //Add more properties...
};

Code Conventions

Basic II

The bad parts

  • Global variables: subprograms that share the same name.
  • Newlines get converted into semicolons => StandardJS
  • Operator typeof is not very helpful.
  • Operator + adds numbers and concatenates.
  • Operators == and != do type coercion
function Error(){
   return
   {
      status: true
   };
}
typeof null == typeof [1,2,3]
(0.1 + 0.2) != 0.3   // => true
//Bad
"4" + 3
//Better
Number("4") + 3
parseInt("4") + 3

Reflection

Link:  J avascript The Good Parts - Page 23

typeof flight.number // 'number'
typeof flight.status // 'string'
typeof flight.arrival // 'object'
typeof flight.manifest // 'undefined'

typeof flight.toString // 'function'
typeof flight.constructor // 'function'

flight.hasOwnProperty('number') // true
flight.hasOwnProperty('constructor') // false

if (typeof(v) === "function") {
// do something
}

La reflexión es un proceso mediante el cual un programa es capaz de obtener información sobre si mismo y por tanto es capaz de auto modificarse en tiempo de ejecución.

Prototypal Inheritance

Link: Javascript The Good Parts - Page 23 and 46

//For IE...
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
var Cat = function (name, age) {
    this.name = name;
    this.age = age;
};
var Siamese = function (color, colorEyes, name, age) {
    Cat.call(this, name, age);
    this.color = color;
    this.color_eyes = colorEyes;
};

Siamese.prototype = Object.create(Cat.prototype);
Siamese.prototype.constructor = Siamese;

var cat = new Siamese("black", "green", "Little cat", 2);

Cat.prototype.run = function(){
  console.log(this.name + " is running!!");
};

cat.run(); // => "Little cat is running!!"

Regular expressions

Link: Javascript The Good Parts - Page 65

"JavaScript’s Regular Expression feature was borrowed from Perl"

//Validate Numbers
var pattern = /^\d+$/;
pattern.test("Juan")   // => false

//Validate Emails
var pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
pattern.test("john.smith@gmail.com")  // => tr4e
//But the grammar specified in RFC 5322 is too complicated for primitive regular expressions

//Validate Date (MM/DD/YYYY)/(MM-DD-YYYY)/(MM.DD.YYYY)/(MM DD YYYY)
/^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$/

//Validate HTML tag
/^<([a-z]+)([^<]+)*(?:>(.*)</1>|s+/>)$/

//Validate URL
/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/

OOP

var Fenton = (function () {
    function Customer(name) {
        this.name = name;
    }
    Customer.prototype.greet: function () {
        return this.name + ' says hi!';
    };
    function VipCustomer(name, discountPercentage) {
        Customer.call(this, name);
        this.discountPercentage = discountPercentage;
    }
    VipCustomer.prototype = new Customer();
    VipCustomer.prototype.constructor = VipCustomer;
    
    return {
        Customer: Customer,
        VipCustomer: VipCustomer
    };
}());
var steve = new Fenton.Customer('Osman');
var todd = new Fenton.VipCustomer('Jorge', 10);

"use call  to chain constructors for an object"

Basic III

jQuery Essentials

$("document").ready(function() {
    //code code code
});
$(function() {
    //code code code
});

The DOM is ready!

or

DOM Manipulation

//Selectors
$("#myinput")   // => Get element by ID
$(".myinputs")  // => Get elements by class

$("#myinput").val()                     // => get value from element
$("#myinput").val("example")            // => set value to the element
$("#elem").attr("title", "My title")    // => set an element's title attribute
$("#elem").css("color", "red")          // => set an element's text color

//Hide elements
$("#elem").hide();
$("#elem").fadeOut();
$("body").fadeOut(1000, function(){
    alert("finish hide element!");
});
//Insert HTML
$('#elem').html("<h1>Demo</h1>");
$('#elem').text("This is Sparta!");

$("#mydiv").addClass("gored");
$("#mydiv").removeClass("gored");
$("#mydiv").toggleClass("zclass");

$("<div></div>").appendTo("#myParent");
$("#myParent").prepend("<div></div>");
$("#myParent").append("<div></div>");
$("#myParent").before("<div></div>");
$("#myParent").after("<div></div>");

$("#other").load("otherpage.html");
//Find elements
$('#class-container .class')   //Modern browsers, QuerySelectorAll like CSS
$('.class', '#class-container')
$parent.find(".child")      //Better for all browsers
$parent.children();         //Direct children
$("#mydiv").animate({
    opacity: 0.25,
    left: "+=50",
    height: "toggle"
  }, 5000, function() {
// Animation complete.
});
var arr = [1, 2, 3, 4, 5, 6];
var filter = $.grep(arr, function(item, index) {  
  return item > 3; 
});
console.log(filter); // [4, 5, 6]
var arr = [1, 2, 3, 4, 5, 6];
var filter = $.map(arr, function(item, index) {  
  return item + ", position: "+ index; 
});
console.log(filter); // ["1, position: 0", "2, position: 1", ...]

The best practices

//Cache your selectors in variables
var $myinput = $("#myinput");
$myinput.css("color", "red");
$myinput.delay(2000).fadeOut(1000);

//Chaining => shorter is better! :)
$myinput.css("color", "red")
        .delay(2000)
        .fadeOut(1000);
//Append once
var girls = ["Andrea", "Yuliana", "Sorel", "Erica"];
var girlsHtml = "";
$.each(girls, function(index, value) {
    girlsHtml += "<li id=" + index + ">" + value + "</li>"
});

$list.append(girlsHtml);

Don't abuse this

$('#someAnchor').click(function() {
    // Bleh
    alert( $(this).attr('id') );
});
$('#someAnchor').click(function() {
    alert( this.id );
});
//Add multiple events at the same time
$button.on({
    "mouseenter": function() {
      $(this).text("Click me!");
    },
    "click": function() {
      $(this).text("Why did you click me?!");
    }
});

BAD

GOOD

$body.on("mouseenter", function() {
    $(this).text("Click me!");
});
$body.on("click", function() {
    $(this).text("Why did you click me?!");
});
//Event delegation with parents, just once! :)
$list.on("click", "li.myitem", function(){
   console.log("click");
});
//code code code

$list.append("<li class='myitem'>Demo</li>");
$list.append($("<li class='myitem'>Demo</li>")
              .on.("click", function(){ 
                  console.log("click");
}));
//OR
$list.append("<li class='myitem'>Demo</li>");
$(".myitem").on.("click", function(){ 
      console.log("click");
 });

AJAX

//Use json2 libray to support JSON.stringify in old browsers
$.ajax({
    url: "http://.....",
    type: "POST",
    data: JSON.stringify(data),
    contentType: "application/json", //Request json in server side
    dataType : 'json',               //Response json in browser side
    success : function(json) {
        console.log(json);
        alert("success");
    },
    error : function(xhr, status) {
        alert('Error call service');
    },
    complete : function(xhr, status) {
        alert('Finish');
    }
});
var userId = 2;
$.getJSON("/api/users?id=" + userId , function(data, status){
    alert("User Name: " + data.Name);
});
$.post( "http://myURL.com/usuario", {'nombre': 'Oscar'}, function( data, textStatus, jqxhr ) {
  alert( "Exito" );
});
$(document).ajaxError(function() {
  alert('Ajax Error');
});

Global

npm

Gulp y Grunt

var gulp = require('gulp');
var gutil = require('gulp-util');
var concat = require('gulp-concat');
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');

var paths = {
  sass: ['./scss/**/*.scss'],
  controllers: ['./www/js/controllers/*.js'],
  directives: ['./www/js/directives/*.js'],
  services: ['./www/js/services/*.js']
};
 
gulp.task('default', ['sass', 'controllers', 'directives', 'services']);
gulp.task('controllers', function() {
    return gulp.src(paths.controllers)
        .pipe(concat("controllers.js"))
        .pipe(gulp.dest("./www/js/"))
        .pipe(rename('controllers.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest("./www/js/"));
});
gulp.task('watch', function() {
  gulp.watch(paths.sass, ['sass']);
  gulp.watch(paths.controllers, ['controllers']);
  gulp.watch(paths.directives, ['directives']);
  gulp.watch(paths.services, ['services']);
});

Example with Ionic Framework here

ECMAScript 6

ECMAscript 6 is the next generation JavaScript standard, and the first update to the language since ES5 was standardized in 2009...

Let + Const

function f() {
  {
    let x;
    {
      // okay, block scoped name
      const x = "sneaky";
      // error, const
      x = "foo";
    }
    // error, already declared in block
    let x = "inner";
  }
}

Arrows

They support both expression and statement bodies

var evens = [1, 2, 3, 4, 5];
var nums = evens.map((v, i) => v + i);
console.log(nums); // [1,3,5,7,9]

var fives = [];
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});
console.log(fives); // [5]

var nicholls = {
  _name: "Nicholls",
  _friends: ["Andrea", "Osman", "Silva"],
  printFriends() {
    var exit = [];
    this._friends.forEach(f =>
      exit.push(this._name + " knows " + f));
      console.log(exit);
  }
}
let x = [0,1,2];
x.map(x => console.log(x * x)); //arrow function
var x = [0,1,2];
x.map(function (x) { //anonymous function
  console.log(x * x);
});

Classes

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    //call the parent constructor with super
    super(geometry, materials); 

    //...
  }
  update(camera) {
    //...
    //call the parent method with super
    super.update();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}

are a simple sugar over the prototype-based OO pattern

// Superclass
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    describe() {
        return 'Person called ' + this.name;
    }
    get getYears() {
        return this.age;
    }
    set increaseAge() {
        this.age++;
    }
}

// Subclass
class Employee extends Person {
    constructor(name, age, title) {
        super(name, age); 
        this.title = title;
    }
    describe() {
        return super.describe() + ' (' + this.title + ')';
    }
}

Arrows + Classes

function Car() {
  var self = this; //locally assign this
  self.speed = 0;

  setInterval(function goFaster() {
    //this has a different scope
    self.speed += 5;
      console.log('now going: ' + self.speed);
  }, 1000);
}

var car = new Car();
function Car() {
  this.speed = 0;

  setInterval(() => {
    this.speed += 5; //this is from Car
    console.log
    console.log('now going: ' + this.speed);
  }, 1000);
}

Template Strings

//Create string
`In ES5 "\n" is a line-feed.` // "In ES5 \"\n\" is a line-feed.";

// Multiline strings
`In ES5 this is
 not legal.`

var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?` //Hello Bob, how are you today?

provide syntactic sugar for constructing strings

function renderPerson(person) { return `
<dl>
  <dt>First</dt> <dd>${person.first}</dd>
  <dt>Last</dt> <dd>${person.last}</dd>
</dl>  
`;}

renderPerson({first: 'Brian', last: 'Genisio'});

Default + Rest + Spread

function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined)
  return x + y;
}
console.log(f(3) == 15) // true
function f(x, ...y) {
  // y is an Array
  return x * y.length;
}

console.log(f(3, "hello", true) == 6)
function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
console.log(f(...[1,2,3]) == 6); // true

Modules

 // lib.js
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
// main.js
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));

Promises

var p1 = new Promise((resolve, reject) => setTimeout(resolve, 400, "one"));
var p2 = new Promise((resolve, reject) => setTimeout(resolve, 200, "two"));
Promise.race([p1, p2]).then(function(value) {
    console.log(value); //two
});
var p1 = new Promise((resolve, reject) => setTimeout(resolve, 400, "one"));
var p2 = new Promise((resolve, reject) => setTimeout(resolve, 200, "two"));
Promise.all([p1, p2]).then(function(value) {
    console.log(value); //one, two
});
function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

Architecture I

Promises

Deferred object controls operation

step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4 
            });
        });
    });
});
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
    // Do something with value4 
})
.catch(function (error) {
    // Handle any error from all above steps 
})
.done();

Q

Method Invocation Pattern

Link: Javascript The Good Parts - Page 27

var myObject = {
 value: 0,
 increment: function (inc) {
 this.value += typeof inc === 'number' ? inc : 1;
 }
};
myObject.increment( );
document.writeln(myObject.value); // 1

myObject.increment(2);
document.writeln(myObject.value); // 3

When a function is stored as a property of an object, we call it a method...

A method can use this to access the object so that it can retrieve values from the object or modify the object

Function Invocation Pattern

Link: Javascript The Good Parts - Page 28

// Augment myObject with a double method.
myObject.double = function ( ) {

 var that = this; // Workaround.

 var helper = function ( ) {
     that.value = add(that.value, that.value);
 };
 helper( ); // Invoke helper as a function.

};

// Invoke double as a method.
myObject.double( );
document.writeln(myObject.getValue( )); // 6

When a function is not the property of an object, then it is invoked as a function...

Constructor Invocation Pattern

Link: Javascript The Good Parts - Page 29

// Create a constructor function called Quo.
// It makes an object with a status property.
var Quo = function (string) {
 this.status = string;
};
// Give all instances of Quo a public method
// called get_status.
Quo.prototype.get_status = function ( ) {
 return this.status;
};
// Make an instance of Quo.
var myQuo = new Quo("confused");
document.writeln(myQuo.get_status( )); // confused

Functions that are intended to be used with the new prefix are called constructors

Apply Invocation Pattern

Link: Javascript The Good Parts - Page 30

// Make an array of 2 numbers and add them.
var array = [3, 4];
var add = function(x, y){
    return x + y;
};
var sum = add.apply(null, array); // sum is 7

// Make an object with a status member.
var statusObject = {
 status: 'A-OK'
};

// statusObject does not inherit from Quo.prototype,
// but we can invoke the get_status method on
// statusObject even though statusObject does not have
// a get_status method.
var status = Quo.prototype.get_status.apply(statusObject);
 // status is 'A-OK

The apply method lets us construct an array of arguments to use to invoke a function.

It also lets us choose the value of this.

The apply method takes two parameters.


The first is the value that should be bound to this. The second is an array of
parameters.

The Module Pattern

var awesomeNewModule = (function(){

    var exports = {
        foo: 5
    };

    exports.helloPeople = function(){
        console.log("Hello guys!");
    };

    return exports;

}());
var awesomeNewModule.sub = (function(exports){

    exports.foo = 5;

    exports.helloPeople = function(){
        console.log("Hello guys!");
    };

    return exports;

}(awesomeNewModule.sub || {}));
//File1.js
var awesomeNewModule = awesomeNewModule || {};
awesomeNewModule.sub = (function(exports){

    exports.foo = 5;

    exports.helloPeople = function(){
        console.log("Hello guys!");
    };

    return exports;

})(awesomeNewModule.sub || {});
//File2.js
var awesomeNewModule = awesomeNewModule || {};
awesomeNewModule.sub = (function(exports){

    exports.bla = 10;

    exports.goodbyePeople = function(){
        console.log("Bye bye guys!");
    };

    return exports;

})(awesomeNewModule.sub || {});
awesomeNewModule.sub.helloPeople();
awesomeNewModule.sub.goodbyePeople();
var App = App || {};
App.Models = (function(response){

    response.User.prototype.jump = function(){
        console.log(this.name + " is jumping!");
    };

    return response;
})(App.Models || {});

Extension of my library

var App = App || {};
App.Models = (function(response){
     
    response.User = function(name){
        this.name = name;
    };

    response.User.prototype.run = function(){
        console.log(this.name + " is running!");
    };

    return response;
})(App.Models || {});

My library

Architecture II

Constructor

Module

Singleton

Observer

Prototype

Facade

Architecture III

MVC patterns

used for structuring desktop and server-side applications...

JavaScript MV* Patterns

MVC

MVC is an architectural design pattern that encourages improved application organization through a separation of concerns.

  • Models: the isolation of business data.
  • Views: user interfaces.
  • Controllers: traditionally managing logic and user-input

JavaScript now has a number of frameworks boasting support for MVC (or variations on it, which we refer to as the MV* family), allowing developers to easily add structure to their applications without great effort.

Backbone, Ember.js and AngularJS

"spaghetti" code:

A term which describes code that is very difficult to read or maintain due to its lack of structure.

Models

Manage the data for an application.

They represent unique forms of data that an application may require.

Represents a unique kind of domain-specific data. Such a model may contain related attributes

it is quite common for them to support validation of attributes

Views

Views are a visual representation of models that present a filtered view of their current state.

A view typically observes a model and is notified when the model changes

The benefit of this architecture is that each component plays its own separate role in making the application function as needed.

Controllers

Controllers are an intermediary between models and views which are classically responsible for updating the model when the user manipulates the view.

You Rock!

JavaScript Course

By J.D Nicholls

JavaScript Course

A course about JavaScript

  • 4,751