L33t J4v45cr1pt H4x

seriously though, just some cool info. no h4x involved.

agenda

  • a very brief history of jstime
  • javascript in html
  • syntax
  • lesser-known things
  • prototypal inheritance
  • closures
  • "this" and "that" and .bind();
  • .. also call and apply
  • modular design pattern
  • events

very brief history

  • developed by Brandon Eich at Netscape
  • he designed the language in ten days
  • built to be a lightweight complement to java applets that would appeal to amateur programmers
  • massively uncertain beginnings, almost derailed completely by some terrible language decisions
  • language likely saved by other, more excellent, decisions
  • now arguably the most important language on the web.

javascript in html

<html>
    <head>
        <!-- typical way to load -->
        <script src="js/lib0.js"></script>

        <!-- new async attr -->
        <script async src="js/lib1.js"></script>

        <!-- new defer attr -->
        <script defer src="js/lib2.js"></script>
    </head>
    <body>
        <main class="main">
        <!-- WEBSITE -->
        </main>

        <!-- browser-friendly way to load -->        
        <script src="js/lib3.js"></script>
    </body>
</html>
  • content >>> javascript
  • blocks downloading and parsing of html
  • user-perceived latency

javascript in html

html parsing

script downloading

script execution

html parsing paused

normal <script> 

<script async>

<script defer>

javascript in html

alternate method: use js to load js asynchronously

var head = document.getElementsByTagName('head')[0],
    script = document.createElement('script');

script.src = url;
head.appendChild(script);

problem: no way to dictate order, find dependencies.

    solution: REQUIRE.js

// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function   ($,        canvas,   sub) {
    //jQuery, canvas and the app/sub module are all
    //loaded and can be used here now.
});

javascript in html

further performance enhancements

  • use a cdn. location-based content delivery and multiple domains means maximizing parallel downloads and minimizing latency
  • jslint/jshint everything. your code will be better and faster (and it will teach you a lot)
  • minify your code 
  • gzip compress your code

syntax

simple things: EQUALITY

=== operator

syntax

simple things: EQUALITY

long story short, use the === operator. == opens up your code to unintended side-effects.

syntax

simple things

=== operator

function baz() {
    var foo = "hello"
    var bar = "world"
    
    return 
    {
        one: foo,
        two: bar
    }
}

baz(); // "undefined"

javascript will allow you to omit semicolons. do not do this.

syntax

method signatures

=== operator

// initial definition of foo
function foo(one) {
    console.log(one);
}

// this overrides foo. old foo no longer exists.
function foo(one, two) {
    console.log(one + " " + two);
}


foo(); // "undefined undefined"
foo("hello"); // "hello undefined"
foo("hello", "world"); // "hello world"
foo("Goodbye", "cruel", "world"); // "Goodbye cruel"

// each function is passed an "arguments" object into its
// context, giving you access to each parameter that
// a function is called with

in other languages, varying parameters means different methods. not so in javascript.

syntax

logic h4x

=== operator

// logical operators can be used to set variables

function test(foo) {
    // adding in false for example. foo will
    // be foo or a brand new object.
    foo = foo || false || {};
} 

syntax

constructor convention

=== operator

function Foo() {
    this.bar = "Hello";
    this.baz = "World!";
}

this function is a constructor. you can tell because the first letter is capitalized. more on this later.

syntax

alternate for loop

var obj = {
    foo: "Hello",
    bar: "World",
    baz: "Cheeseburgers"
};

for (var i in obj) {
    console.log(obj[i]);  
}

// "Hello"
// "World"
// "Cheeseburgers"

// interesting note: Arrays.
var arr = ["zero", "one", "two", "three", "four", "five"];

for(var i in arr) {
    console.log(i);
}

// 0
// 1
// 2
// 3
// 4 
// 5

syntax

callbacks

function iterateOverBoard(fn) {
    for(var i = 0;i < spec.size;i++) {
        for(var j = 0; j < spec.size;j++) {
            if (fn(board[j][i], j, i) === false) {
                break;
            }
        }
    }
}

// jsperf indicates Array.join is faster than + operator.
// so, some people do this.
iterateOverBoard(function (val, x, y) {
    console.log(["element at (", x, ",", y, ") contains value", val].join());
});

lesser-known things

function-level scope (vs block scope)

var x = 1;
console.log(x); // 1
if (true) {
	var x = 2;
	console.log(x); // 2
}
console.log(x); // 2

var foo = 1;
function bar() {
	if (!foo) {
		var foo = 10;
	}
	alert(foo);
}
bar(); // alerts 10


var a = 1;
function b() {
	a = 10;
	return;
	function a() {}
}
b();
alert(a); // alerts 1

lesser-known things

hoisting


var test = function () {
    // instantiation of x. itself, a valid 
    // statement in js, but would cause x
    // to become a global variable.
    x = "Hello";

    console.log(x);

    // declaration of x gets hoisted
    // to the top of the function, 
    // preventing x from becoming global.
    var x;
};

var test2 = function () {
    foo(); // "foo";
    bar(); // TypeError: undefined is not a function

    // function declaration is hoisted
    function foo() {
        console.log("foo");
    }

    // variable initialization does not get hoisted
    var bar = function () {
        console.log("bar");
    };
};


test(); // "Hello"
console.log(x); // "undefined"

lesser-known things

dom rendering potential issues

function expensiveOperation() {
    // don't try this at home.
    for(var i = 0;i < 10000000;i++) {
        document.body.appendChild(document.createElement("div"));
    }
}

function methodThatDependsOnOperationSuccess() {
    return document.getElementsByTagName("div").length;
}

expensiveOperation();
methodThatDependsOnOperationSuccess(); // has a chance of failure

// alternative:
expensiveOperation();
setTimeout(methodThatDependsOnOperationSuccess, 0);

most people are like "let's just give it some time", and set setTimeout's time to like half a second. this misses the point entirely.

prototypal inheritance

objects from objects, not from types

  • objects are essentially just property bags
  • each object has an internal  'prototype' property which is a reference to its parent object
  • if you try to access a property on an object, it ask its prototype if it has it
  • this process continues until Object.prototype is hit

prototypal inheritance

forms of object creation

// initial capital letter means this function is a prototype
function Foo () {
    function bar() {
        console.log(bar);
    }

    this.test = "Hello";
}

// invoke Function with the "new" keyword, and it runs the
// function in the context of a new object you're creating.
// otherwise, it runs globally. 
new Foo();

// WARNING, DO NOT CALL FOO (EVEN THOUGH IT'S A FUNCTION)
// doing so will glom all instance methods/properties to the 
// window (more on this later).

Foo();
console.log(test); //"Hello"

prototypal inheritance

forms of object creation (part deux)

// Crockfordian abstraction
Object.prototype.begetObject = function () {
    function F() {}
    F.prototype = this;
    return new F();
};

var a = [];

// new object b, whose properties inherit 
// from object a, is an array.
var b = a.begetObject();

// Alternate syntax using the "New" keyword.
// note the first letter in "Foo" is capitalized.
function Foo () {
    this.a = "hello";
    this.b = "world";
}

new Foo(); // correct
Foo(); // oops, all of your variables now exist globally.


// newer form of object instantiation. IE9+
Object.create([prototype], [properties list]);

closures

the most popular interview question ever, simplified.

// not a closure
setInterval(function () {
    console.log("Test", 500);
});

// almost a closure
function test (word) {
    return function () {
        return "Cheese.";
    }
}

// yay closures
function test (word) {
    return function () {
        return word;
    }
}

function test (word) {
    return {
        foo: word
    };
}

"this" and "that" and "bind"

perhaps the most confusing part of js

// in every function invocation, "this" is set
// to the object before the function.
// e.g., in a.test() below, "this" would be a.
// for foo(), this would be the window.

function foo() {
    console.log(this.bar + " " + this.baz);
}

var a = {
    bar: "Hello",
    baz: "World",
    test: function () {
        return this.bar + " " + this.baz;
    }
};

foo(); // "undefined undefined"

// bind returns a function with 
// the passed-parameter set as the
// context. you have the option
// of immediately executing it.
foo.bind(a)(); // "Hello World"


// a common pattern is to store a reference
// to the current "this" for various method calls.
// this would seem very odd to a classical programmer.
var test = { 
    baz: function() {
        var that = this;
    
        function test() {
            console.log(this);
            console.log(that);
        }

        test();    
    }
};

test.baz(); 
/* window
   test */

"this" and "that" and "bind"

asynchronous method calls

var test = { 
    baz: function() {
        var that = this;

        setTimeout(function () {
            // closure! outputs test object
            console.log(that);
    
            // outputs "window"
            console.log(this);
        }, 500);
    }
};

... also call() and apply()

more context switching

// call() and apply() are methods on function. 
// call takes a series of parameters, apply takes an array.
// in both functions, the first parameter is the this 
// of the function.

function test(foo, bar, baz) {
    console.log(foo + " " + bar + " " + baz);
}

test.call(this, "hello", "world", "cheeseburgers");
test.apply(this, ["hello", "world", "cheeseburgers"]);


module design pattern

some structure to your code

// this pattern allows you to encapsulate logic,
// separate concerns across modules, split modules
// into separate files without wholesale overriding 
// the module, use private methods, limit your global
// object footprint.
//
// all of these are good things

var MODULE = (function () {
	var my = {},
		privateVariable = 1;

	function privateMethod() {
		// ...
	}

	my.moduleProperty = 1;
	my.moduleMethod = function () {
            // oh look, more closures!
            privateVariable++;
            privateMethod();
	};

	return my;
}());


(function ($, window) {
	// now have access to globals jQuery (as $) and window in this code
}(jQuery, window));

events

process

events

event bottlenecking

<html>
<head></head>
<body>
    <table>
        <tbody>
            <tr>
                <td>Column 1</td>
                <td>Column 2</td>
            </tr>
            .
            .
            .
            <!-- 100,000 rows later.. -->
            <tr>
                <td>Column 1</td>
                <td>Column 2</td>
            </tr>
        <tbody>
    </table>
</body>
</html>

events

event delegation (with jquery)

// typical event handling
$("#myTable tr").on("click", function (ev) {
    console.log("myTable row clicked!");
    ev.preventDefault();
    ev.stopPropagation();
});


// event delegation
$("#myTable").on("click", "tr", function (ev) {
    console.log("myTable row clicked!");
    ev.preventDefault();
    ev.stopPropagation();
});


// event delegation on the body
// (otherwise known as .live(), which
// is a deprecated method now
$("body").on("click", "#myTable tr", function (ev) {
    console.log("myTable row clicked!");
    ev.preventDefault();
    ev.stopPropagation();
});

that's it

those are the things I wanted to cover

var x = ({a:function(c){this.b.push(c);return c?this.a(--c):this.b;},b:[]}.a(~+!"">>>+!""));

bonus points: what is a?

JavaScript

By Ben Sterrett

JavaScript

  • 571