<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>html parsing
script downloading
script execution
html parsing paused
normal <script>
<script async>
<script defer>
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.
});further performance enhancements
simple things: EQUALITY
=== operator
simple things: EQUALITY
long story short, use the === operator. == opens up your code to unintended side-effects.
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.
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 within other languages, varying parameters means different methods. not so in javascript.
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 || {};
} 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.
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
// 5callbacks
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());
});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 1hoisting
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"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.
objects from objects, not from types
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"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]);
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
};
}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 */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);
}
};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"]);
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));process
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>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();
});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?