Skip to content

Instantly share code, notes, and snippets.

@chorr
Created January 18, 2012 05:44
Show Gist options
  • Save chorr/1631233 to your computer and use it in GitHub Desktop.
Save chorr/1631233 to your computer and use it in GitHub Desktop.
Secrets of the JavaScript Ninja - Chapter.3 Sample Code
/* HTML code snippet
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>JS Bin</title>
<script type="text/javascript" src="http://chorr.net/lib/js/assert.js"></script>
<style>
#results li.pass { color: green; }
#results li.fail { color: red; }
</style>
</head>
<body>
<ul id="results"></ul>
</body>
</html>
*/
// Listing 3.1 : http://jsbin.com/ahokod
function isNimble(){ return true; } //#1
var canFly = function(){ return true; }; //#2
window.isDeadly = function(){ return true; }; //#3
console.log(window.isNimble); //#4
console.log(window.canFly); //#4
console.log(window.isDeadly); //#4
// Listing 3.2 : http://jsbin.com/uyeneq
var canFly = function() { return true; };
window.isDeadly = function() { return true; };
assert(isNimble() && canFly() && isDeadly(), //#2
'Works, even though isNimble is declared below.'); //#2
function isNimble() { return true; } //#3
// Listing 3.3 : http://jsbin.com/itivom
function stealthCheck(){
assert(stealth(), //#1
"We'll never get below the return, but that's OK!");
return true;
function stealth(){ return true; } //#2
}
stealthCheck(); //#3
// Listing 3.4 : http://jsbin.com/uyomix/2
assert(typeof canFly == "undefined", //#A
"canFly can't be forward referenced."); //#A
assert(typeof isDeadly == "undefined", "Nor can isDeadly." ); //#A
var canFly = function(){ return true; }; //#B
window.isDeadly = function(){ return true; }; //#B
// Listing 3.5 : http://jsbin.com/ivejuq
var obj = {
someMethod: function(){ //#1
console.log('Hi!'); //#1
}
};
obj.someMethod(); //#2
setInterval(
function(){ console.log('Here!'); }, //#3
1000);
// Listing 3.6 : http://jsbin.com/iveduv
function yell(n) { //#1
return n > 0 ? yell(n-1) + "a" : "hiy"; //#1
} //#1
assert(yell(4) == "hiyaaaa", //#2
"Calling the named function comes naturally.");
// Listing 3.7 : http://jsbin.com/ihuquv
var ninja = {
yell: function(n) { //#1
return n > 0 ? ninja.yell(n - 1) + "a" : "hiy";
}
};
assert(ninja.yell(4) == "hiyaaaa",
"An object property isn't too bad, either.");
// Listing 3.8 : http://jsbin.com/ihuquv/2
var ninja = {
yell: function(n) {
return n > 0 ? ninja.yell(n - 1) + "a" : "hiy";
}
};
var samurai = { yell: ninja.yell }; //#1
ninja = {}; //#2
try {
assert(samurai.yell(4) == "hiyaaaa", //#3
"Is this going to work?");
}
catch(e) {
console.log("Uh, this isn't good! Where'd ninja.yell go?");
}
// http://jsbin.com/ihuquv/3
var ninja = {
yell: function(n) {
return n > 0 ? this.yell(n - 1) + "a" : "hiy";
}
};
var samurai = { yell: ninja.yell }; //#1
ninja = {}; //#2
try {
assert(samurai.yell(4) == "hiyaaaa", //#3
"Is this going to work?");
}
catch(e) {
console.log("Uh, this isn't good! Where'd ninja.yell go?");
}
// Listing 3.9 : http://jsbin.com/ihuquv/4
var ninja = {
yell: function shout(n) { //#1
return n > 0 ? shout(n - 1) + "a" : "hiy";
}
};
assert(ninja.yell(4) == "hiyaaaa", //#2
"Works as we would expect it to!");
var samurai = { yell: ninja.yell };
ninja = {}; //#3
assert(samurai.yell(4) == "hiyaaaa", //#4
"The method correctly calls itself.");
// Listing 3.10 : http://jsbin.com/opusuf
var ninja = function myNinja(){ //#1
assert(ninja == myNinja, //#2
"This function is named two things at once!"); //#2
};
ninja(); //#3
assert(typeof myNinja == "undefined", //#4
"But myNinja isn't defined outside of the function."); //#4
// Listing 3.11 : http://jsbin.com/opusuf/2
var ninja = {
yell: function(n){
return n > 0 ? arguments.callee(n-1) + "a" : "hiy"; //#1
}
};
assert(ninja.yell(4) == "hiyaaaa",
"arguments.callee is the function itself.");
//
var obj = {};
var fn = function(){};
assert(obj && fn, "Both the object and function exist.");
//
var obj = {};
var fn = function(){};
obj.prop = "hitsuke (distraction)";
fn.prop = "tanuki (climbing)";
assert(obj.prop == fn.prop,
"Both are objects, both have the property.");
// Listing 3.12 : http://jsbin.com/eqabag
var store = {
nextId: 1, //#1
cache: {}, //#2
add: function(fn) { //#3
if (!fn.id) { //#3
fn.id = store.nextId++; //#3
return !!(store.cache[fn.id] = fn); //#3
}
}
};
function ninja(){}
assert(store.add(ninja), //#4
"Function was safely added."); //#4
assert(!store.add(ninja), //#4
"But it was only added once."); //#4
// Listing 3.13 : http://jsbin.com/arenaz
function isPrime(value) {
if (isPrime.answers[value] != null) { //#1
return isPrime.answers[value]; //#1
} //#1
var prime = value != 1; // 1 can never be prime
for (var i = 2; i < value; i++) {
if (value % i == 0) {
prime = false;
break;
}
}
return isPrime.answers[value] = prime; //#2
}
isPrime.answers = {}; //#3
assert(isPrime(5), "5 is prime!" ); //#4
assert(isPrime.answers[5], "The answer was cached!" ); //#4
//
function getElements( name ) {
if (!getElements.cache) getElements.cache = {};
return getElements.cache[name] =
getElements.cache[name] ||
document.getElementsByTagName(name);
}
// Listing 3.14 : http://jsbin.com/uzucop
var katana = {
isSharp: true, //#1
use: function(){ //#2
this.isSharp = !this.isSharp; //#2
} //#2
};
katana.use(); //#3
assert(!katana.isSharp, //#4
"The value of isSharp has been changed!");
// Listing 3.15 : http://jsbin.com/ukuwev
function katana(){ //#1
this.isSharp = true; //#1
} //#1
katana(); //#2
assert(isSharp === true, //#3
"A global property now exists.");
// Listing 3.16 : http://jsbin.com/ibipeg
function fn(){ return this; } //#1
var ronin = {}; //#2
assert(fn() == this, "The context is the global object."); //#3
assert(fn.call(ronin) == ronin, //#4
"The context is changed to a specific object." );
// Listing 3.17 : http://jsbin.com/unesoq
function add(a, b){ //#1
return a + b; //#1
} //#1
assert(add.call(this, 1, 2) == 3, //#2
".call() takes individual arguments" );
assert(add.apply(this, [1, 2]) == 3, //#3
".apply() takes an array of arguments" );
// Listing 3.18 : http://jsbin.com/elilix
function loop(array,fn){ //#1
for (var i = 0; i < array.length; i++) //#1
if (fn.call(array, array[i], i) === false) break; //#1
} //#1
var num = 0; //#2
var numbers = [4,5,6]; //#2
loop(numbers, function(value, n){
assert(this === numbers, //#3
"Context is correct.");
assert(n == num++, //#4
"Counter is as expected.");
assert(value == numbers[n], //#5
"Value is as expected.");
});
// Listing 3.19 : http://jsbin.com/utibam/2
var elems = {
length: 0, //#1
add: function(elem){ //#2
Array.prototype.push.call(this, elem);
},
find: function(id){ //#3
this.add(document.getElementById(id));
}
};
elems.find("first"); //#4
assert(elems.length == 1 && elems[0].nodeType, //#4
"Verify that we have an element in our stash"); //#4
elems.find("second"); //#4
assert(elems.length == 2 && elems[1].nodeType, //#4
"Verify the other insertion"); //#4
// Listing 3.20 : http://jsbin.com/uxipot
function smallest(array){ //#1
return Math.min.apply(Math, array); //#1
} //#1
function largest(array){ //#2
return Math.max.apply(Math, array); //#2
} //#2
assert(smallest([0, 1, 2, 3]) == 0, //#3
"Located the smallest value."); //#3
assert(largest([0, 1, 2, 3]) == 3, //#3
"Located the largest value."); //#3
// Listing 3.21 : http://jsbin.com/ereseg
function merge(root){ //#1
for (var i = 1; i < arguments.length; i++) {
for (var key in arguments[i]) {
root[key] = arguments[i][key];
}
}
return root;
}
var merged = merge( //#2
{name: "Batou"}, //#2
{city: "Niihama"}); //#2
assert(merged.name == "Batou", //#3
"The original name is intact."); //#3
assert(merged.city == "Niihama", //#3
"And the city has been copied over."); //#3
// Listing 3.22 : http://jsbin.com/iwacod
function multiMax(multi){
return multi * Math.max.apply(Math, arguments.slice(1));
}
assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)");
// Listing 3.23 : http://jsbin.com/iwacod/2
function multiMax(multi){
return multi * Math.max.apply(Math,
Array.prototype.slice.call(arguments, 1)); //#1
}
assert(multiMax(3, 1, 2, 3) == 9,
"3*3=9 (First arg, by largest.)");
// http://jsbin.com/ubacul
function makeNinja(name){}
function makeSamurai(name, rank){}
assert( makeNinja.length == 1, "Only expecting a single argument" );
assert( makeSamurai.length == 2, "Two arguments expected" );
// Listing 3.24 : http://jsbin.com/ayuher
function addMethod(object, name, fn) {
var old = object[name]; //#1
object[name] = function(){
if (fn.length == arguments.length) //#2
return fn.apply(this, arguments) //#2
else if (typeof old == 'function') //#3
return old.apply(this, arguments); //#3
};
}
// Listing 3.25 : http://jsbin.com/ayuher
var ninjas = { //#1
values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"]
};
addMethod(ninjas, "find", function(){ //#2
return this.values;
});
addMethod(ninjas, "find", function(name){ //#3
var ret = [];
for (var i = 0; i < this.values.length; i++)
if (this.values[i].indexOf(name) == 0)
ret.push(this.values[i]);
return ret;
});
addMethod(ninjas, "find", function(first, last){ //#4
var ret = [];
for (var i = 0; i < this.values.length; i++)
if (this.values[i] == (first + " " + last))
ret.push(this.values[i]);
return ret;
});
assert(ninjas.find().length == 3, //#5
"Found all ninjas");
assert(ninjas.find("Sam").length == 1,
"Found ninja by first name");
assert(ninjas.find("Dean", "Edwards").length == 1,
"Found ninja by first and last name");
assert(ninjas.find("Alex", "X", "Russell") == null,
"Found nothing");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment