풀이
- Objects
describe("About Objects", function () {
describe("Properties", function () {
var megalomaniac;
beforeEach(function () {
megalomaniac = { mastermind: "Joker", henchwoman: "Harley" };
});
it("should confirm objects are collections of properties", function () {
expect(megalomaniac.mastermind).toBe("Joker");
});
it("should confirm that properties are case sensitive", function () {
expect(megalomaniac.henchwoman).toBe("Harley");
expect(megalomaniac.henchWoman).toBe(undefined);
});
});
it("should know properties that are functions act like methods", function () {
var megalomaniac = {
mastermind: "Brain",
henchman: "Pinky",
battleCry: function (noOfBrains) {
return (
"They are " +
this.henchman +
" and the" +
Array(noOfBrains + 1).join(" " + this.mastermind)
);
},
};
var battleCry = megalomaniac.battleCry(4);
expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry);
});
it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
var currentDate = new Date();
var currentYear = currentDate.getFullYear();
var megalomaniac = {
mastermind: "James Wood",
henchman: "Adam West",
birthYear: 1970,
calculateAge: function () {
return currentYear - this.birthYear;
},
};
expect(currentYear).toBe(2021);
expect(megalomaniac.calculateAge()).toBe(51);
});
describe("'in' keyword", function () {
var megalomaniac;
beforeEach(function () {
megalomaniac = {
mastermind: "The Monarch",
henchwoman: "Dr Girlfriend",
theBomb: true,
};
});
it("should have the bomb", function () {
var hasBomb = "theBomb" in megalomaniac;
expect(hasBomb).toBe(true);
});
it("should not have the detonator however", function () {
var hasDetonator = "theDetonator" in megalomaniac;
expect(hasDetonator).toBe(false);
});
});
it("should know that properties can be added and deleted", function () {
var megalomaniac = { mastermind: "Agent Smith", henchman: "Agent Smith" };
expect("secretary" in megalomaniac).toBe(false);
megalomaniac.secretary = "Agent Smith";
expect("secretary" in megalomaniac).toBe(true);
delete megalomaniac.henchman;
expect("henchman" in megalomaniac).toBe(false);
});
it("should use prototype to add to all objects", function () {
function Circle(radius) {
this.radius = radius;
}
var simpleCircle = new Circle(10);
var colouredCircle = new Circle(5);
colouredCircle.colour = "red";
expect(simpleCircle.colour).toBe(undefined);
expect(colouredCircle.colour).toBe("red");
Circle.prototype.describe = function () {
return "This circle has a radius of: " + this.radius;
};
expect(simpleCircle.describe()).toBe("This circle has a radius of: 10");
expect(colouredCircle.describe()).toBe("This circle has a radius of: 5");
});
});
- Mutability
describe("About Mutability", function () {
it("should expect object properties to be public and mutable", function () {
var aPerson = { firstname: "John", lastname: "Smith" };
aPerson.firstname = "Alan";
expect(aPerson.firstname).toBe("Alan");
});
it("should understand that constructed properties are public and mutable", function () {
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
var aPerson = new Person("John", "Smith");
aPerson.firstname = "Alan";
expect(aPerson.firstname).toBe("Alan");
});
it("should expect prototype properties to be public and mutable", function () {
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
Person.prototype.getFullName = function () {
return this.firstname + " " + this.lastname;
};
var aPerson = new Person("John", "Smith");
expect(aPerson.getFullName()).toBe("John Smith");
aPerson.getFullName = function () {
return this.lastname + ", " + this.firstname;
};
expect(aPerson.getFullName()).toBe("Smith, John");
});
it("should know that variables inside a constructor and constructor args are private", function () {
function Person(firstname, lastname) {
var fullName = firstname + " " + lastname;
this.getFirstName = function () {
return firstname;
};
this.getLastName = function () {
return lastname;
};
this.getFullName = function () {
return fullName;
};
}
var aPerson = new Person("John", "Smith");
aPerson.firstname = "Penny";
aPerson.lastname = "Andrews";
aPerson.fullName = "Penny Andrews";
expect(aPerson.getFirstName()).toBe("John");
expect(aPerson.getLastName()).toBe("Smith");
expect(aPerson.getFullName()).toBe("John Smith");
aPerson.getFullName = function () {
return aPerson.lastname + ", " + aPerson.firstname;
};
expect(aPerson.getFullName()).toBe("Andrews, Penny");
});
});
```
- Higher Order Function
```jsx
var _;
describe("About Higher Order Functions", function () {
it("should use filter to return array items that meet a criteria", function () {
var numbers = [1, 2, 3];
var odd = _(numbers).filter(function (x) {
return x % 2 !== 0;
});
expect(odd).toEqual([1, 3]);
expect(odd.length).toBe(2);
expect(numbers.length).toBe(3);
});
it("should use 'map' to transform each element", function () {
var numbers = [1, 2, 3];
var numbersPlus1 = _(numbers).map(function (x) {
return x + 1;
});
expect(numbersPlus1).toEqual([2, 3, 4]);
expect(numbers).toEqual([1, 2, 3]);
});
it("should use 'reduce' to update the same result on each iteration", function () {
var numbers = [1, 2, 3];
var reduction = _(numbers).reduce(function (
memo,
x
) {
return memo + x;
},
0);
expect(reduction).toBe(6);
expect(numbers).toEqual([1, 2, 3]);
});
it("should use 'forEach' for simple iteration", function () {
var numbers = [1, 2, 3];
var msg = "";
var isEven = function (item) {
msg += item % 2 === 0;
};
_(numbers).forEach(isEven);
expect(msg).toEqual("falsetruefalse");
expect(numbers).toEqual([1, 2, 3]);
});
it("should use 'all' to test whether all items pass condition", function () {
var onlyEven = [2, 4, 6];
var mixedBag = [2, 4, 5, 6];
var isEven = function (x) {
return x % 2 === 0;
};
expect(_(onlyEven).all(isEven)).toBe(true);
expect(_(mixedBag).all(isEven)).toBe(false);
});
it("should use 'any' to test if any items passes condition", function () {
var onlyEven = [2, 4, 6];
var mixedBag = [2, 4, 5, 6];
var isEven = function (x) {
return x % 2 === 0;
};
expect(_(onlyEven).any(isEven)).toBe(true);
expect(_(mixedBag).any(isEven)).toBe(true);
});
it("should use range to generate an array", function () {
expect(_.range(3)).toEqual([0, 1, 2]);
expect(_.range(1, 4)).toEqual([1, 2, 3]);
expect(_.range(0, -4, -1)).toEqual([0, -1, -2, -3]);
});
it("should use flatten to make nested arrays easy to work with", function () {
expect(
_([
[1, 2],
[3, 4],
]).flatten()
).toEqual([1, 2, 3, 4]);
});
it("should use chain() ... .value() to use multiple higher order functions", function () {
var result = _([[0, 1], 2])
.chain()
.flatten()
.map(function (x) {
return x + 1;
})
.reduce(function (sum, x) {
return sum + x;
})
.value();
expect(result).toEqual(6);
});
});
```
### - Inheritance
```jsx
function Muppet(age, hobby) {
this.age = age;
this.hobby = hobby;
this.answerNanny = function () {
return "Everything's cool!";
};
}
function SwedishChef(age, hobby, mood) {
Muppet.call(this, age, hobby);
this.mood = mood;
this.cook = function () {
return "Mmmm soup!";
};
}
SwedishChef.prototype = new Muppet();
describe("About inheritance", function () {
beforeEach(function () {
this.muppet = new Muppet(2, "coding");
this.swedishChef = new SwedishChef(2, "cooking", "chillin");
});
it("should be able to call a method on the derived object", function () {
expect(this.swedishChef.cook()).toEqual("Mmmm soup!");
});
it("should be able to call a method on the base object", function () {
expect(this.swedishChef.answerNanny()).toEqual("Everything's cool!");
});
it("should set constructor parameters on the base object", function () {
expect(this.swedishChef.age).toEqual(2);
expect(this.swedishChef.hobby).toEqual("cooking");
});
it("should set constructor parameters on the derived object", function () {
expect(this.swedishChef.mood).toEqual("chillin");
});
});
Object.prototype.beget = function () {
function F() {}
F.prototype = this;
return new F();
};
function Gonzo(age, hobby, trick) {
Muppet.call(this, age, hobby);
this.trick = trick;
this.doTrick = function () {
return this.trick;
};
}
Gonzo.prototype = Muppet.prototype.beget();
describe("About Crockford's inheritance improvement", function () {
beforeEach(function () {
this.gonzo = new Gonzo(3, "daredevil performer", "eat a tire");
});
it("should be able to call a method on the derived object", function () {
expect(this.gonzo.doTrick()).toEqual("eat a tire");
});
it("should be able to call a method on the base object", function () {
expect(this.gonzo.answerNanny()).toEqual("Everything's cool!");
});
it("should set constructor parameters on the base object", function () {
expect(this.gonzo.age).toEqual(3);
expect(this.gonzo.hobby).toEqual("daredevil performer");
});
it("should set constructor parameters on the derived object", function () {
expect(this.gonzo.trick).toEqual("eat a tire");
});
});
- Functions
describe("About Functions", function () {
it("should declare functions", function () {
function add(a, b) {
return a + b;
}
expect(add(1, 2)).toBe(3);
});
it("should know internal variables override outer variables", function () {
var message = "Outer";
function getMessage() {
return message;
}
function overrideMessage() {
var message = "Inner";
return message;
}
expect(getMessage()).toBe("Outer");
expect(overrideMessage()).toBe("Inner");
expect(message).toBe("Outer");
});
it("should have lexical scoping", function () {
var variable = "top-level";
function parentfunction() {
var variable = "local";
function childfunction() {
return variable;
}
return childfunction();
}
expect(parentfunction()).toBe("local");
});
it("should use lexical scoping to synthesise functions", function () {
function makeMysteryFunction(makerValue) {
var newFunction = function doMysteriousThing(param) {
return makerValue + param;
};
return newFunction;
}
var mysteryFunction3 = makeMysteryFunction(3);
var mysteryFunction5 = makeMysteryFunction(5);
expect(mysteryFunction3(10) + mysteryFunction5(5)).toBe(23);
});
it("should allow extra function arguments", function () {
function returnFirstArg(firstArg) {
return firstArg;
}
expect(returnFirstArg("first", "second", "third")).toBe("first");
function returnSecondArg(firstArg, secondArg) {
return secondArg;
}
expect(returnSecondArg("only give first arg")).toBe(undefined);
function returnAllArgs() {
var argsArray = [];
for (var i = 0; i < arguments.length; i += 1) {
argsArray.push(arguments[i]);
}
return argsArray.join(",");
}
expect(returnAllArgs("first", "second", "third")).toBe(
"first,second,third"
);
});
it("should pass functions as values", function () {
var appendRules = function (name) {
return name + " rules!";
};
var appendDoubleRules = function (name) {
return name + " totally rules!";
};
var praiseSinger = { givePraise: appendRules };
expect(praiseSinger.givePraise("John")).toBe("John rules!");
praiseSinger.givePraise = appendDoubleRules;
expect(praiseSinger.givePraise("Mary")).toBe("Mary totally rules!");
});
});
- Expects
describe("About Expects", function () {
it("should expect true", function () {
expect(true).toBeTruthy();
});
it("should expect equality", function () {
var expectedValue = 2;
var actualValue = 1 + 1;
expect(actualValue === expectedValue).toBeTruthy();
});
it("should assert equality a better way", function () {
var expectedValue = 2;
var actualValue = 1 + 1;
expect(actualValue).toEqual(expectedValue);
});
it("should assert equality with ===", function () {
var expectedValue = "2";
var actualValue = (1 + 1).toString();
expect(actualValue).toBe(expectedValue);
});
it("should have filled in values", function () {
expect(1 + 1).toEqual(2);
});
});
```
- Array
```jsx
describe("About Arrays", function () {
it("should create arrays", function () {
var emptyArray = [];
expect(typeof emptyArray).toBe("object");
expect(emptyArray.length).toBe(0);
var multiTypeArray = [
0,
1,
"two",
function () {
return 3;
},
{ value1: 4, value2: 5 },
[6, 7],
];
expect(multiTypeArray[0]).toBe(0);
expect(multiTypeArray[2]).toBe("two");
expect(multiTypeArray[3]()).toBe(3);
expect(multiTypeArray[4].value1).toBe(4);
expect(multiTypeArray[4]["value2"]).toBe(5);
expect(multiTypeArray[5][0]).toBe(6);
});
it("should understand array literals", function () {
var array = [];
expect(array).toEqual([]);
array[0] = 1;
expect(array).toEqual([1]);
array[1] = 2;
expect(array).toEqual([1, 2]);
array.push(3);
expect(array).toEqual([1,2,3]);
});
it("should understand array length", function () {
var fourNumberArray = [1, 2, 3, 4];
expect(fourNumberArray.length).toBe(4);
fourNumberArray.push(5, 6);
expect(fourNumberArray.length).toBe(6);
var tenEmptyElementArray = new Array(10);
expect(tenEmptyElementArray.length).toBe(10);
tenEmptyElementArray.length = 5;
expect(tenEmptyElementArray.length).toBe(5);
});
it("should slice arrays", function () {
var array = ["peanut", "butter", "and", "jelly"];
expect(array.slice(0, 1)).toEqual(FILL_ME_IN);
expect(array.slice(0, 2)).toEqual(FILL_ME_IN);
expect(array.slice(2, 2)).toEqual(FILL_ME_IN);
expect(array.slice(2, 20)).toEqual(FILL_ME_IN);
expect(array.slice(3, 0)).toEqual(FILL_ME_IN);
expect(array.slice(3, 100)).toEqual(FILL_ME_IN);
expect(array.slice(5, 1)).toEqual(FILL_ME_IN);
});
it("should know array references", function () {
var array = ["zero", "one", "two", "three", "four", "five"];
function passedByReference(refArray) {
refArray[1] = "changed in function";
}
passedByReference(array);
expect(array[1]).toBe(FILL_ME_IN);
var assignedArray = array;
assignedArray[5] = "changed in assignedArray";
expect(array[5]).toBe(FILL_ME_IN);
var copyOfArray = array.slice();
copyOfArray[3] = "changed in copyOfArray";
expect(array[3]).toBe(FILL_ME_IN);
});
it("should push and pop", function () {
var array = [1, 2];
array.push(3);
expect(array).toEqual(1, 2, 3);
var poppedValue = array.pop();
expect(poppedValue).toBe(3);
expect(array).toEqual(1, 2);
});
it("should know about shifting arrays", function () {
var array = [1, 2];
array.unshift(3);
expect(array).toEqual(FILL_ME_IN);
var shiftedValue = array.shift();
expect(shiftedValue).toEqual(FILL_ME_IN);
expect(array).toEqual(FILL_ME_IN);
});
});
- Applying What We Have Learnt
var _;
describe("About Applying What We Have Learnt", function () {
var products;
beforeEach(function () {
products = [
{
name: "Sonoma",
ingredients: ["artichoke", "sundried tomatoes", "mushrooms"],
containsNuts: false,
},
{
name: "Pizza Primavera",
ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"],
containsNuts: false,
},
{
name: "South Of The Border",
ingredients: ["black beans", "jalapenos", "mushrooms"],
containsNuts: false,
},
{
name: "Blue Moon",
ingredients: ["blue cheese", "garlic", "walnuts"],
containsNuts: true,
},
{
name: "Taste Of Athens",
ingredients: ["spinach", "kalamata olives", "sesame seeds"],
containsNuts: true,
},
];
});
it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {
var i,
j,
hasMushrooms,
productsICanEat = [];
for (i = 0; i < products.length; i += 1) {
if (products[i].containsNuts === false) {
hasMushrooms = false;
for (j = 0; j < products[i].ingredients.length; j += 1) {
if (products[i].ingredients[j] === "mushrooms") {
hasMushrooms = true;
}
}
if (!hasMushrooms) productsICanEat.push(products[i]);
}
}
expect(productsICanEat.length).toBe(1);
});
it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {
var productsICanEat = [];
expect(productsICanEat.length).toBe(0);
});
it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {
var sum = 0;
for (var i = 1; i < 1000; i += 1) {
if (i % 3 === 0 || i % 5 === 0) {
sum += i;
}
}
expect(sum).toBe(233168);
});
it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {
var sum = 233168;
expect(233168).toBe(233168);
});
it("should count the ingredient occurrence (imperative)", function () {
var ingredientCount = { "{ingredient name}": 0 };
for (i = 0; i < products.length; i += 1) {
for (j = 0; j < products[i].ingredients.length; j += 1) {
ingredientCount[products[i].ingredients[j]] =
(ingredientCount[products[i].ingredients[j]] || 0) + 1;
}
}
expect(ingredientCount["mushrooms"]).toBe(2);
});
it("should count the ingredient occurrence (functional)", function () {
var ingredientCount = { "{ingredient name}": 0 };
expect(ingredientCount["mushrooms"]).toBe();
});
});