Yeah, JavaScript!
Because Forrest Gump is one of those movies ...
... and because Robert Nyman made an awesome presentation about it, which formed the starting point for these slides.
Another thank you goes out to Mathias Bynens (2nd one from the left) who gave some handy remarks.
Life is like a box of chocolates,
you never know what you're gonna get
firstName
and firstname
are not the same!3
will be a number"Hello"
it'll become a stringvar
keyword and assign a value to a name
var firstName = 'Forrest';
alert(firstName);
// Dynamic typing
var firstName = 'Forrest';
alert(typeof firstName); // string
// Weak typing
firstName = 3;
alert(typeof firstName); // JavaScript has changed the type to number
var firstName = 'Forrest',
lastName = 'Gump';
alert(firstName);
alert(lastName);
string
number
boolean
null
undefined
Array
? And Date
? And ...?
Object
s reallystring
you also have something like String
Object
Let me explain on the next few slides ;)
Object
Object
is the core of the languageString
, Number
, Boolean
, Array
, etc.
Object
myString.length;
(Also noted as String#length
)myString.toUpperCase();
(Also noted as String#toUpperCase
)var firstName = new String('Forrest');
String
object
string
var firstName = new String('Forrest');
alert(firstName instanceof String); // true
alert(typeof firstName); // object
alert(typeof firstName.toString()); // string
var firstName = 'Forrest';
string
(dynamic typing in action)var firstName = 'Forrest';
alert(firstName instanceof String); // false
alert(typeof firstName); // string
It's not that hard, really!
Integer num = new Integer(3); // Not Literal
Integer num = 3; // Literal
String
Number
Boolean
RegExp
Function
(*)Array
Object
var firstName = new String('Forrest'); // String Constructor
var firstName = 'Forrest'; // String Literal
var birthYear = new Number('1945'); // Number Constructor
var birthYear = 1945; // Number Literal
var isRunning = new Boolean('false'); // Boolean Constructor
var isRunning = false; // Boolean Literal
var hasR = new RegExp('r', 'i'); // RegExp Constructor
var hasR = /r/i; // RegExp Literal
var says = new Function('sentence', 'alert(sentence)'); // Function Constructor
var says = function(sentence) { alert(sentence); }; // Function Literal
function says(sentence) { alert(sentence); }; // The function statement
var forrestFriends = new Array('Bubba', 'Lieutenant Dan');
var forrestFriends = ['Bubba', 'Lieutenant Dan']; // Array Literal
var forrest = new Object();
forrest.firstName = 'Forrest';
forrest.lastName = 'Gump';
var forrest = { // Object Literal
firstName : 'Forrest', // semi-colons to assign
lastName : 'Gump',
says : function() { // works with functions too!
return 'Stupid is as stupid does';
} // no trailing comma (!)
};
string
, number
, boolean
), you'll get the primitive returned when using the literal notation!
// String Instance
var lastName = new String('Gump');
alert(typeof lastName); // object
alert(lastName instanceof String); // true
// String Literal
var firstName = 'Forrest';
alert(typeof firstName); // string
alert(firstName instanceof String); // false
Object
, Array
, RegExp
, Function
), the literal will return an instance when using the literal notation.
// Array Instance
var forrestFriends = new Array('Bubba', 'Lieutenant Dan');
alert(typeof forrestFriends); // object
alert(forrestFriends instanceof Array); // true
// Array Literal
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
alert(typeof forrestFriends); // object
alert(forrestFriends instanceof Array); // true
Or at least I hope you do
String
) derive from Object
?
// Number Instance
var birthYear = new Number('1945');
alert(typeof birthYear);
alert(birthYear instanceof Number);
alert(birthYear instanceof Object);
// Array Instance
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
alert(typeof forrestFriends);
alert(forrestFriends instanceof Array);
alert(forrestFriends instanceof Object);
// Function literal
var says = function() { alert('Stupid is as stupid does'); };
alert(typeof says); // <-- the odd one out
alert(says instanceof Function);
alert(says instanceof Object);
Now, back to variables
// Object Literal
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
sentence : 'Stupid is as stupid does',
says : function() {
return this.sentence;
}
};
// test
console.log(forrest);
alert(forrest.firstName);
alert(forrest['firstName']);
alert(forrest.says());
// Various 'false' values
var nullVal = null;
var undefinedVal = undefined;
var zeroVal = 0;
var falseVal = false;
var emptyString = '';
if (emptyString) {
alert('truthy');
} else {
alert('falsy'); // false-ish
}
console.log('5' + 6 + 7);
// Equality
alert((7 == '7') ? 'equal' : 'not equal');
// Identity
alert((7 === '7') ? 'equal (identity)' : 'not equal (identity)');
// Type Coercion (default)
alert('5' + 6 + 7);
// Prevent Type Coercion
alert(parseInt('5', 10) + 6 + 7);
// Global
var quote = 'I had run for 3 years, 2 months, 14 days, and 16 hours.';
var foo = function() {
var saying = 'My name is Forrest, Forrest Gump'; // Local
alert(saying);
alert(quote); // Access to Global
question = 'Why don\'t you love me, Jenny?'; // Local ?
alert(question);
};
foo();
alert(quote);
// alert(saying); // disabled, will fail
alert(question); // Nope, Chuck Testa! Erm, I mean global!
var
keyword is mandatory.
var
keyword inside functions, loops, etc.
String#length
String#toUpperCase
Array#isArray
// String Instance
var firstName = new String('Forrest'); // an instance of String
alert(firstName.toUpperCase());
// String Literal
var firstName = 'Forrest'; // a variable of the type string
alert(firstName.toUpperCase());
// Look ma, no var
alert('Forrest'.toUpperCase());
alert(['Bubba', 'Lieutenant Dan'].length);
Object
String
, Number
, Boolean
)
I had run for 3 years, 2 months, 14 days, and 16 hours.
// If statement
var badGrades = true;
if (badGrades) {
alert('Mom sleeps with teacher');
} else {
alert('Mom does not sleep with teacher');
}
// Switch statement
var age = 10,
lifeState;
switch (age) {
case 10:
lifeState = 'Young';
break;
case 60:
lifeState = 'Old';
break;
default:
lifeState = 'unknown';
break;
}
alert(lifeState);
// Var we'll be using
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
// For
for (var i = 0; i < forrestFriends.length; i++) {
alert(forrestFriends[i]);
}
Performance can be improved by caching variables. That way JavaScript doesn't have to look up everything again.
// Var we'll be using
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
// For
for (var i = 0, len = forrestFriends.length; i < len; i++) {
alert(forrestFriends[i]);
}
// Vars we'll be using
var forrest = {
firstName : 'Forrest',
lastName : 'Gump' // no trailing comma (!)
};
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
// For - In (Array)
for (var friend in forrestFriends) {
alert(forrestFriends[friend]);
}
// For - In (Object)
for (var prop in forrest) {
alert(prop + ' = ' + forrest[prop]);
}
Note: When using arrays, the order is not guaranteed! Better to use Array#forEach
// While
var count = 5;
while (count > 0) {
console.log(count);
count--;
}
// Do - While
var count = 5;
do {
console.log(count);
count--;
} while (count > 0);
// Tip: retry this example with count = 0 as starting value
// Vars we'll be using
var forrest = {
firstName : 'Forrest',
lastName : 'Gump' // no trailing comma (!)
};
// With
with (forrest) {
alert(firstName);
alert(lastName);
}
Note: With is considered harmful and performs badly. Not suggested.
// Vars we'll be using
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
console.log('Stupid is as stupid does');
}
};
// Try-Catch
try {
forrest.functionDoesNotExist();
} catch (error) {
console.error('ERROR! ' + error.name + ' : ' + error.message);
}
// Try-Catch-Finally
try {
forrest.functionDoesNotExist();
} catch (error) {
console.error('ERROR! ' + error.name + ' : ' + error.message);
} finally {
forrest.says();
}
Not a real control structure, but found it fitting here
switch
, for
, for-in
, while
, and do-while
for (var x = 1; x <= 5; x++) {
var y = 1;
while (y <= 7) {
if (y == 5) { break; }
console.log(x + '-' + y);
y++;
}
}
myForLoop:
for (var x = 1; x <= 5; x++) {
var y = 1;
while (y <= 7) {
if (y == 5) { break myForLoop; }
console.log(x + '-' + y);
y++;
}
}
for
, for-in
, while
, and do-while
for (var x = 1; x <= 5; x++) {
for (var y = 1; y <= 7; y++) {
if (y == 5) continue;
console.log(x + '-' + y);
}
}
myForLoop:
for (var x = 1; x <= 5; x++) {
for (var y = 1; y <= 7; y++) {
if (y == 5) { continue myForLoop; }
console.log(x + '-' + y);
}
}
In this example you get the same result as the first break
example
My name is Forrest, Forrest Gump.
// A var we'll need
var looking = true;
// How you'd probably write it at first
var forrestSays;
if (looking) {
forrestSays = 'I gotta find Bubba!';
} else {
forrestSays = 'It\'s OK';
}
alert(forrestSays);
// A var we'll need
var looking = true;
// Better: Ternary operators
var forrestSays = looking ? 'I gotta find Bubba!' : 'It\'s OK';
alert(forrestSays);
// How you'd probably write it at first
var lifeIs = function(boxOfChocolates) {
var life;
if (!boxOfChocolates) {
life = 'a Snickers bar';
} else {
life = boxOfChocolates;
}
return 'Life is like ' + life;
};
alert(lifeIs('a Box of Chocolates'));
// Better: Shorthand assignment
var lifeIs = function(boxOfChocolates) {
return 'Life is like ' + (boxOfChocolates || 'a Snickers bar');
};
alert(lifeIs('a Box of Chocolates'));
// An Object we'll need
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
alert('Stupid is as stupid does');
}
};
// How you'd probably write it at first
if ((forrest != null) && (forrest.says != null)) {
forrest.says();
}
// An Object we'll need
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
alert('Stupid is as stupid does');
}
};
// Short circuit logic
forrest && forrest.says && forrest.says();
var example = 'Forrest'.substr(0,5).split('').join('-').toUpperCase();
alert(example);
Run Forrest, Run()
// Function Constructor
var says = new Function('sentence', 'alert(sentence)');
// function statement or function declaration
function says(sentence) { alert(sentence); };
// function expression or function operator
var says = function(sentence) { alert(sentence); };
var says = function(sentence) {
alert(sentence);
};
says('Stupid is as stupid does');
var says = function(sentence) {
alert(sentence);
};
var forrestSays = function(whatForrestSays) {
says('Forrest Says "' + whatForrestSays + '"');
};
forrestSays('Stupid is as stupid does');
var change = function(obj) {
obj.sentence = 'My name is Forrest, Forrest Gump';
};
// Object Literal => Object Returned
var forrest = {
sentence : 'Stupid is as stupid does'
};
alert(forrest.sentence);
change(forrest);
alert(forrest.sentence);
var change = function(arr) {
arr.unshift('Jenny');
};
// Array Literal => Array (essentially Object) Returned
var forrestFriends = ['Bubba', 'Lieutenant Dan'];
alert(forrestFriends.length);
change(forrestFriends);
alert(forrestFriends.length);
var change = function(sentence) {
sentence = 'My name is Forrest, Forrest Gump';
};
var sentence = 'Stupid is as stupid does'; // String literal (string)
alert(sentence);
change(sentence);
alert(sentence);
var change = function(sentence) {
sentence = 'My name is Forrest, Forrest Gump';
};
var sentence = new String('Stupid is as stupid does'); // String Instance (Object)
alert(sentence);
change(sentence);
alert(sentence);
var logs = function(sentence) {
console.log(sentence);
};
var says = function(sentence) {
alert(sentence);
};
var forrestDoes = function(fn, sentence) {
fn(sentence);
};
forrestDoes(says, 'Stupid is as stupid does');
forrestDoes(logs, 'Stupid is as stupid does');
fn
with the actual passed in function
Function#toString
var logs = function(sentence) {
console.log(sentence);
};
var says = function(sentence) {
alert(sentence);
};
var forrestDoes = function(fn, sentence) {
alert(fn.toString());
fn(sentence);
};
forrestDoes(says, 'Stupid is as stupid does');
forrestDoes(logs, 'Stupid is as stupid does');
var forrestDoes = function(fn, sentence) {
fn(sentence);
};
forrestDoes(function(sentence) { // says from the previous example
alert(sentence);
}, 'Stupid is as stupid does');
forrestDoes(function(sentence) { // logs from the previous example
console.log(sentence);
}, 'Stupid is as stupid does');
function change(fn) {
fn = function() {
alert('changed');
};
};
var says = function() {
alert('Stupid is as stupid does');
};
says();
change(says);
says();
var says = function() { };
alert(typeof says); // Not an object!
var forrest = {
sentence : 'Stupid is as stupid does',
say : function() {
return this.sentence;
}
};
var show = function(fn) {
alert(fn());
};
show(forrest.say);
this
has hanged!var forrest = {
sentence : 'Stupid is as stupid does',
say : function() {
return this.sentence;
}
};
var show = function(obj) {
alert(obj.say());
};
show(forrest);
Function#call
var forrest = {
sentence : 'Stupid is as stupid does',
say : function() {
return this.sentence;
}
};
var show = function(obj, fn) {
alert(fn.call(obj));
};
show(forrest, forrest.say);
Function#call
lets you call a function and give a new meaning to this
when calling itFunction#call
later
var run = function() {
alert('Run Forrest, Run');
};
run();
var run = (function() {
alert('Run Forrest, Run');
});
run();
run();
, JavaScript will replace the run
part of that statement with the actual contents of the variable run
(function() {
alert('Run Forrest, Run');
})();
(function() {
alert('Run Forrest, Run');
}()); // The Crockford Way
(function(sentence) {
alert(sentence);
})('Run Forrest, Run');
run('Run Forrest, Run');
var toSay = 'Run Forrest, Run';
(function(sentence) {
alert(sentence);
})(toSay);
var forrestSays = function(whatForrestSays) {
var says = function(sentence) {
alert(sentence);
};
says(whatForrestSays);
};
forrestSays('Stupid is as stupid does');
var forrestSays = function(whatForrestSays) {
var says = function(sentence) {
alert(sentence);
};
says(whatForrestSays);
};
forrestSays('Stupid is as stupid does');
says('Stupid is as stupid does'); // will fail, not in scope!
var says = function(sentence) {
alert('Outer says, says "' + sentence + '"');
};
var forrestSays = function(whatForrestSays) {
var says = function(sentence) {
alert('Inner says, says "' + sentence + '"');
};
says(whatForrestSays);
};
forrestSays('Stupid is as stupid does');
says('Stupid is as stupid does'); // won't fail
says
from within forrestSays
?return
statement
var says = function(what, verb) {
return what + ' ' + verb;
};
var shitHappens = says('Shit', 'happens');
alert(shitHappens);
var says = function(what) {
return function(verb) {
return what + ' ' + verb;
};
};
var shit = says('Shit');
alert(shit('happens'));
// also possible
alert(says('Shit')('happens'));
LexicalEnvironment
)Yeah, I understand ... lets just check an example
var firstName = 'Forrest';
var forrestFriends = function() {
var friends = ['Bubba', 'Lieutenant Dan'];
var friendsCount = function() {
return friends.length;
};
var joinFriends = function() {
return firstName + ' has ' + friendsCount() + ' friends: ' + friends.join(', ');
};
return joinFriends();
};
alert(forrestFriends());
joinFriends
(or any of the other functions) is created, a closure is created
var firstName = 'Forrest';
var forrestFriends = function() {
var friends = ['Bubba', 'Lieutenant Dan'];
var friendsCount = function() {
return friends.length;
};
var joinFriends = function() {
return firstName + ' has ' + friendsCount() + ' friends: ' + friends.join(', ');
};
return joinFriends();
};
alert(forrestFriends());
joinFriends
is everything “on the same level of it”, thus everything inside the curly brackets of forrestFriends
LexicalEnvironment
of the created closure holds the variablesfriends
, friendsCount
and joinFriends
var firstName = 'Forrest';
var forrestFriends = function() {
var friends = ['Bubba', 'Lieutenant Dan'];
var friendsCount = function() {
return friends.length;
};
var joinFriends = function() {
return firstName + ' has ' + friendsCount() + ' friends: ' + friends.join(', ');
};
return joinFriends();
};
alert(forrestFriends());
firstName
? That wasn't part of the current scope?
LexicalEnvironment
, it will try the outer LexicalEnvironment
(go up one level) to (hope to) find it there
LexicalEnvironment
of the closure created when forrestFriends
was created; which has access to the vars in the global scope
Please, bear with me, there are some facts you should know
LexicalEnvironment
var firstName = 'Forrest';
var forrestFriends = function() {
var friends = ['Bubba', 'Lieutenant Dan'];
var friendsCount = function() {
return friends.length;
};
var joinFriends = function() {
return firstName + ' has ' + friendsCount() + ' friends: ' + friends.join(', ');
};
friends.unshift('Jenny'); // Change friends, after the function was created
return joinFriends();
};
alert(forrestFriends());
var firstName = 'Forrest';
var forrestFriends = function() {
var friends = ['Bubba', 'Lieutenant Dan'];
var friendsCount = function() {
return friends.length;
};
var joinFriends = function() {
return firstName + ' has ' + friendsCount() + ' friends: ' + friends.join(', ');
};
return joinFriends;
};
var ff = forrestFriends();
// at this moment, the outer function has ended
// only joinFriends() was returned
// what about friends and friendsCount? Will they still exist?
alert(ff());
var add = function(x) {
return function(y) {
return x + y;
};
};
var add5 = add(5),
add6 = add(6);
var eleven = add5(6),
twelve = add6(6);
alert(eleven);
alert(twelve)
add5
has become
function(y) {
return x + y;
}; // How I know? Try alert(add5.toString()); in the example above ;)
x
?
LexicalEnvironment
)var sum = function(a, b, c, d, e) {
return a + b + c + d + e
};
alert(sum(1,2)); // NaN (!)
alert(sum(1,2,3,4,5)); // 15
alert(sum(1,2,3,4,5,6)); // What now?
arguments
variable inside each function
var sum = function() {
alert(typeof arguments);
alert(arguments instanceof Object);
alert(arguments instanceof Array);
};
sum(1,2);
arguments
variable is an Object
, and not an Array
, as you can see!Object
with a for
loop just as you'd do with an Array
var sum = function() {
var sum = 0;
for (var i = 0, len = arguments.length; i < len; i++) {
sum += parseInt(arguments[i]);
}
return sum;
};
alert(sum(1,2));
alert(sum(1,2,3,4,5));
alert(sum(1,2,3,4,5,6));
arguments
to an other function?
var otherFunc=function() {
alert('otherFunc : ' + arguments.length);
};
var myFunc = function() {
alert('myFunc : ' + arguments.length);
otherFunc(arguments);
};
myFunc(1,2,3,4,5,6,7,8,9,10);
Function#apply
and Function#call
Function#apply
allows you to call an other function and give it a new meaning of this
. Arguments passed in using an Array
-like Object
Function#apply(this, Array(arg1[, arg2[, ...[, argN]]]));
var otherFunc = function() {
alert('otherFunc : ' + arguments.length);
};
var myFunc = function() {
alert('myFunc : ' + arguments.length);
otherFunc.apply(this, arguments);
};
myFunc(1,2,3,4,5,6,7,8,9,10);
this
laterFunction#call
does the same as Function#apply
, but passed in arguments must be passed in one by one (comma separated)
Function#call(this, arg1[, arg2[, ...[, argN]]]);
Function#apply
in this context though, as we can immediately pass in arguments
or any other Array
or Object
Function#bind
also exists, but we'll touch that later
var says = function() {
var firstName = arguments[0],
sentence = arguments[1];
return firstName + ' says "' + sentence + '"';
};
alert(says('Forrest', 'Stupid is as stupid does'));
0
is who
and index 1
is what
in this example
Object
var says = function(person) {
return person.firstName + ' says "' + person.sentence + '"';
};
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
sentence : 'Stupid is as stupid does',
birthYear : 1945
};
alert(says(forrest));
var extend = function(params, defaults) {
for (var i in defaults) {
if (!params[i]) {
params[i] = defaults[i];
}
}
};
var foo = function(params) {
var defaults = { position: 'left', start: 0, stop: 10 };
extend(params, defaults);
console.log(params);
};
foo({ position: 'left', start: 3 });
LexicalEnvironment
arguments
or pass in your own Object
Gump! What's your sole purpose in this army?
To do whatever you tell me, drill sergeant!
Object
// Object Constructor
var forrest = new Object();
forrest.firstName = 'Forrest';
forrest.lastName = 'Gump';
forrest.says = function() {
return 'Stupid is as stupid does';
};
alert(forrest.says());
// Object Literal
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
return 'Stupid is as stupid does';
} // no trailing comma (!)
};
alert(forrest.says());
this
keyword
// Object Literal
var forrest = {
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
return this.firstName + ' says "Stupid is as stupid does"';
}
};
alert(forrest.says());
this
?Function#call
or Function#apply
, this will be set to the first argument passed to call
/apply
. If the first argument passed to call
/apply
is null
or undefined
, this will refer to the global object.Function#bind
, this will be the first argument that was passed to bind at the time the function was created.this
will refer to that object.Object
var forrest = { // Forrest
firstName : 'Forrest',
lastName : 'Gump',
says : function() {
return this.firstName + ' says "Stupid is as stupid does"';
}
};
var dan = { // Lieutenant Dan
firstName : 'Dan',
lastName : 'Taylor',
says : function() {
return this.firstName + ' says "I\'m here to try out my sea legs"';
}
};
// Jenny
// ...
var Person = function(firstName, lastName, sentence) {
this.firstName = firstName;
this.lastName = lastName;
this.sentence = sentence;
this.says = function() {
return this.firstName + ' says "' + this.sentence + '"';
};
};
var forrest = new Person('Forrest', 'Gump', 'Stupid is as stupid does');
var dan = new Person('Dan', 'Taylor', 'I\'m here to try out my sea legs');
alert(forrest.says());
alert(dan.says());
Person#firstName
, Person#lastName
, Person#sentence
and Person#says
as those are properties/methods of Person
Person#firstName
and the others in the .prototype
of Person
Person#firstName
, we actually say Person.prototype.firstName
.prototype
, you're basically changing the class definition
.prototype
console.log(String.prototype);
.prototype
, you're basically changing the class definition
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Person.prototype.isRunning = false;
Person.prototype.run = function() {
this.isRunning = true;
};
var forrest = new Person('Forrest', 'Gump');
var dan = new Person('Dan', 'Taylor');
alert(forrest.isRunning ? 'Forrest is running' : 'Forrest is not running');
alert(dan.isRunning ? 'Dan is running' : 'Dan is not running');
forrest.run();
alert(forrest.isRunning ? 'Forrest is running' : 'Forrest is not running');
alert(dan.isRunning ? 'Dan is running' : 'Dan is not running');
Number.prototype.fahrenheitToCelcius = function() {
return (parseInt(this, 10) - 32) / 1.8;
};
Number.prototype.celciusToFahrenheit = function() {
return (parseInt(this, 10) * 1.8) + 32;
};
var c = 40;
var f = 104;
alert(c.celciusToFahrenheit());
alert(f.fahrenheitToCelcius());
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Person.prototype.fullName = function() {
return this.firstName + ' ' + this.lastName;
};
var Actor = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Actor.prototype = new Person; // Inheritance
var forrest = new Person('Forrest', 'Gump');
var tomhanks = new Actor('Tom', 'Hanks');
alert(forrest.fullName());
alert(tomhanks.fullName());
Function#call
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
Person.prototype.fullName = function() {
return this.firstName + ' ' + this.lastName;
};
var Actor = function(firstName, lastName) {
Person.call(this, firstName, lastName);
};
Actor.prototype = new Person;
var forrest = new Person('Forrest', 'Gump');
var tomhanks = new Actor('Tom', 'Hanks');
alert(forrest.fullName());
alert(tomhanks.fullName());
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
};
var Actor = function(firstName, lastName) {
Person.call(this, firstName, lastName);
};
Actor.prototype = new Person;
Person.prototype.isHuman = true;
var forrest = new Person('Forrest', 'Gump');
var tomhanks = new Actor('Tom', 'Hanks');
alert(forrest.isHuman ? 'Human' : 'Not Human');
alert(tomhanks.isHuman ? 'Human' : 'Not Human');
var forrest = (function() {
var firstName = 'Forrest'; // Private var
var says = function() { // Private function
return 'Stupid is as stupid does';
};
return {
lastName : 'Gump', // Public var
getLastName : function() { // Public function
return this.lastName; // use this when accessing a public var
},
getFirstName : function () {
return firstName; // no this when accessing private vars!
}
};
})(); // IIFE
alert(forrest.getFirstName() + ' ' + forrest.getLastName());
var forrest = (function() {
var firstName = 'Forrest';
var lastName = 'Gump';
var says = function() {
return 'Stupid is as stupid does';
};
var getLastName = function() {
return lastName;
};
var getFirstName = function () {
return firstName;
};
return {
getFirstName: getFirstName,
getLastName: getLastName,
whatDoesHeSay: says
};
})(); // IIFE
alert(forrest.whatDoesHeSay());
Stupid is as stupid does
Array#forEach
is only available since JavaScript 1.6)<!DOCTYPE HTML>
<html>
<head>
<title>The document</title>
</head>
<body>
<div>Data</div>
<ul>
<li>Warning</li>
<li></li>
</ul>
<div>Top Secret!</div>
</body>
</html>
Yes, whitespace counts as a node too!
window.document
offers quite a few ways of selecting elements from the document
// get one element with the given id
var el = document.getElementById('siteWrapper');
// get all links (<a> elements)
var links = document.getElementsByTagName('a');
document.links; // or use the built-in property!
// get all elements with the class foo
var foos = document.getElementsByClassName('foo');
// get elements based on a CSS selector
var els = document.querySelectorAll('code pre');
// get elements based on CSS selector
var el = document.querySelector('code pre'); // only returns the first match
// change CSS properties
document.getElementById('manipulating-demo').style.border = '1px solid #FFF';
document.getElementById('manipulating-demo').style.padding = '20px';
// change text
document.getElementById('manipulating-demo').innerHTML = 'Code has been run, I am changed';
// set 'test' as classname
document.getElementById('manipulating-demo').className = 'test';
// give notice
alert('The element #' + document.getElementById('manipulating-demo').id + ' was changed');
Run example above to change me
// cache the variable
var el = document.getElementById('manipulating-demo2');
// change CSS properties
el.style.border = '1px solid #FFF';
el.style.padding = '20px';
// change text
el.innerHTML = 'Code has been run, I am changed';
// set 'test' as classname
el.className = 'test';
// give notice
alert('The element #' + el.id + ' was changed');
Run example above to change me
var allSpans = document.querySelectorAll('#manipulating-unoptimized span');
for (var i = 0; i < allSpans.length; i++) {
allSpans[i].className = 'test';
allSpans[i].style.border = '1px solid #FFF';
allSpans[i].style.padding = '5px';
allSpans[i].style.margin = '5px';
}
123
var allSpans = document.querySelectorAll('#manipulating-optimized span');
for (var i = 0, len = allSpans.length; i < len; i++) {
var curSpan = allSpans[i];
curSpan.className = 'test';
curSpan.style.border = '1px solid #FFF';
curSpan.style.padding = '5px';
curSpan.style.margin = '5px';
}
456
Element
reference
Node#parentNode
Node#childNodes
, Node#firstChild
, Node#lastChild
Node#previousSibling
, Node#nextSibling
Node#parentElement
Node#children
, Node#firstElementChild
, Node#lastElementChild
Node#previousElementSibling
, Node#nextElementSibling
click
, mouseover
, mouseout
, ..)keypress
, keydown
, keyup
)submit
, reset
)load
ing, a resize
of the window, an element gaining focus
, etc.#onEventname
var p = document.querySelector('#onevent-demo p');
p.onclick = function() { alert('You clicked me!'); };
p.onmouseover = function() { this.style.backgroundColor = '#333'; };
p.onmouseout = function() { this.style.backgroundColor = ''; };
I am the demo
var p = document.querySelector('#oneventtwice-demo p');
p.onclick = function() { alert('You clicked me (1)!'); };
p.onclick = function() { alert('You clicked me (2)!'); };
p.onmouseover = function() { this.style.backgroundColor = '#333'; };
p.onmouseout = function() { this.style.backgroundColor = ''; };
I am the 2nd demo
#addEventListener
var p = document.querySelector('#addeventlistener-demo p');
p.addEventListener('click', function() {
alert('You clicked me!');
});
p.addEventListener('mouseover', function() {
this.style.backgroundColor = '#333';
});
p.addEventListener('mouseout', function() {
this.style.backgroundColor = '';
});
I am the demo
#addEventListener
multiple times for the same event
var p = document.querySelector('#addeventlistenertwice-demo p');
p.addEventListener('click', function() {
alert('You clicked me (1)!');
});
p.addEventListener('click', function() {
alert('You clicked me (2)!');
});
p.addEventListener('mouseover', function() {
this.style.backgroundColor = '#333';
});
p.addEventListener('mouseout', function() {
this.style.backgroundColor = '';
});
I am the demo
#removeEventListener
, but only if you've attached a named function
var p = document.querySelector('#removeeventlistener-demo p');
var clickHandler = function() {
alert('You clicked me!');
};
p.addEventListener('click', clickHandler);
p.removeEventListener('click', clickHandler);
p.addEventListener('mouseover', function() {
this.style.backgroundColor = '#333';
});
p.addEventListener('mouseout', function() {
this.style.backgroundColor = '';
});
I am the demo
var divs = document.querySelectorAll('#bubbling-demo div');
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'yellow';
alert(this.className);
this.style.backgroundColor = '';
});
}
Event#stopPropagation
var divs = document.querySelectorAll('#stoppropagation-demo div');
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'yellow';
alert(this.className);
this.style.backgroundColor = '';
event.stopPropagation(); // stop bubbling!
});
}
Event#preventDefault
var link = document.querySelector('#stopdefault-demo a');
link.addEventListener('click', function(event) {
alert('Link is linked to ' + this.href + ' but won\'t be followed');
event.preventDefault(); // prevent the default action from happening
});
return false;
var divs = document.querySelectorAll('#bubblingtarget-demo div');
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'yellow';
alert(this.className + ' (click was on ' + event.target.className + ')');
this.style.backgroundColor = '';
});
}
event.target
it's possible to bind the handler on the <table>
itself.
var table = document.querySelector('#bubbling-advantage-demo table');
table.addEventListener('click', function(event) {
alert('Table click event (click was on ' + event.target.innerHTML + ')');
});
1 | 2 | 3 |
4 | 5 | 6 |
var divs = document.querySelectorAll('#capturing-demo div');
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'cyan';
alert(this.className);
this.style.backgroundColor = '';
}, true); // phase parameter!
}
var divs = document.querySelectorAll('#capturing-and-bubbling-demo div');
for (var i = 0, len = divs.length; i < len; i++) {
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'cyan';
alert(this.className);
this.style.backgroundColor = '';
}, true); // capturing phase
divs[i].addEventListener('click', function(event) {
this.style.backgroundColor = 'yellow';
alert(this.className);
this.style.backgroundColor = '';
}, false); // bubbling phase
}
var link,
target = Reveal.getCurrentSlide().querySelector('.result');
target.innerHTML = ''; // clear the target
for (var i = 0; i < 3; i++) { // add three links
link = document.createElement('a');
link.style.marginRight = '10px';
link.innerHTML = 'Link ' + i;
link.onclick = function() {
alert('I am link ' + i);
};
target.appendChild(link);
};
onclick
, a function is created
Here we go again!
var link,
target = Reveal.getCurrentSlide().querySelector('.result');
target.innerHTML = ''; // clear the target
for (var i = 3; i < 6; i++) { // add three links
link = document.createElement('a');
link.style.marginRight = '10px';
link.innerHTML = 'Link ' + i;
var j = i; // introduction of a local variable
link.onclick = function() { // function created, ergo closure created!
alert('I am link ' + j);
};
target.appendChild(link);
};
var toSay = 'Run Forrest, Run';
(function(sentence) {
console.log(sentence);
})(toSay);
var link,
target = Reveal.getCurrentSlide().querySelector('.result');
target.innerHTML = ''; // clear the target
for (var i = 6; i < 9; i++) { // add three links
link = document.createElement('a');
link.style.marginRight = '10px';
link.innerHTML = 'Link ' + i;
link.onclick = function(j) { // This one just became an IIFE
return function() { // and returns a function
alert('I am link ' + j);
};
}(i);
target.appendChild(link);
}
<!doctype html>
<html>
<head>
...
<script>
alert('hello');
</script>
...
</head>
<body>
...
</body>
</html>
alert
before the page is being rendered!<!doctype html>
<html>
<head>
...
<script src="path/to/my.js"></script>
...
</head>
<body>
...
</body>
</html>
</body>
, to not block parallel downloads
<!doctype html>
<html>
<head>
...
</head>
<body>
...
<script src="path/to/my.js"></script>
</body>
</html>
<!doctype html>
<html>
<head>
...
</head>
<body>
...
<script src="path/to/my.js"></script>
</body>
</html>
window.onload = function() {
// ... your code here
};
addEventListener
document.addEventListener('load', function(event) {
// ... your code here
}, false);
load
is fired when everything (including images) is loaded. Most of the time you'll want to invoke your scripts when the DOM has loaded.
document.addEventListener('DOMContentLoaded', function(event) {
// ... your code here
}, false);
animate
, but then include a library that defines the same function with the same name
ikdoeict_
) but that isn't quite professional
var IKDOEICT = {
foo : {
bar : function(x) { return x; },
baz : function(x) { return x; }
},
foobar : {
foo : function(x) { return x; },
bar : function(x) { return x; },
baz : function(x) { return x; }
}
};
alert(IKDOEICT.foobar.foo('test'));
// file 1
var IKDOEICT = IKDOEICT || {}; // use existing IKDOEICT, or create a new Object
IKDOEICT.foo = {
bar : function(x) { return x; },
baz : function(x) { return x; }
};
// file 2
var IKDOEICT = IKDOEICT || {}; // use existing IKDOEICT, or create a new Object
IKDOEICT.foobar = {
foo : function(x) { return x; },
bar : function(x) { return x; },
baz : function(x) { return x; }
};
// test
alert(IKDOEICT.foo.baz('test'));
var IKDOEICT = IKDOEICT || {};
(function(o){
o.foo = {
bar : function(x) { return x; },
baz : function(x) { return x; }
}
o.foobar = {
foo : function(x) { return x; },
bar : function(x) { return x; },
baz : function(x) { return x; }
}
})(IKDOEICT);
// test
alert(IKDOEICT.foo.baz('test'));
var IKDOEICT = (function(){
var privateFunction = function() { return; }
return {
foo : {
bar : function(x) { return x; },
baz : function(x) { return x; }
},
foobar : {
foo : function(x) { return x; },
bar : function(x) { return x; },
baz : function(x) { return x; }
}
};
})();
// test
alert(IKDOEICT.foo.baz('test'));
</body>
DOMContentLoaded
for...in
these will appear inside your loop
Object#hasOwnProperty
inside your loop