You are on page 1of 25

How JavaScript Works

-- Miško Hevery
Basic Concepts

Object === Hash


Object, Array, String, Number, Function, null, undefined

JavaScript is a functional language


Functions are first class citizens
Role of Closures

JavaScript does not define any OO notions


Classes / Inheritance
OO conventions

Browser API
global window
Follow on your computer

Open your favorite browser and follow along in the debugger


console (not possible in IE)
Object === Hash

Everything is an object, and an object is just a hashmap

var obj1 = new Object();


var obj2 = {};

typeof obj1 ==> "object"


obj1 instanceof Object ==> true
obj1.constructor ==> Object

obj1.name = "JavaScript";
obj1["name"] ==> "JavaScript"
Object prototype chains

var vehicle = { powered: true };


var volvo = { seats: 4 };

volvo.seats ==> 4
volvo.powered ==> undefined

volvo.__proto__ = vehicle;
volvo.powered ==> true

volvo.powered = 'gasoline';
volvo.powered ==> 'gasoline'
vehicle.powered ==> true
volvo.__proto__.powered ==> true
Defining Functions

function add(a, b) { return a + b; }


var negate = function(a) { return -a; };
add(1, 2) ==> 3
add.apply(null, [1, 2]) ==> 3
add.call(null, 1, 2) ==> 3
typeof add ==> 'function'
add.name ==> 'add'
add.length ==> 2
negate.name ==> ''
typeof add.apply ==> 'function'
negate.constructor ==> Function
var negate2 = new Function('a', 'return -a;');
Function Closure

function greeter(salutation) {
var counter = 0;
var prefix = '. ' +salutation + ' ';
return function(name) {
counter ++;
return counter + prefix + name + '!';
};
}
var greet = greeter('Hello');
greet('World') ==> '1. Hello World!'
greet('World') ==> '2. Hello World!'
Creating a Class

There is no standard "class" it is just a convention!


var circle = {};
circle.radius = 5;
circle.area = function(){
return this.radius * this.radius * Math.PI;
};
circle.area() ==> 78.5398
var fn = circle.area;
fn.call() ==> NaN;
window.radius = 1;
fn.call() ==> 3.1415
fn.call(circle) ==> 78.5375
Separating instance from Class

var Circle = {
area: function(){
return this.radius * this.radius * Math.PI;
}
};

var instance = { radius:5 };


instance.__proto__ = Circle;

instance.area() ==> 78.5398


Constructor

function Circle(radius) {
this.radius = radius;
this.area = function(){
return this.radius * this.radius * Math.PI;
};
}
var instance = {};
Circle.call(instance, 5);
instance.area() ==> 78.5398
var instance2 = new Circle(5);
instance2.area() ==> 78.5398
instance instanceof Circle ==> false
instance2 instanceof Circle ==> true
new Operator

function Class(){}

var instance1 = new Class();

var instance2 = {};


instance2.constructor = Class;
instance2.__proto__ = Class.prototype;
Class.apply(instance2);

instance[1|2].constructor == Class
instance[1|2].__proto__ == Class.prototype
instance[1|2] instanceof Class == true
Function constructor prototype

function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function() {
return this.radius * this.radius * Math.PI;
};

var instance = new Circle(5);


instance.area() ==> 78.5375

instance.constructor == Circle
instance.__proto__ == Circle.prototype
instance instanceof Circle == true
Function binding problem

function Greeter(s){this.salutation = s;}


Greeter.prototype.greet = function(name){
alert(this.salutation + name);
}
var greeter = new Greeter();
var server = new Server();

server.getUser(greeter.greet);
// greet function called with wrong 'this'

server.getUser(function(name){
greeter.greet(name);
});
Function Binding

function bind(fnThis, fn) {


return function(){
return fn.apply(fnThis, arguments);
};
}

server.getUser(bind(greeter, greeter.greet));
Extending Types

var text = 'Hello';


typeof text ==> 'string'
text.__proto__ ==> String.prototype
text.reverse ==> undefined

String.prototype.reverse = function(){
var text = '';
for(var i=0; i < this.length; i++)
text = this.charAt(i) + text;
return text;
}

text.reverse() ==> 'olleH';


Array iteration

var log = '';


var array = ['car', 'book', 'table'];
// ??? {length:3, 0:'car', 1:'book', 2:'table}

for(var i=0; i < array.length; i++) {


log += log[i] + ';';
}
log ==> 'car;book;table;'

log = '';
for(var i in array) {
log += i + ':' + array[i] + ';';
}
log ==> '0:car;1:book;2:table;'
Object iteration

var log = '';


var spanish = {
house:'casa',
hello:'hola'
};

for(var key in spanish) {


log += key + '=>' + spanish[key] + '; ';
}

log ==> 'house=>casa; hello=>hola; '


Global window

var name = 'World';


window.name ==> 'World';

function greet(){
var salutation = 'Hello';
message = salutation + ' ' + name;
}

window.greet();
window.salutation = undefined;
window.message ==> 'Hello World';
Asynchronous API

var xhr = ...;


xhr.request('GET', '/url', function(data){
alert(data);
});

// Pseudo Code
while(true) {
var event = waitForEvent();
try{
event();
} catch(e) {}
redrawDOM();
}
DOM

Parsed representation of the HTML is DOM


Changing the DOM programatically changes the view
DOM is declarative

var body = window.document.body;


body.innerHTML = '<b>Hello <i>World</i>!</b>';
var person = body.getElementsByTagName('i')[0];
person.textContent = 'Misko';
JavaScript Gotchas

JavaScript OO by convention only

Everything defaults to global 'window'

No var implies global 'window'

Reference to a function losses 'this'


defaults to 'window'

Browser is single threaded and all calls return immediately


it is impossible to wait for something, as that would block
the UI thread
Browser Incompatibilities

JavaScript is remarkably consistent across browsers


IE: String [] does not work use .charAt()
IE: Trailing list commas: [ 1, 2, ]
IE: can not set __proto__
Extended APIs

DOM/CSS is remarkably inconsistent across browsers


API to mutate DOM (solution: third-party-libraries)
CSS to style DOM (no good solution)
DOM: IE, WebKit, FireFox, Opera
CSS: IE5, IE6, IE7, WebKit, FireFox, Opera
Browser Memory Leak

JavaScript Objects
Separate memory heap / Advanced Garbage Collectors
Cycles are not a problem

DOM Objects
C/C++ memory heap / RefCounting: malloc() & free()
Cycles are problem for browser developers

Memory Leak
var jsObject = { element: document.body };
document.body.myAttribute = jsObject;
document.addEventListener(...)

Only problem for long lived AJAX apps (no page reloads)
Further Reading

JavaScript puzzlers
http://ejohn.org/apps/learn/

Reference
http://www.w3schools.com/js/default.asp
http://www.w3schools.com/js/js_ex_dom.asp

BOOK: JavaScript the good parts


http://www.crockford.com/javascript/

Functional Programing
http://eloquentjavascript.net/index.html
JavaScript Libraries

Browser DOM abstraction


http://code.google.com/closure/
http://jquery.com/

Functional API
http://documentcloud.github.com/underscore/

JavaScript on Server
http://nodejs.org/

Better syntax for JavaScript


http://jashkenas.github.com/coffee-script/

You might also like