Javascript

koan 풀기

big whale 2021. 6. 6. 22:16

koan은 자바스크립트 기본 프로그래밍을 퀴즈 형식의 문제를 풀며 이해하는 방식으로 진행된다.

https://github.com/mrdavidlaing/javascript-koans

 

mrdavidlaing/javascript-koans

Koans to learn Javascript. Contribute to mrdavidlaing/javascript-koans development by creating an account on GitHub.

github.com

 

1. Thinking About Expects

등호를 배워보자

10=='10': a와 b의 값이 같다.

10===10: a와b는 값에다가 데이터 타입까지 같다.

 

2. Thinking About Arrays

배열을 배워보자

하나의 배열에는 여러 타입의 원소가 들어갈 수 있다. ( 값,함수,문자열,객체,배열 등등)

array.push(a): array의 마지막에 새로운 원소로 a를 추가한다.

array.push(a,b): a와 b는 각각 array의 새로운 원소이며 인덱스가 +2 된다.

var emptyArray = new Array(10): 길이가 10인 배열 emptyArray 생성 방법

array.slice(a,b): array의 a번째 인덱스 원소부터 b-1번째 원소까지를 잘라서 새로운 배열로 리턴한다.

array.pop(): array의 마지막 원소를 삭제하고 이를 리턴한다.

array.unshift(a): array의 맨 처음에 a를 넣고 새로운 배열의 길이를 리턴한다.

 

3. Thinking About Functions

함수를 배워보자

 

var variable = "top-level";

function parentfunction() {
  var variable = "local";
  function childfunction() {
    return variable;
  }
  return childfunction();
}
    

--> 전역변수 variable과 parentfunction함수 내에 지역변수 variable 이 있다.

parentfunction함수 내의 childfunction함수는 variable변수를 리턴하는데 이 값은 지역변수 variable이다. 

 

 

    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 firstArg(first)는 firstArg(a,b,c);를 했을 때 a만을 인자로 갖는다.

인자가 정해지지 않은 함수 function returnAllArgs()는 returnAllArgs(a,b,c);를 했을 때 a,b,c 모두 인자로 갖는다.

 

 

    var appendRules = function (name) {
      return name + " rules!";
    };

    var praiseSinger = { givePraise: appendRules };
    expect(praiseSinger.givePraise("John")).toBe('John rules!');

--> 함수를 변수에 저장하면 변수명을 가지고도 이용할 수 있다.

 

4. Thinking About Objects

객체를 배워보자

    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(battleCry).toMatch('They are Pinky and the Brain');

--> megalomaniac 객체는 mastermind, henchman, battleCry 프로퍼티를 가지고 있고 이중 battleCry는 함수이다.

객체 내 함수는 객체가 가지고 있는 변수를 사용하고 싶을 때 this.변수명으로 사용할 수 있다.

 

    var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in megalomaniac).toBe(false);

    megalomaniac.secretary = "Agent Smith";
    expect("secretary" in megalomaniac).toBe(true);

--> 이미 만들어진 객체에도 프로퍼티를 추가할 수 있다.

 

 

      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');

 --> 모든 객체에 적용하고 싶다면 prototype에다가 넣어라.

 

5. Think About Mutability

    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe('Alan');

--> 객체의 프로퍼티는 public,mutable 라서 값을 바꿀 수 있다.

 

    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에 firstname이라는 변수가 들어갔고 인자firstname이랑은 다르다.
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe('John');
    expect(aPerson.getLastName()).toBe('Smith');
    expect(aPerson.getFullName()).toBe('John Smith');
    console.log(aPerson);
    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe('Andrews, Penny');

--> 구조체 내부 변수와 구조체 인자는 private이다. aPerson.fullName과 aPerson.getFullName()의 값은 다르다.

 

6. Thinking About Higher Order Functions

filter, map, reduce, forEach, all, any, range, flatten, chain, value

 

1. filter

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

--> numbers배열 안의 모든 원소에 대해서 return값이 true인 원소만을 odd에 저장한다.

 

2. map

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

--> numbers배열 안의 모든 원소에 x+1을 적용한 값을 numbersPlus1에 저장한다.

 

3. reduce

function () {
    var numbers = [1, 2, 3];
    var reduction = _(numbers).reduce(
            function(/* result from last call */ memo, /* current */ x) { return memo + x }, /* initial */ 0); // 배열.reduce((누적값,현재값,인덱스) => {return 결과}, 초기값);

    expect(reduction).toBe(6);
    expect(numbers).toEqual([1,2,3]);
}

-->reduce는 배열 내의 모든 원소의 합을 구할때 자주 쓰이며, reduce(function(누적값,더할값) {return 누적값+더할값},0) 의 문법을 따른다.0은 누적값의 초기값이다.

 

4. forEach

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(function)는 원소 각각에 특정 함수를 적용할때 쓰인다.

 

7. Thinking About Inheritance

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();

function() {
  beforeEach(function(){
    this.muppet = new Muppet(2, "coding");
	this.swedishChef = new SwedishChef(2, "cooking", "chillin");
}

expect(this.swedishChef.cook()).toEqual('Mmmm soup!');
expect(this.swedishChef.answerNanny()).toEqual("Everything's cool!");

--> SwedishChef.prototype = new Muppet();을 통해서 상속이 일어났고 swedishChef는 answerNanny 프로퍼티를 사용할 수 있게 된다.

 

8. Thinking About Applying What We Have Learnt

지금까지 배운 기본 개념을 써먹어보자.

    var sum = 0; 
    var numArr = _.range(1000).filter(function(x) {if (x%3===0 || x%5===0) {return x; }})
    sum = numArr.reduce(function(accum,curr) {return accum+curr},0);
    
    console.log(sum);
    expect(233168).toBe(sum);

--> range(1000)으로 0부터 999까지 만든 다음 3이나 5로 나눠지는 수만 numArr에 넣는다. reduce를 이용해서 그 숫ㅈ들을 다 더한다.

 

  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 }
    ];
  }

function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i++) {
        for (j = 0; j < products[i].ingredients.length; j++) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }
    console.log(ingredientCount);
    expect(ingredientCount['mushrooms']).toBe(2);
}

--> product 배열은 음식 객체가 원소로 이루어져 있고, 함수는 이 음식에 어떤 재료가 몇번 들어갔는지 알아내는 함수이다. 

객체의 길이로 for문을 돌리고 그 안에서 ingredient의 길이로 for문을 돌려서 ingredientCount객체에 성분명과 개수를 삽입하는 과정을 거친다.

 

배열과 객체를 사용해서 코드 작성하는 법을 배웠는데 아직 어떤 작성법이 더 좋은지를 모르기 때문에 좋은게 맞나 하는 생각이 든다. 객체, 메서드, this가 어려운 것 같아서 여러번 봐야겠다.