JavaScript Koans

Hannahhhยท2022๋…„ 7์›” 13์ผ
0

JavaScript

๋ชฉ๋ก ๋ณด๊ธฐ
18/47

๐Ÿ‘€ JavaScript Koans

Unit 10์—์„œ ๊ณต๋ถ€ํ•œ JavaScript์˜ ํ•ต์‹ฌ ๊ฐœ๋…๊ณผ ์ฃผ์š” ๋ฌธ๋ฒ•์„ ์ž˜ ์ดํ•ดํ–ˆ๋Š” ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ณผ์ œ๋กœ, pair ์ฝ”๋”ฉ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ ํ’€์ด๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.
์ฃผ์ œ๋Š” JavaScript์˜ ํƒ€์ž…, ๋ณ€์ˆ˜ ์„ ์–ธ ํ‚ค์›Œ๋“œ let๊ณผ const, ํ™”์‚ดํ‘œ ํ•จ์ˆ˜, ์Šค์ฝ”ํ”„, ๋ฐฐ์—ด, ๊ฐ์ฒด, spread, ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น ๋“ฑ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด์žˆ๋‹ค.


JavaScipt Koans๋ฅผ ํ•™์Šตํ–ˆ๋˜ ๊ณผ์ •์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

1) ํŽ˜์–ด์™€ ํ•จ๊ป˜ ๋ฌธ์ œ๋ฅผ ํ‘ผ๋‹ค.(1์ฐจ ํ’€์ด)
2) 1์ฐจ ํ’€์ด ํ›„, ์ƒˆ๋กœ ํŒŒ์ผ์„ ๋‹ค์šด๋ฐ›์•„ ํ˜ผ์ž์„œ ๋ฌธ์ œ๋ฅผ ๋‹ค์‹œ ํ’€์–ด๋ณธ๋‹ค.
3) ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…์ด๋‚˜ ํ—ท๊ฐˆ๋ ธ๋˜ ๋ฌธ์ œ๋“ค ์œ„์ฃผ๋กœ ๋ธ”๋กœ๊ทธ์— ์ •๋ฆฌํ•œ๋‹ค.


โ—พ JavaScript์˜ ํƒ€์ž…


 // expect์˜ ์ „๋‹ฌ์ธ์ž๋กœ ๋“ค์–ด๊ฐ„ ํ‘œํ˜„์‹์˜ ํ‰๊ฐ€ ๊ฒฐ๊ณผ
expect(1 + '1').to.equal('11');  // number(n) + string('i') = string('ni') 
expect(123 - '1').to.equal(122); // number(n) - string(i) = number(n-i),  string์€ +๋งŒ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ
expect(1 + true).to.equal(2);   // number(n) + true = number(n+1),  true = 1 & false = 0
expect('1' + true).to.equal('1true'); // string(1) + true = string('1true'), string๊ณผ ๋ง์…ˆํ•˜๋ฉด ๋ฌด์กฐ๊ฑด string์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

์œ„์™€ ๊ฐ™์€ ์ฝ”๋”ฉ ๋ฐฉ์‹์€ ์˜ˆ์ƒํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ํ”ผํ•ด์•ผ ํ•œ๋‹ค..!


//์ฐธ์กฐ ์ž๋ฃŒํ˜•
const ages = [22, 23, 27];
    allowedToDrink = ages;
    expect(allowedToDrink === ages).to.equal(true);
    expect(allowedToDrink === [22, 23, 27]).to.equal(false);  // 1
//arr === [] ๊ฐ€ ์•ˆ๋˜๋Š” ์ด์œ ์™€ ๊ฐ™๋‹ค! ์ฝ”ํ”Œ๋ฆฟ ํ’€ ๋•Œ ์ž์ฃผ ์ด๋žฌ๋Š”๋ฐ..

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

    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); // 3

์ฐธ์กฐ ํƒ€์ž…์˜ ๋ณ€์ˆ˜์—๋Š” ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ฃผ์†Œ๋งŒ์ด ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์ด๋Š” ๊ฐ’์ด ๊ฐ™์•„๋„(์ฃผ์„ 1,2,3), ๊ฐ™๋‹ค๊ณ  ์ธ์‹ํ•  ์ˆ˜ ์—†๋‹ค.



โ—พ ๋ณ€์ˆ˜ ์„ ์–ธ ํ‚ค์›Œ๋“œ let๊ณผ const


 it("'const'๋กœ ์„ ์–ธ๋œ ๊ฐ์ฒด์˜ ๊ฒฝ์šฐ, ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.", function () {
    const obj = { x: 1 };
    expect(obj.x).to.equal(1);         // key์ธ x์˜ ๊ฐ’ = 1

    delete obj.x;                      // key์ธ x ์‚ญ์ œ
    expect(obj.x).to.equal(undefined); // x๊ฐ€ ์—†์œผ๋ฏ€๋กœ undefined ์ถœ๋ ฅ

  });

const๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋Š”let๊ณผ ๋‹ค๋ฅด๊ฒŒ ์žฌํ• ๋‹น์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„์น˜ ์•Š์€ ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ๋ฐฉ์ง€ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, ์ผ๋ฐ˜์ ์œผ๋กœ const๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ , ์žฌํ• ๋‹น์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ let์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.



โ—พ ํ•จ์ˆ˜ ํ‘œํ˜„์‹

it('ํ•จ์ˆ˜ ์„ ์–ธ์‹(declaration)๊ณผ ํ•จ์ˆ˜ ํ‘œํ˜„์‹(expression)์˜ ์ฐจ์ด๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.', function () {
    let funcExpressed = 'to be a function';

    expect(typeof funcDeclared).to.equal('function'); // ํ•จ์ˆ˜ ์„ ์–ธ์‹: function ํƒ€์ž…
    expect(typeof funcExpressed).to.equal('string');  // ํ•จ์ˆ˜ ํ‘œํ˜„์‹: string ํƒ€์ž…

    function funcDeclared() {  //ํ•จ์ˆ˜ ์„ ์–ธ์‹
      return 'this is a function declaration';
    }

    funcExpressed = function () {  //ํ•จ์ˆ˜ ํ‘œํ˜„์‹
      return 'this is a function expression';
    };

    // ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜ ํ˜ธ์ด์ŠคํŒ…(hoisting)์— ๋Œ€ํ•ด์„œ ๊ฒ€์ƒ‰ํ•ด ๋ด…๋‹ˆ๋‹ค.

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

ํ•จ์ˆ˜ ์„ ์–ธ์‹๊ณผ ํ•จ์ˆ˜ ํ‘œํ˜„์‹์˜ ์ฐจ์ด๋Š” ๊ฐ๊ฐ ๋‹ค๋ฅธ(function, string) ํƒ€์ž…์œผ๋กœ ์ธ์‹ํ•œ๋‹ค๋Š” ์ ๊ณผ, ํ•จ์ˆ˜ ํ˜ธ์ด์ŠคํŒ…์˜ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์— ์žˆ๋‹ค.

๋งํฌํ…์ŠคํŠธ



โ—พ ์Šค์ฝ”ํ”„ & ํด๋กœ์ €

โ• ์Šค์ฝ”ํ”„๋Š” '๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ฐพ์„ ๋•Œ ํ™•์ธํ•˜๋Š” ๊ณณ'์ด๋‹ค.
ํด๋กœ์ €๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ์ง€์—ญ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์œ ์ฆˆ ์ผ€์ด์Šค๋กœ Function factory์™€ Namespacing(privacy)๊ฐ€ ์žˆ๋‹ค.



โ—พ ๊ฐ์ฒด

it('Object์˜ ๊ธฐ๋ณธ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.', function () {
    const emptyObj = {};
    expect(typeof emptyObj === 'object').to.equal(true);
    expect(emptyObj.length).to.equal(undefined);  // ๊ฐ์ฒด์—๋Š” length ์†์„ฑ์ด ์—†์œผ๋ฏ€๋กœ undefined

length ์†์„ฑ์€ ๋ฐฐ์—ด๊ณผ ๋ฌธ์ž์—ด์—๋งŒ ์žˆ๋Š” ์†์„ฑ์œผ๋กœ, ๊ฐ์ฒด์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ฐ์ฒด ์•ˆ์— ๊ฐ’์ด ์žˆ์–ด๋„ length ์†์„ฑ ์‚ฌ์šฉ์‹œ, undefined๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

๊ฐ์ฒด์˜ ๊ธธ์ด๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Object.keys๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ex)Object.keys(obj).length



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'); // .repeat(n) => . ์•ž์˜ ๊ฐ’์„ n๋ฒˆ ๋ฐ˜๋ณต

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'); // obj์˜ jenchwoman ๊ฐ’ ๋ณ€๊ฒฝ

    const copiedObj = Object.assign({}, obj);  // obj๊ฐ์ฒด๋ฅผ assign ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜์—ฌ copiedObj ๊ฐ์ฒด ์ƒ์„ฑ
    copiedObj.mastermind = 'James Wood';       // copiedObj์˜ mastermind ๊ฐ’ ๋ณ€๊ฒฝ
    expect(obj.mastermind).to.equal('Joker');  // obj์˜ mastermind๋Š” ๊ทธ๋Œ€๋กœ

    obj.henchwoman = 'Harley';  // obj์˜ hanchwoman ๊ฐ’ ๋ณ€๊ฒฝ
    expect(copiedObj.henchwoman).to.equal('Adam West');  // copiedObj์˜ henchwoman์€ ๊ทธ๋Œ€๋กœ

    delete obj.twins['Jared Leto']; // obj์˜ key์ธ twins ๊ฐ์ฒด์˜ Jared Leto ํ‚ค ์‚ญ์ œ
    expect('Jared Leto' in copiedObj.twins).to.equal(false); // ๊ฐ์ฒด ์•ˆ์˜ ๊ฐ์ฒด -> ์–•์€ ๋ณต์‚ฌ์ด๋ฏ€๋กœ ๋ฐ์ดํ„ฐ์— ์˜ํ–ฅ์„ ์คŒ

'Object.assign'์„ ํ†ตํ•œ ๋ณต์‚ฌ๋Š” ๊นŠ์€ ๋ณต์‚ฌ(deep copy)๋กœ, reference๋งŒ ๋ณต์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์‚ฌํ•œ ๊ฐ์ฒด ๋‚ด์—์„œ ๊ฐ’์˜ ๋ณ€๊ฒฝ์ด ์žˆ์„ ๊ฒฝ์šฐ ์›๋ณธ ๊ฐ์ฒด์—๋Š” ์˜ํ–ฅ์„ ๋ผ์น˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ์ฒด ์•ˆ์˜ ๊ฐ์ฒด๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ํ•œ๊ฐœ์˜ ๊ฐ์ฒด๋ผ๋„ ์›๋ณธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์–•์€ ๋ณต์‚ฌ(shallow copy)๋กœ, ๋ฐ์ดํ„ฐ์— ์˜ํ–ฅ์„ ์ค€๋‹ค. ๋”ฐ๋ผ์„œ,delete obj.twins['Jared Leto'];๋Š” copieObj ๊ฐ์ฒด์— ์˜ํ–ฅ์„ ์ค€๋‹ค.


์–•์€ ๋ณต์‚ฌ, ๊นŠ์€ ๋ณต์‚ฌ?
๋งํฌํ…์ŠคํŠธ



โ—พ spread

function returnFirstArg(firstArg) {
  return firstArg;
}
expect(returnFirstArg('first', 'second','third')).to.equal('first', 'second', 'third');

function returnSecondArg(firstArg, secondArg) {
  return secondArg;
    }
expect(returnSecondArg('only give firstarg')).to.equal(undefined);  
//๊ฐ’์„ ํ•˜๋‚˜๋งŒ ์ž…๋ ฅํ–ˆ์œผ๋ฏ€๋กœ ๊ฐ€์žฅ ์ฒซ ๋ฒˆ์งธ ์ „๋‹ฌ์ธ์ž์ธ firstArg์— ๊ฐ’์ด ํ• ๋‹น๋˜์—ˆ๋‹ค. 
//๊ทธ๋Ÿฌ๋‚˜ secondArg๋ฅผ return ํ–ˆ์œผ๋ฏ€๋กœ undefinde ์ถœ๋ ฅ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” named parameter๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ์ „๋‹ฌ์ธ์ž์˜ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค.


// 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']); // key๊ฐ’์ด index ๊ฐ’์œผ๋กœ ์ถœ๋ ฅ

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');  // ๋ฐฐ์—ด์— typeof ์†์„ฑ ์‚ฌ์šฉ์‹œ, object๋กœ ์ถœ๋ ฅ
expect(typeof argumentsObj).to.deep.equal('object');
expect(Array.isArray(restParams)).to.deep.equal(true);
expect(Array.isArray(argumentsObj)).to.deep.equal(false);

// rest parameter๋Š” ์ „๋‹ฌ์ธ์ž์˜ ์ผ๋ถ€์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ๋„ ์žˆ๋‹ค.
// rest parameter๋Š” ํ•ญ์ƒ ๋ฐฐ์—ด
    function getAllParams(required1, required2, ...args) {
      return [required1, required2, args];
    }
    expect(getAllParams(123)).to.deep.equal([123, undefined, []]); 



โ—พ ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น


it('rest/spread ๋ฌธ๋ฒ•์„ ๊ฐ์ฒด ๋ถ„ํ•ด์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค #3', () => {
    const user = {
      name: '๊น€์ฝ”๋”ฉ',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      },
      age: 35
    }

    const changedUser = {  // ๋งจ ์•ž์— ...user๋กœ ์›๋ณธ ๋ถˆ๋Ÿฌ์˜จ ํ›„, ๊ทธ ๋’ค์—์„œ ๋‚˜๋จธ์ง€ ํ‚ค์˜ ๊ฐ’์„ ๋ณ€๊ฒฝ
      ...user,
      name: '๋ฐ•ํ•ด์ปค',
      age: 20
    }

    const overwriteChanges = {  // ๋ณ€์ˆ˜ ์„ ์–ธ ์ดํ›„, ๋งจ ๋งˆ์ง€๋ง‰์— ...user๋กœ ์›๋ณธ์„ ๋ถˆ๋Ÿฌ์˜ด(๋ณ€๊ฒฝx)
      name: '๋ฐ•ํ•ด์ปค',
      age: 20,
      ...user
    }

    expect(changedUser).to.eql({
      name: '๋ฐ•ํ•ด์ปค',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      },
      age: 20
    })

    expect(overwriteChanges).to.eql({
      name: '๊น€์ฝ”๋”ฉ',
      company: {
        name: 'Code States',
        department: 'Development',
        role: {
          name: 'Software Engineer'
        }
      },
      age: 35
    })   //...user์˜ ์œ„์น˜์— ๋”ฐ๋ผ ๊ฐ์ฒด์˜ ๊ฐ’์ด ๋‹ฌ๋ผ์ง„๋‹ค.
  })



** ๋ฐฐ์—ด ์ƒ๋žต




Reference: ์ฝ”๋“œ์Šคํ…Œ์ด์ธ 

0๊ฐœ์˜ ๋Œ“๊ธ€