diff --git a/jskoans.htm b/jskoans.htm deleted file mode 100644 index 1da57b5a..00000000 --- a/jskoans.htm +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -

QUnit example

-

-

-

To begin, find the file 'topics/about_asserts.js', and complete the tests.

-
    -
    test markup, will be hidden
    - - diff --git a/jskoans.html b/jskoans.html new file mode 100644 index 00000000..b51047bd --- /dev/null +++ b/jskoans.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +

    QUnit example

    +

    +

    +

    To begin, find the file 'topics/0_asserts.js', and complete the tests.

    +
      +
      test markup, will be hidden
      + + diff --git a/topics/about_asserts.js b/topics/0_asserts.js similarity index 54% rename from topics/about_asserts.js rename to topics/0_asserts.js index f94dde46..3f82c7e0 100644 --- a/topics/about_asserts.js +++ b/topics/0_asserts.js @@ -1,5 +1,8 @@ - -module("About Asserts (topics/about_asserts.js)"); +/* + These exercises use the QUnit test suite. It contains of three different + functions to test for expected values. Fill in the values to see how they work! +*/ +module("About Asserts (topics/0_asserts.js)"); test("ok", function() { ok(__, 'what will satisfy the ok assertion?'); diff --git a/topics/10_reflection.js b/topics/10_reflection.js new file mode 100644 index 00000000..ee9f3b6f --- /dev/null +++ b/topics/10_reflection.js @@ -0,0 +1,22 @@ +module("About Reflection (topics/10_reflection.js)"); + +test("typeof", function() { + equals(typeof({}), __, 'what is the type of an empty object?'); + equals(typeof('apple'), __, 'what is the type of a string?'); + equals(typeof(-5), __, 'what is the type of -5?'); + equals(typeof(false), __, 'what is the type of false?'); +}); + +test("property enumeration", function() { + var keys = []; + var values = []; + var person = {name: 'Amory Blaine', age: 102, unemployed: true}; + for(propertyName in person) { + keys.push(propertyName); + values.push(person[propertyName]); + } + ok(keys.equalTo(['__','__','__']), 'what are the property names of the object?'); + ok(values.equalTo(['__',__,__]), 'what are the property values of the object?'); +}); + + diff --git a/topics/about_prototype_chain.js b/topics/11_prototype_chain.js similarity index 96% rename from topics/about_prototype_chain.js rename to topics/11_prototype_chain.js index e215b8a7..8b60dbd2 100644 --- a/topics/about_prototype_chain.js +++ b/topics/11_prototype_chain.js @@ -1,7 +1,7 @@ // demonstrate objects prototype chain // https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_and_the_prototype_chain -module("About Prototype Chain (topics/about_prototype_chain.js)"); +module("About Prototype Chain (topics/11_prototype_chain.js)"); var father = { b: 3, diff --git a/topics/about_prototypal_inheritance.js b/topics/12_prototypal_inheritance.js similarity index 67% rename from topics/about_prototypal_inheritance.js rename to topics/12_prototypal_inheritance.js index b2d152c6..5235583b 100644 --- a/topics/about_prototypal_inheritance.js +++ b/topics/12_prototypal_inheritance.js @@ -1,7 +1,7 @@ // demonstrate the effect of modifying an objects prototype before and after the object is constructed -module("About Prototypal Inheritance (topics/about_prototypal_inheritance.js)"); +module("About Prototypal Inheritance (topics/12_prototypal_inheritance.js)"); // this 'class' pattern defines a class by its constructor var Mammal = function(name) { @@ -37,24 +37,3 @@ test("calling functions added to a prototype after an object was created", funct // for the following statement asks the paul object to call a function that was added to the Mammal prototype after paul was constructed. equals(paul.numberOfLettersInName(), __, "how long is Paul's name?"); }); - -// helper function for inheritance. -// From https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited -function extend(child, supertype){ - child.prototype = supertype.prototype; -} - -// "Subclass" Mammal -function Bat(name, wingspan) { - Mammal.call(this, name); - this.wingspan = wingspan; -} - -// configure inheritance -extend(Bat, Mammal); - -test("Inheritance", function() { - var lenny = new Bat("Lenny", "1.5m"); - equals(lenny.sayHi(), __, "what does Lenny say?"); - equals(lenny.wingspan, __, "what is Lenny's wingspan?"); -}); diff --git a/topics/13_functions_and_closure.js b/topics/13_functions_and_closure.js new file mode 100644 index 00000000..b5b9758f --- /dev/null +++ b/topics/13_functions_and_closure.js @@ -0,0 +1,35 @@ + +module("About Functions And Closure (topics/13_functions_and_closure.js)"); + +test("defining functions directly", function() { + var result = "a"; + function changeResult() { + // the ability to access a variables defined in the same scope as the function is known as 'closure' + result = "b"; + }; + changeResult(); + equals(result, __, 'what is the value of result?'); +}); + +test("assigning functions to variables", function() { + var triple = function(input) { + return input * 3; + }; + equals(triple(4), __, 'what is triple 4?'); +}); + +test("self invoking functions", function() { + var publicValue = "shared"; + + // self invoking functions are used to provide scoping and to alias variables + (function(pv) { + var secretValue = "password"; + equals(pv, __, 'what is the value of pv?'); + equals(typeof(secretValue), "__", "is secretValue available in this context?"); + equals(typeof(publicValue), "__", "is publicValue available in this context?"); + })(publicValue); + + equals(typeof(secretValue), "__", "is secretValue available in this context?"); + equals(typeof(publicValue), "__", "is publicValue available in this context?"); +}); + diff --git a/topics/about_this.js b/topics/14_this.js similarity index 95% rename from topics/about_this.js rename to topics/14_this.js index cad5546e..303a5def 100644 --- a/topics/about_this.js +++ b/topics/14_this.js @@ -1,4 +1,4 @@ -module("About this (topics/about_this.js)"); +module("About this (topics/14_this.js)"); test("'this' inside a method", function () { var person = { diff --git a/topics/about_regular_expressions.js b/topics/15_regular_expressions.js similarity index 92% rename from topics/about_regular_expressions.js rename to topics/15_regular_expressions.js index 8d409fca..1fcaed63 100644 --- a/topics/about_regular_expressions.js +++ b/topics/15_regular_expressions.js @@ -1,5 +1,5 @@ -module("About Regular Expressions (topics/about_regular_expressions.js)"); +module("About Regular Expressions (topics/15_regular_expressions.js)"); test("exec", function() { var numberFinder = /(\d).*(\d)/; diff --git a/topics/1_operators.js b/topics/1_operators.js new file mode 100644 index 00000000..3483096f --- /dev/null +++ b/topics/1_operators.js @@ -0,0 +1,17 @@ + +module("About Operators (topics/1_operators.js)"); + +test("logic", function(){ + equals(true && true, __, "and"); + equals(true || false, __, "or"); +}); + +test("plus", function() { + // The plus operator works for nearly every datatype. + // But be careful, the results may be strange for everything + // else than strings and numbers. + equals(5+5, __, 'plus with numeric values'); + equals("a" + "string", '__', 'string concatenation'); + // Something unexecpected, better use Array.concat. + equals([1,2] + [3,4], '__', 'plus with arrays'); +}); diff --git a/topics/2_equality.js b/topics/2_equality.js new file mode 100644 index 00000000..7a363d6a --- /dev/null +++ b/topics/2_equality.js @@ -0,0 +1,32 @@ +/* + There are two differant operators to tests for + equality in JavaScript: + 1) ==, != + 2) ===, !== + The first one does type coercion if the operands are + not of the same type. This leads to bugs which are very + hard to find. The rules for the type coercion are complicated + and unmemorable. So always use triple equals instead! +*/ +module("About Equality (topics/2_equality.js)"); + +test("equality without type coercion", function() { + ok(3 === __, 'what is exactly equal to 3?'); +}); + +test("equality with type coercion", function() { + ok(3 == "__", 'what string is equal to 3, with type coercion?'); +}); + +test("why type coercion is bad", function() { + // Can you guess all of them? + equals(0 == '', __); + equals('' == '0', __); + equals(0 == [0], __); + equals(0 == false, __); + equals(',,,' == new Array(4), __); +}); + +test("string literals", function() { + equals("frankenstein", '__', "quote types are interchangable, but must match."); +}); diff --git a/topics/about_truthyness.js b/topics/3_truthyness.js similarity index 90% rename from topics/about_truthyness.js rename to topics/3_truthyness.js index 9c3f2319..c47d6b2c 100644 --- a/topics/about_truthyness.js +++ b/topics/3_truthyness.js @@ -1,5 +1,5 @@ -module("About Truthyness (topics/about_truthyness.js)"); +module("About Truthyness (topics/3_truthyness.js)"); test("truthyness of positive numbers", function() { var oneIsTruthy = 1 ? true : false; diff --git a/topics/4_assignment.js b/topics/4_assignment.js new file mode 100644 index 00000000..d82e742f --- /dev/null +++ b/topics/4_assignment.js @@ -0,0 +1,53 @@ + +module("About Assignment (topics/4_assignment.js)"); + +test("local variables", function() { + var temp = __; + equals(1, temp, "Assign a value to the variable temp"); +}); + +test("no block scope", function() { + // JavaScript has no block scope like Java, but function scope. + // It's best to define all vars at the top of a function to avoid confusion + var isInnerVariableDefined = true; + if(true) { + var innerVariable = 5; + } + try { + innerVariable + } catch(e){ + isInnerVariableDefined = false; + } + equals(isInnerVariableDefined, true, "there is no block scope"); +}); + +test("function scope", function() { + var outerVariable = "outer"; + + // this is a self-invoking function. Notice that it calls itself at the end (). + (function() { + var innerVariable = "inner"; + equals(outerVariable, __, 'is outerVariable defined in this scope?'); + equals(innerVariable, __, 'is innerVariable defined in this scope?'); + })(); + + equals(outerVariable, __, 'is outerVariable defined in this scope?'); + var isInnerVariableDefined = true; + try { + innerVariable + } catch(e) { + isInnerVariableDefined = false; + } + equals(isInnerVariableDefined, __, 'is innerVariable defined in this scope?'); +}); + +temp = 1; +test("global variables", function() { + //If you try to use a variable before declaring it, JavaScript assumes that you + //meant the global context. The top level object is the window object, so your + //variable becomes a property of that object. Most of the time this is not intended + //by the programmer, so they introduced "use strict" in ES5. If you really want + //to make a global var use windows.myVar = value instead, but make sure not to + //override any existing properties! + equals(temp, window.__, 'global variables are assigned to the window object'); +}); diff --git a/topics/about_control_structures.js b/topics/5_control_structures.js similarity index 89% rename from topics/about_control_structures.js rename to topics/5_control_structures.js index 84e1f161..3b2e1230 100644 --- a/topics/about_control_structures.js +++ b/topics/5_control_structures.js @@ -1,5 +1,5 @@ -module("About Control Structures (topics/about_control_structures.js)"); +module("About Control Structures (topics/5_control_structures.js)"); test("if", function() { var isPositive = false; @@ -18,7 +18,7 @@ test("for", function() { }); test("for in", function() { - // this syntax will be explained in about objects + // this syntax will be explained in 8_objects var person = { name: "Amory Blaine", age: 102 @@ -69,6 +69,7 @@ test("switch default case", function() { }); test("null coallescion", function() { + //assigns the first value if it's "truthy", else the second value var result = null || "a value"; equals(result, __, 'what is the value of result?'); }); diff --git a/topics/about_strings.js b/topics/6_strings.js similarity index 64% rename from topics/about_strings.js rename to topics/6_strings.js index 68fa6894..5c08c94c 100644 --- a/topics/about_strings.js +++ b/topics/6_strings.js @@ -1,5 +1,5 @@ -module("About Strings (topics/about_strings.js)"); +module("About Strings (topics/6_strings.js)"); test("delimiters", function() { var singleQuotedString = 'apple'; @@ -18,17 +18,9 @@ test("character Type", function() { equals(characterType, __, 'Javascript has no character type'); }); -test("escape character", function() { - var stringWithAnEscapedCharacter = "\u0041pple"; - equals(stringWithAnEscapedCharacter, __, 'what is the value of stringWithAnEscapedCharacter?'); -}); - test("string.length", function() { var fruit = "apple"; equals(fruit.length, __, 'what is the value of fruit.length?'); }); -test("slice", function() { - var fruit = "apple pie"; - equals(fruit.slice(0,5), __, 'what is the value of fruit.slice(0,5)?'); -}); + diff --git a/topics/about_numbers.js b/topics/7_numbers.js similarity index 91% rename from topics/about_numbers.js rename to topics/7_numbers.js index 672f3318..75f50f05 100644 --- a/topics/about_numbers.js +++ b/topics/7_numbers.js @@ -1,5 +1,5 @@ -module("About Numbers (topics/about_numbers.js)"); +module("About Numbers (topics/7_numbers.js)"); test("types", function() { var typeOfIntegers = typeof(6); diff --git a/topics/about_objects.js b/topics/8_objects.js similarity index 96% rename from topics/about_objects.js rename to topics/8_objects.js index 35185b32..7515af0a 100644 --- a/topics/about_objects.js +++ b/topics/8_objects.js @@ -1,5 +1,5 @@ -module("About Objects (topics/about_objects.js)"); +module("About Objects (topics/8_objects.js)"); test("object type", function() { var empty_object = {}; diff --git a/topics/about_arrays.js b/topics/9_arrays.js similarity index 71% rename from topics/about_arrays.js rename to topics/9_arrays.js index ab74a6c4..6cbc52f1 100644 --- a/topics/about_arrays.js +++ b/topics/9_arrays.js @@ -1,5 +1,5 @@ -module("About Arrays (topics/about_arrays.js)"); +module("About Arrays (topics/9_arrays.js)"); test("array literal syntax and indexing", function() { var favouriteThings = ["cellar door", 42, true]; // note that array elements do not have to be of the same type @@ -17,13 +17,6 @@ test("length", function() { equals(collection.length, __, 'what is the length of the collection array?'); }); -test("splice", function() { - var daysOfWeek = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; - var workingWeek = daysOfWeek.splice(__, __); - ok(workingWeek.equalTo([__]), 'what is the value of workingWeek?'); - ok(daysOfWeek.equalTo([__]), 'what is the value of daysOfWeek?'); -}); - test("stack methods", function() { var stack = []; stack.push("first"); diff --git a/topics/about_assignment.js b/topics/about_assignment.js deleted file mode 100644 index 3b5c9831..00000000 --- a/topics/about_assignment.js +++ /dev/null @@ -1,12 +0,0 @@ - -module("About Assignment (topics/about_assignment.js)"); - -test("local variables", function() { - var temp = __; - equals(1, temp, "Assign a value to the variable temp"); -}); - -test("global variables", function() { - temp = 1; - equals(temp, window.__, 'global variables are assigned to the window object'); -}); diff --git a/topics/about_equality.js b/topics/about_equality.js deleted file mode 100644 index 797a653e..00000000 --- a/topics/about_equality.js +++ /dev/null @@ -1,22 +0,0 @@ - -module("About Equality (topics/about_equality.js)"); - -test("numeric equality", function() { - equals(3 + __, 7, 'hmmmm?'); -}); - -test("string equality", function() { - equals("3" + __, "37", "concatenate the strings"); -}); - -test("equality without type coercion", function() { - ok(3 === __, 'what is exactly equal to 3?'); -}); - -test("equality with type coercion", function() { - ok(3 == "__", 'what string is equal to 3, with type coercion?'); -}); - -test("string literals", function() { - equals("frankenstein", '__', "quote types are interchangable, but must match."); -}); diff --git a/topics/about_functions_and_closure.js b/topics/about_functions_and_closure.js deleted file mode 100644 index ebe69740..00000000 --- a/topics/about_functions_and_closure.js +++ /dev/null @@ -1,75 +0,0 @@ - -module("About Functions And Closure (topics/about_functions_and_closure.js)"); - -test("defining functions directly", function() { - var result = "a"; - function changeResult() { - // the ability to access a variables defined in the same scope as the function is known as 'closure' - result = "b"; - }; - changeResult(); - equals(result, __, 'what is the value of result?'); -}); - -test("assigning functions to variables", function() { - var triple = function(input) { - return input * 3; - }; - equals(triple(4), __, 'what is triple 4?'); -}); - -test("self invoking functions", function() { - var publicValue = "shared"; - - // self invoking functions are used to provide scoping and to alias variables - (function(pv) { - var secretValue = "password"; - equals(pv, __, 'what is the value of pv?'); - equals(typeof(secretValue), "__", "is secretValue available in this context?"); - equals(typeof(publicValue), "__", "is publicValue available in this context?"); - })(publicValue); - - equals(typeof(secretValue), "__", "is secretValue available in this context?"); - equals(typeof(publicValue), "__", "is publicValue available in this context?"); -}); - -test("arguments array", function() { - var add = function() { - var total = 0; - for(var i = 0; i < arguments.length; i++) { - // complete the implementation of this method so that it returns the sum of its arguments - } - // __ - }; - - equals(add(1,2,3,4,5), 15, "add 1,2,3,4,5"); - equals(add(4,7,-2), 9, "add 1,2,3,4,5"); -}); - -test("using call to invoke function",function(){ - var invokee = function( message ){ - return this + message; - }; - - //another way to invoke a function is to use the call function which allows - //you to set the callers "this" context. Call can take any number of arguments: - //the first one is always the context that this should be set to in the called - //function, and the arguments to be sent to the function,multiple arguments are separated by commas. - var result = invokee.call("I am this!", "Where did it come from?"); - - equals(result,__,"what will the value of invokee's this be?"); -}); - -test("using apply to invoke function",function(){ - var invokee = function( message1, message2 ){ - return this + message1 + message2; - }; - - //similar to the call function is the apply function. Apply only has two - //arguments: the first is the context that this should be set to in the called - //function and and array of arguments to be passed into the called function. - var result = invokee.apply("I am this!", ["I am arg1","I am arg2"]); - - equals(result,__,"what will the value of invokee's this be?"); -}); - diff --git a/topics/about_operators.js b/topics/about_operators.js deleted file mode 100644 index 09df716b..00000000 --- a/topics/about_operators.js +++ /dev/null @@ -1,47 +0,0 @@ - -module("About Operators (topics/about_operators.js)"); - -test("addition", function() { - var result = 0; - //starting i at 0, add i to result and increment i by 1 until i is equal to 5 - for (var i = 0; i <= 5; i++) { - result = result + i; - } - equals(result, __, "What is the value of result?"); -}); - -test("assignment addition", function() { - var result = 0; - for (var i = 0; i <=5; i++) { - //the code below is just like saying result = result + i; but is more concise - result += i; - } - equals(result, __, "What is the value of result?"); -}); - -test("subtraction", function() { - var result = 5; - for (var i = 0; i <= 2; i++) { - result = result - i; - } - equals(result, __, "What is the value of result?"); -}); - -test("assignment subtraction", function() { - var result = 5; - for (var i = 0; i <= 2; i++) { - result -= i; - } - equals(result, __, "What is the value of result?"); -}); - -//Assignment operators are available for multiplication and division as well -//let's do one more, the modulo operator, used for showing division remainder - -test("modulus", function() { - var result = 10; - var x = 5; - //again this is exactly the same as result = result % x - result %= x; - equals(result, __, "What is the value of result?"); -}); diff --git a/topics/about_reflection.js b/topics/about_reflection.js deleted file mode 100644 index 30b716c1..00000000 --- a/topics/about_reflection.js +++ /dev/null @@ -1,67 +0,0 @@ -module("About Reflection (topics/about_reflection.js)"); - -var A = function() { - this.aprop = "A"; -}; - -var B = function() { - this.bprop = "B"; -}; - -B.prototype = new A(); - -test("typeof", function() { - equals(typeof({}), __, 'what is the type of an empty object?'); - equals(typeof('apple'), __, 'what is the type of a string?'); - equals(typeof(-5), __, 'what is the type of -5?'); - equals(typeof(false), __, 'what is the type of false?'); -}); - -test("property enumeration", function() { - var keys = []; - var values = []; - var person = {name: 'Amory Blaine', age: 102, unemployed: true}; - for(propertyName in person) { - keys.push(propertyName); - values.push(person[propertyName]); - } - ok(keys.equalTo(['__','__','__']), 'what are the property names of the object?'); - ok(values.equalTo(['__',__,__]), 'what are the property values of the object?'); -}); - -test("hasOwnProperty", function() { - var b = new B(); - - var keys = []; - for (propertyName in b) { - keys.push(propertyName); - } - equals(keys.length, __, 'how many elements are in the keys array?'); - ok(keys.equalTo([__, __]), 'what are the properties of the array?'); - - // hasOwnProperty returns true if the parameter is a property directly on the object, - // but not if it is a property accessible via the prototype chain. - var ownKeys = []; - for(propertyName in b) { - if (b.hasOwnProperty(propertyName)) { - ownKeys.push(propertyName); - } - } - equals(ownKeys.length, __, 'how many elements are in the ownKeys array?'); - ok(ownKeys.equalTo([__, __]), 'what are the own properties of the array?'); -}); - -test("constructor property", function () { - var a = new A(); - var b = new B(); - equals(typeof(a.constructor), __, "what is the type of a's constructor?"); - equals(a.constructor.name, __, "what is the name of a's constructor?"); - equals(b.constructor.name, __, "what is the name of b's constructor?"); -}); - -test("eval", function() { - // eval executes a string - var result = ""; - eval("result = 'apple' + ' ' + 'pie'"); - equals(result, __, 'what is the value of result?'); -}); diff --git a/topics/about_scope.js b/topics/about_scope.js deleted file mode 100644 index 10278fcf..00000000 --- a/topics/about_scope.js +++ /dev/null @@ -1,28 +0,0 @@ - -module("About Scope (topics/about_scope.js)"); - -thisIsAGlobalVariable = 77; - -test("global variables", function() { - equals(thisIsAGlobalVariable, __, 'is thisIsAGlobalVariable defined in this scope?'); -}); - -test("variables declared inside of a function", function() { - var outerVariable = "outer"; - - // this is a self-invoking function. Notice that it calls itself at the end (). - (function() { - var innerVariable = "inner"; - equals(outerVariable, __, 'is outerVariable defined in this scope?'); - equals(innerVariable, __, 'is innerVariable defined in this scope?'); - })(); - - equals(outerVariable, __, 'is outerVariable defined in this scope?'); - var isInnerVariableDefined = true; - try { - innerVariable - } catch(e) { - isInnerVariableDefined = false; - } - equals(isInnerVariableDefined, __, 'is innerVariable defined in this scope?'); -});