Javascript Koans

GY·2021년 5월 30일
0
post-thumbnail

풀이

- 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);
        //woman 과 Woman 대소문자를 구분한다.
      });
    });

    //should know properties that are functions act like methods
    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)
            //join() 메서드는 배열의 모든 요소를 연결해 하나의 문자열로 만듭니다.
          );
        },
      };

      var battleCry = megalomaniac.battleCry(4);
      expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry);
  //왜 Braib을 4번 반복할까?
    });

    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);
      });
      //in keyword

      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");
 //????왜왜???
 //Knowing it should know that variables inside a constructor and constructor args are private has expanded your awareness.

     aPerson.getFullName = function () {
       return aPerson.lastname + ", " + aPerson.firstname;
     };

     expect(aPerson.getFullName()).toBe("Andrews, Penny");
   });
 });
 ```

- Higher Order Function

 ```jsx
 var _; //globals

 /* This section uses a functional extension known as Underscore.js - http://documentcloud.github.com/underscore/
      "Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support
       that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects.
       It's the tie to go along with jQuery's tux."
  */
 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);
   });
   //filter는 조건에 맞는값은 제외한다.

   it("should use 'map' to transform each element", function () {
     var numbers = [1, 2, 3];
     var numbersPlus1 = _(numbers).map(function (x) {
       return x + 1;
     });
     //map은 함수를 호출한 그 결과대로 새로운 배열로 교체한다.
     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 (
       /* result from last call */ memo,
       /* current */ x
     ) {
       return memo + x;
     },
     /* initial */ 0);
     // reduce : 함수 호출하여 더하고, 새로운 하나의 결과값만 반환
     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]);
   });
   /*forEach :배열의 모든 요소를 반복하며 콜백함수를 실행
 //각 요소들이 iseven의 조건에 부합하는지
 어떻게 동작하는지가 잘 이해가 안된다.
   */

   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);
   });
   //onlyeven의 모든 요소가 isEven의 조건에 부합하는지
   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]);
   });
   /*range : 시작숫자와 끝숫자로 연속된 숫자배열을 만들 수 있다.
   3번째 인수는 간격이다. 0부터 -4까지 연속된 숫자배열을 만들되, 간격은 -1인 것이다.
   (1,4) 끝숫자는 포함하지 않는다.[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]);
   });
   //flatten 은 배열을 평평하게 만든다.[1,2,[3]]은 [1,2,3]이 된다.
   it("should use chain() ... .value() to use multiple higher order functions", function () {
     var result = _([[0, 1], 2])
       .chain()
       .flatten()
       .map(function (x) {
   //map: 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환
         return x + 1;
       })
       .reduce(function (sum, x) {
         return sum + x;
       })
       /*
       arr.reduce(callback[,initialValue])
       reduce는 배열의 각 요소에 대해 콜백을 실행하며, 1개의 출력 결과를 만든다.
       배열 원소들의 전체 합을 구하거나 최대값을 구할 수 있다.
       첫번째 인자:reucer함수
       두 번째 인자:초기값initialValue 라는 빈 object
       배열의 각 요소가 주어진 콜백함수를 거친다.(reducer)
       reducer의 네가지 인자
         accumulator(누산기) reducer의 반환 값을 누적한다.
         currengValue:현재 처리할 요소
         currentIndex(생략가능):처리할 현재 요소의 인덱스
         array(생략가능): reduce()를 호출한 배열
         
        */
       .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();
 //prototype은 뭘까??

 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!");
     //call로 불러왔기 때문에, 출력 가능
   });

   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");
   });
 });

 // http://javascript.crockford.com/prototypal.html
 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;
   };
 }

 //no longer need to call the Muppet (base type) constructor
 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);
    });
    //makemysteryfunction의 인자는 makervalue,
    //mysteryfunction의 인자는 param에 들어가는 것 같다.
  //잘 이해가 되지 않는다..
    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(",");
      }
      //[0,1,2,3,4]
      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 () {
   // We shall contemplate truth by testing reality, via spec expectations.
   it("should expect true", function () {
     // Your journey begins here: Replace the word false with true
     expect(true).toBeTruthy();
   });

   // To understand reality, we must compare our expectations against reality.
   it("should expect equality", function () {
     var expectedValue = 2;
     var actualValue = 1 + 1;

     expect(actualValue === expectedValue).toBeTruthy();
   });

   // Some ways of asserting equality are better than others.
   it("should assert equality a better way", function () {
     var expectedValue = 2;
     var actualValue = 1 + 1;

     // toEqual() compares using common sense equality.
     expect(actualValue).toEqual(expectedValue);
   });

   // Sometimes you need to be precise about what you "type."
   it("should assert equality with ===", function () {
     var expectedValue = "2";
     var actualValue = (1 + 1).toString();

     // toBe() will always use === to compare.
     expect(actualValue).toBe(expectedValue);
   });

   // Sometimes we will ask you to fill in the values.
   it("should have filled in values", function () {
     expect(1 + 1).toEqual(2);
   });
 });
 ```

- Array

 ```jsx
 describe("About Arrays", function () {
   //We shall contemplate truth by testing reality, via spec expectations.
   it("should create arrays", function () {
     var emptyArray = [];
     expect(typeof emptyArray).toBe("object"); //A mistake? - http://javascript.crockford.com/remedial.html
     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 _; //globals

 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 = [];

     /* solve using filter() & all() / any() */

     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; /* try chaining range() and reduce() */

     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]] =
           //ingredients배열 전부를 훑는다.
           (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 };
     //이 의미가 뭐지?
     /* chain() together map(), flatten() and reduce() */

     expect(ingredientCount["mushrooms"]).toBe();
   });
   //이게 이해가 안돼... 뭐가 다르다는 거지?
   /*********************************************************************************/
   /* UNCOMMENT FOR EXTRA CREDIT */
   /*
   it("should find the largest prime factor of a composite number", function () {

   });

   it("should find the largest palindrome made from the product of two 3 digit numbers", function () {

   });

   it("should find the smallest number divisible by each of the numbers 1 to 20", function () {

   });

   it("should find the difference between the sum of the squares and the square of the sums", function () {

   });

   it("should find the 10001st prime", function () {

   });
   */
 });
profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글