Created
January 18, 2012 05:44
-
-
Save chorr/1631233 to your computer and use it in GitHub Desktop.
Secrets of the JavaScript Ninja - Chapter.3 Sample Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* 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