[C/F TIL] 15일차 - JavaScript Koans 문제풀이

mu-eng·2023년 5월 1일
1

TIL (in boost camp)

목록 보기
17/53
post-thumbnail

Code States
Front-end boost camp
Today
I
Learned

🍀 5월의 첫날~ 15일차 리뷰 시자쿠


🍀 JavaScript Koans 문제풀이

✔️ 01. Introduction

describe('expect에 대해서 학습합니다.', function () {
  
  it('테스트하는 값(expect의 전달인자)이 true인지의 여부를 검사합니다.', function () {
    expect(true).to.be.true;
  });

  it('테스트하는 값(expect의 전달인자)이 falsy 여부를 검사합니다.', function () {
    expect(false).to.be.false;
  });
  
  it("'테스트하는 값'을 '기대하는 값'과 비교한 결과가 참 인지 확인합니다.", function () {
    let actualValue = 1 + 1;
    let expectedValue = 2;
    expect(actualValue === expectedValue).to.be.true;
  });

  it('Matcher .equal 의 사용법을 학습합니다.', function () {
    let expectedValue = 1 + 1;
    expect(1 + 1).to.equal(expectedValue);
  });

  it('Matcher .equal의 사용법을 학습합니다.', function () {
    let actualValue = (1 + 1).toString();
    expect(actualValue).to.equal('2');
  });
});

✔️ 02. Type

describe('type에 대해서 학습합니다.', function () {
  it("비교연산자 '=='는 두 값의 일치 여부를 느슨하게 검사(loose equality)합니다.", function () {
    let actualValue = 1 + 1;
    let expectedValue = 1 + 1;
    expect(actualValue == expectedValue).to.be.true;

  it("비교연산자 '==='는 두 값의 일치 여부를 엄격하게 검사(strict equality)합니다.", function () {
    let actualValue = 1 + 1;
    let expectedValue = 2;
    expect(actualValue === expectedValue).to.be.true;
  });

  it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
    expect(1 + '1').to.equal(1 + '1');
  });

  it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
    expect(123 - '1').to.equal(123 - '1');
  });

  it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
    expect(1 + true).to.equal(1 + true);
  });

  it('expect의 전달인자로 들어간 표현식의 평가(evaluation) 결과를 예측해 봅니다.', function () {
    expect('1' + true).to.equal('1' + true);
  });

✔️ 03. LetConst

describe("'const'에 대해서 학습합니다.", function () {
    const constNum = 0;
    expect(constNum).to.equal(0);

    const constString = 'I am a const';
    expect(constString).to.equal('I am a const');
  });

  it("'const'로 선언된 배열의 경우 새로운 요소를 추가하거나 삭제할 수 있습니다.", function () {
    const arr = [];
    const toBePushed = 42;
    arr.push(toBePushed);
    expect(arr[0]).to.equal(42);
  });

  it("'const'로 선언된 객체의 경우, 속성을 추가하거나 삭제할 수 있습니다.", function () {
    const obj = { x: 1 };
    expect(obj.x).to.equal(1);

    delete obj.x;
    expect(obj.x).to.equal(undefined);

    obj.occupation = 'SW Engineer';
    expect(obj['occupation']).to.equal('SW Engineer');
  });

✔️ 04. Scope

describe('scope 대해서 학습합니다.', function () {
  it('함수 선언식(declaration)과 함수 표현식(expression)의 차이를 확인합니다.', function () {
    let funcExpressed = 'to be a function';

    expect(typeof funcDeclared).to.equal('function');
    expect(typeof funcExpressed).to.equal('string');

    function funcDeclared() {
      return 'this is a function declaration';
    }

    funcExpressed = function () {
      return 'this is a function expression';
    };

    const funcContainer = { func: funcExpressed };
    expect(funcContainer.func()).to.equal('this is a function expression');

    funcContainer.func = funcDeclared;
    expect(funcContainer.func()).to.equal('this is a function declaration');
  });

  
  it('lexical scope에 대해서 확인합니다.', function () {
    let message = 'Outer';

    function getMessage() {
      return message;
    }

    function shadowGlobal() {
      let message = 'Inner';
      return message;
    }

    function shadowGlobal2(message) {
      return message;
    }

    function shadowParameter(message) {
      message = 'Do not use parameters like this!';
      return message;
    }

    expect(getMessage()).to.equal(message);
    expect(shadowGlobal()).to.equal('Inner');
    expect(shadowGlobal2('Parameter')).to.equal('Parameter');
    expect(shadowParameter('Parameter')).to.equal('Do not use parameters like this!');
    expect(message).to.equal(message);
  });

  
  it('default parameter에 대해 확인합니다.', function () {
    function defaultParameter(num = 5) {
      return num;
    }

    expect(defaultParameter()).to.equal(5);
    expect(defaultParameter(10)).to.equal(10);

    function pushNum(num, arr = []) {
      arr.push(num);
      return arr;
    }

    expect(pushNum(10)).to.deep.equal([10]);
    expect(pushNum(20)).to.deep.equal([20]);
    expect(pushNum(4, [1, 2, 3])).to.deep.equal([1, 2, 3, 4]);
  });

  
  it('클로저(closure)에 대해 확인합니다.', function () {
    function increaseBy(increaseByAmount) {
      return function (numberToIncrease) {
        return numberToIncrease + increaseByAmount;
      };
    }

    const increaseBy3 = increaseBy(3);
    const increaseBy5 = increaseBy(5);

    expect(increaseBy3(10)).to.equal(13);
    expect(increaseBy5(10)).to.equal(15);
    expect(increaseBy(8)(6) + increaseBy(5)(9)).to.equal(28);
  });

  
  it('lexical scope와 closure에 대해 다시 확인합니다.', function () {
    let age = 27;
    let name = 'jin';
    let height = 179;

    function outerFn() {
      let age = 24;
      name = 'jimin';
      let height = 178;

      function innerFn() {
        age = 26;
        let name = 'suga';
        return height;
      }

      innerFn();

      expect(age).to.equal(26);
      expect(name).to.equal('jimin');

      return innerFn;
    }

    const innerFn = outerFn();

    expect(age).to.equal(27);
    expect(name).to.equal('jimin');
    expect(innerFn()).to.equal(178);
  });
});

✔️ 06. ArrowFunction

describe('화살표 함수에 관해서', function () {
  it('함수 표현식 사용법을 복습합니다', function () {
    const add = function (x, y) {
      return x + y
    }

    expect(add(5, 8)).to.eql(13)
  })

  
  it('화살표 함수 사용법을 익힙니다', function () {
    // function 키워드를 생략하고 화살표 => 를 붙입니다
    const add = (x, y) => {
      return x + y
    }
    expect(add(10, 20)).to.eql(30)

    // 리턴을 생략할 수 있습니다
    const subtract = (x, y) => x - y
    expect(subtract(10, 20)).to.eql(-10)

    // 필요에 따라 소괄호를 붙일 수도 있습니다
    const multiply = (x, y) => (x * y)
    expect(multiply(10, 20)).to.eql(200)

    // 파라미터가 하나일 경우 소괄호 생략이 가능합니다
    const divideBy10 = x => x / 10
    expect(divideBy10(100)).to.eql(10)
  })

  
  it('화살표 함수를 이용해 클로저를 표현합니다', function () {
    const adder = x => {
      return y => {
        return x + y
      }
    }

    expect(adder(50)(10)).to.eql(60)

    const subtractor = x => y => {
      return x - y
    }

    expect(subtractor(50)(10)).to.eql(40)

    const htmlMaker = tag => textContent => `<${tag}>${textContent}</${tag}>`
    expect(htmlMaker('div')('code states')).to.eql('<div>code states</div>')

    const liMaker = htmlMaker('li')
    expect(liMaker('1st item')).to.eql('<li>1st item</li>')
    expect(liMaker('2nd item')).to.eql('<li>2nd item</li>')
  })
})

✔️ 07. Array



  it('원시 자료형은 값 자체에 대한 변경이 불가능(immutable)합니다.', function () {
    let name = 'codestates';
    expect(name).to.equal('codestates');
    expect(name.toUpperCase()).to.equal('CODESTATES');
    expect(name).to.equal('codestates');
    // 새로운 값으로 재할당은 가능합니다.
    name = name.toUpperCase();
    expect(name).to.equal('CODESTATES');
  });


  it('원시 자료형을 변수에 할당할 경우, 값 자체의 복사가 일어납니다.', function () {
    let overTwenty = true;
    let allowedToDrink = overTwenty;

    overTwenty = false;
    expect(overTwenty).to.equal(false);
    expect(allowedToDrink).to.equal(true);

    let variable = 'variable';
    let variableCopy = 'variableCopy';
    variableCopy = variable;
    variable = variableCopy;
    expect(variable).to.equal('variable');
  });


  it('원시 자료형 또는 원시 자료형의 데이터를 함수의 전달인자로 전달할 경우, 값 자체의 복사가 일어납니다.', function () {
    let currentYear = 2020;
    function afterTenYears(year) {
      year = year + 10;
    }
    afterTenYears(currentYear);
    expect(currentYear).to.equal(2020);
    function afterTenYears2(currentYear) {
      currentYear = currentYear + 10;
      return currentYear;
    }
    let after10 = afterTenYears2(currentYear);
    expect(currentYear).to.equal(2020);
    expect(after10).to.equal(2030);
  });


  it('참조 자료형의 데이터는 동적(dynamic)으로 변합니다.', function () {
    const arr = [1, 2, 3];
    expect(arr.length).to.equal(3);
    arr.push(4, 5, 6);
    expect(arr.length).to.equal(6);
    arr.pop();
    expect(arr.length).to.equal(5);

    const obj = {};
    expect(Object.keys(obj).length).to.equal(0);
    obj['name'] = 'codestates';
    obj.quality = 'best';
    obj.product = ['sw engineering', 'product manager', 'growth marketing', 'data science'];
    expect(Object.keys(obj).length).to.equal(3);
    delete obj.name;
    expect(Object.keys(obj).length).to.equal(2);
  });

  it('참조 자료형을 변수에 할당할 경우, 데이터의 주소가 저장됩니다.', function () {
    const overTwenty = ['hongsik', 'minchul', 'hoyong'];
    let allowedToDrink = overTwenty;

    overTwenty.push('san');
    expect(allowedToDrink).to.deep.equal(['hongsik', 'minchul', 'hoyong', 'san']);
    overTwenty[1] = 'chanyoung';
    expect(allowedToDrink[1]).to.deep.equal('chanyoung');

    const ages = [22, 23, 27];
    allowedToDrink = ages;
    expect(allowedToDrink === ages).to.equal(true);
    expect(allowedToDrink === [22, 23, 27]).to.equal(false);

    const nums1 = [1, 2, 3];
    const nums2 = [1, 2, 3];
    expect(nums1 === nums2).to.equal(false);

    const person = {
      son: {
        age: 9,
      },
    };

    const boy = person.son;
    boy.age = 20;
    expect(person.son.age).to.equal(20);
    expect(person.son === boy).to.equal(true);
    expect(person.son === { age: 9 }).to.equal(false);
    expect(person.son === { age: 20 }).to.equal(false);
  });
});

✔️ 08. Object

describe('Object에 대해서 학습합니다.', function () {

  it('Object의 기본을 확인합니다.', function () {
    const emptyObj = {};
    expect(typeof emptyObj === 'object').to.equal(true);
    expect(emptyObj.length).to.equal(undefined);

    const megalomaniac = {
      mastermind: 'Joker',
      henchwoman: 'Harley',
      getMembers: function () {
        return [this.mastermind, this.henchwoman];
      },
      relations: ['Anarky', 'Duela Dent', 'Lucy'],
      twins: {
        'Jared Leto': 'Suicide Squad',
        'Joaquin Phoenix': 'Joker',
        'Heath Ledger': 'The Dark Knight',
        'Jack Nicholson': 'Tim Burton Batman',
      },
    };

    expect(megalomaniac.length).to.equal(undefined); // https://developer-talk.tistory.com/813
    expect(megalomaniac.mastermind).to.equal('Joker');
    expect(megalomaniac.henchwoman).to.equal('Harley');
    expect(megalomaniac.henchWoman).to.equal(undefined);
    expect(megalomaniac.getMembers()).to.deep.equal(['Joker', 'Harley']);
    expect(megalomaniac.relations[2]).to.equal('Lucy');
    expect(megalomaniac.twins['Heath Ledger']).to.deep.equal('The Dark Knight');
  });


  it('Object의 속성(property)를 다루는 방법을 확인합니다.', function () {
    const megalomaniac = { mastermind: 'Agent Smith', henchman: 'Agent Smith' };

    expect('mastermind' in megalomaniac).to.equal(true);

    megalomaniac.mastermind = 'Neo';
    expect(megalomaniac['mastermind']).to.equal('Neo');

    expect('secretary' in megalomaniac).to.equal(false);

    megalomaniac.secretary = 'Agent Smith';
    expect('secretary' in megalomaniac).to.equal(true);

    delete megalomaniac.henchman;
    expect('henchman' in megalomaniac).to.equal(false);
  });


  it("'this'는 method를 호출하는 시점에 결정됩니다.", function () {
    const currentYear = new Date().getFullYear();
    const megalomaniac = {
      mastermind: 'James Wood',
      henchman: 'Adam West',
      birthYear: 1970,
      calculateAge: function (currentYear) {
        return currentYear - this.birthYear;
      },
      changeBirthYear: function (newYear) {
        this.birthYear = newYear;
      },
    };

    expect(currentYear).to.equal(2023);
    expect(megalomaniac.calculateAge(currentYear)).to.equal(53);

    megalomaniac.birthYear = 2000;
    expect(megalomaniac.calculateAge(currentYear)).to.equal(23);

    megalomaniac.changeBirthYear(2010);
    expect(megalomaniac.calculateAge(currentYear)).to.equal(13);
  });

  it('객체의 method를 정의하는 방법을 확인합니다.', function () {
    const megalomaniac = {
      mastermind: 'Brain',
      henchman: 'Pinky',
      getFusion: function () {
        return this.henchman + this.mastermind;
      },
      battleCry(numOfBrains) {
        return `They are ${this.henchman} and the` + ` ${this.mastermind}`.repeat(numOfBrains);
      },
    };

    expect(megalomaniac.getFusion()).to.deep.equal('PinkyBrain');
    expect(megalomaniac.battleCry(3)).to.deep.equal('They are Pinky and the Brain Brain Brain');
  });

  
  it('Object를 함수의 전달인자로 전달할 경우, reference가 전달됩니다.', function () {
    const obj = {
      mastermind: 'Joker',
      henchwoman: 'Harley',
      relations: ['Anarky', 'Duela Dent', 'Lucy'],
      twins: {
        'Jared Leto': 'Suicide Squad',
        'Joaquin Phoenix': 'Joker',
        'Heath Ledger': 'The Dark Knight',
        'Jack Nicholson': 'Tim Burton Batman',
      },
    };

    function passedByReference(refObj) {
      refObj.henchwoman = 'Adam West';
    }
    passedByReference(obj);
    expect(obj.henchwoman).to.equal('Adam West');

    const assignedObj = obj;
    assignedObj['relations'] = [1, 2, 3];
    expect(obj['relations']).to.deep.equal([1, 2, 3]);

    const copiedObj = Object.assign({}, obj);
    copiedObj.mastermind = 'James Wood';
    expect(obj.mastermind).to.equal('Joker');

    obj.henchwoman = 'Harley';
    expect(copiedObj.henchwoman).to.equal('Adam West');

    delete obj.twins['Jared Leto'];
    expect('Jared Leto' in copiedObj.twins).to.equal(false);
  });
});

✔️ 09. SpreadSyntax

describe('Spread syntax에 대해 학습합니다.', function () {
  
  
  it('전개 문법(spread syntax)을 학습합니다.', function () {
    const spread = [1, 2, 3];
    // TODO: 전개 문법을 사용해 테스트 코드를 완성합니다. spread를 지우지 않고 해결할 수 있습니다.
    const arr = [0, ...spread, 4];
    expect(arr).to.deep.equal([0, 1, 2, 3, 4]);
  });

  
  it('빈 배열에 전개 문법을 사용할 경우, 아무것도 전달되지 않습니다.', function () {
    const spread = [];
    // TODO: 전개 문법을 사용해 테스트 코드를 완성합니다. spread를 지우지 않고 해결할 수 있습니다.
    const arr = [0, ...spread, 1];
    expect(arr).to.deep.equal([0, 1]);
  });

  
  it('여러 개의 배열을 이어붙일 수 있습니다.', function () {
    const arr1 = [0, 1, 2];
    const arr2 = [3, 4, 5];
    const concatenated = [...arr1, ...arr2];
    expect(concatenated).to.deep.equal([0, 1, 2, 3, 4, 5]);
    // 아래 코드도 같은 동작을 수행합니다.
    //  arr1.concat(arr2);
  });

  
  it('여러 개의 객체를 병합할 수 있습니다.', function () {
    const fullPre = {
      cohort: 7,
      duration: 4,
      mentor: 'hongsik',
    };

    const me = {
      time: '0156',
      status: 'sleepy',
      todos: ['coplit', 'koans'],
    };

    const merged = { ...fullPre, ...me };
    // 변수 'merged'에 할당된 것은 'obj1'과 'obj2'의 value일까요, reference일까요?
    // 만약 값(value, 데이터)이 복사된 것이라면, shallow copy일까요, deep copy일까요?

    expect(merged).to.deep.equal({
      cohort: 7,
      duration: 4,
      mentor: 'hongsik',
      time: '0156',
      status: 'sleepy',
      todos: ['coplit', 'koans'],
    });
  });

  
  it('Rest Parameter는 함수의 전달인자를 배열로 다룰 수 있게 합니다.', function () {
    // 자바스크립트는 (named parameter를 지원하지 않기 때문에) 함수 호출 시 전달인자의 순서가 중요합니다.
    function returnFirstArg(firstArg) {
      return firstArg;
    }
    expect(returnFirstArg('first', 'second', 'third')).to.equal('first');

    function returnSecondArg(firstArg, secondArg) {
      return secondArg;
    }
    expect(returnSecondArg('only give first arg')).to.equal(undefined);

    // rest parameter는 spread syntax를 통해 간단하게 구현됩니다.
    function getAllParamsByRestParameter(...args) {
      return args;
    }

    // arguments를 통해 '비슷하게' 함수의 전달인자들을 다룰 수 있습니다. (spread syntax 도입 이전)
    // arguments는 모든 함수의 실행 시 자동으로 생성되는 '객체'입니다.
    function getAllParamsByArgumentsObj() {
      return arguments;
    }

    const restParams = getAllParamsByRestParameter('first', 'second', 'third');
    const argumentsObj = getAllParamsByArgumentsObj('first', 'second', 'third');

    expect(restParams).to.deep.equal(['first', 'second', 'third']);
    expect(Object.keys(argumentsObj)).to.deep.equal(['0', '1', '2']);
    expect(Object.values(argumentsObj)).to.deep.equal(['first', 'second', 'third']);

    // arguments와 rest parameter를 통해 배열로 된 전달인자(args)의 차이를 확인하시기 바랍니다.
    expect(restParams === argumentsObj).to.deep.equal(false);
    expect(typeof restParams).to.deep.equal('object');
    expect(typeof argumentsObj).to.deep.equal('object');
    expect(Array.isArray(restParams)).to.deep.equal(true);
    expect(Array.isArray(argumentsObj)).to.deep.equal(false);

    const argsArr = Array.from(argumentsObj);
    expect(Array.isArray(argsArr)).to.deep.equal(true);
    expect(argsArr).to.deep.equal(['first', 'second', 'third']);
    expect(argsArr === restParams).to.deep.equal(false); // Array.from() 메서드는 유사 배열 객체(array-like object)나 반복 가능한 객체(iterable object)를 얕게 복사해 새로운Array 객체를 만듭니다.
  });

  
  it('Rest Parameter는 전달인자의 수가 정해져 있지 않은 경우에도 유용하게 사용할 수 있습니다.', function () {
    function sum(...nums) {
      let sum = 0;
      for (let i = 0; i < nums.length; i++) {
        sum = sum + nums[i];
      }
      return sum;
    }
    expect(sum(1, 2, 3)).to.equal(6);
    expect(sum(1, 2, 3, 4)).to.equal(10);
  });

  it('Rest Parameter는 전달인자의 일부에만 적용할 수도 있습니다.', function () {
    // rest parameter는 항상 배열입니다.
    function getAllParams(required1, required2, ...args) {
      return [required1, required2, args];
    }
    expect(getAllParams(123)).to.deep.equal([123, undefined, []]);

    function makePizza(dough, name, ...toppings) {
      const order = `You ordered ${name} pizza with ${dough} dough and ${toppings.length} extra toppings!`;
      return order;
    }
    expect(makePizza('original')).to.equal(`You ordered undefined pizza with original dough and 0 extra toppings!`);
    expect(makePizza('thin', 'pepperoni')).to.equal(`You ordered pepperoni pizza with thin dough and 0 extra toppings!`);
    expect(makePizza('napoli', 'meat', 'extra cheese', 'onion', 'bacon')).to.equal(`You ordered meat pizza with napoli dough and 3 extra toppings!`);
  });
});

✔️ 10. Destructuring

describe('구조 분해 할당(Destructuring Assignment)에 관해서', () => {


  it('배열을 분해합니다', () => {
    const array = ['code', 'states', 'im', 'course']

    const [first, second] = array
    expect(first).to.eql('code')
    expect(second).to.eql('states')

    const result = []
    function foo([first, second]) {
      result.push(second)
      result.push(first)
    }

    foo(array)
    expect(result).to.eql(['states', 'code'])
  })


  it('rest/spread 문법을 배열 분해에 적용할 수 있습니다', () => {
    const array = ['code', 'states', 'im', 'course']
    const [start, ...rest] = array
    expect(start).to.eql('code')
    expect(rest).to.eql(['states', 'im', 'course'])

    // 다음과 같은 문법은 사용할 수 없습니다. 할당하기 전 왼쪽에는, rest 문법 이후에 쉼표가 올 수 없습니다
    // const [first, ...middle, last] = array
  })


  it('객체의 단축(shorthand) 문법을 익힙니다', () => {
    const name = '김코딩'
    const age = 28

    const person = {
      name,
      age,
      level: 'Junior',
    }
    expect(person).to.eql({...person})
  })


  it('객체를 분해합니다', () => {
    const student = { name: '박해커', major: '물리학과' }

    const { name } = student
    expect(name).to.eql('박해커')
  })


  it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #1', () => {
    const student = { name: '최초보', major: '물리학과' }
    const { name, ...args } = student

    expect(name).to.eql('최초보')
    expect(args).to.eql({major: '물리학과'})
  })


  it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #2', () => {
    const student = { name: '최초보', major: '물리학과', lesson: '양자역학', grade: 'B+' }

    function getSummary({ name, lesson: course, grade }) {
      return `${name}님은 ${grade}의 성적으로 ${course}을 수강했습니다` // lesson-> course key값을 바꿈
    }

    expect(getSummary(student)).to.eql(`최초보님은 B+의 성적으로 양자역학을 수강했습니다`)
  })

  
  it('rest/spread 문법을 객체 분해에 적용할 수 있습니다 #3', () => {
    const user = {
      name: '김코딩',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      },
      age: 35
    }

    const changedUser = {
      ...user,
      name: '박해커',
      age: 20
    }

    const overwriteChanges = {
      name: '박해커',
      age: 20,
      ...user
    }

    const changedDepartment = {
      ...user,
      company: {
        ...user.company,
        department: 'Marketing'
      }
    }

    expect(changedUser).to.eql({
      name: '박해커',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      },
      age: 20
    })

    expect(overwriteChanges).to.eql({
      name: '김코딩',
      age: 35,
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      }
    })

    expect(changedDepartment).to.eql({
      name: '김코딩',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        },
        department: 'Marketing'
      },
      age: 35
    })
  })
})

// key 값이 같은 애들은 value값이 재할당(?)됨.

🍀 15일차 수업을 마치며...

지난 금요일부터 푼 51개의 문제! 잘 알려주시던 페어님과 즐겁게 51문제를 모두 풀었다! 페어 프로그래밍의 순기능을 봤다. ㅎ_ㅎ 낼부턴 첨 보는 개념인 DOM(?) 수업을 들어야한다. 화이텡!

profile
[무엥일기] 무엥,,, 내가 머쨍이 개발자가 될 수 이쓰까,,,

0개의 댓글