2021년 1월 7일 복기

Ji Taek Lim·2021년 1월 7일
0

오늘은 하지 못했던 코플릿들과 과제들을 정리하려고 한다.

중요한 개념들을 정리한다.

코언즈에 나오는 중요한 개념

    mdn에 따르면 클로저의 정의는 다음과 같습니다. 반드시 기억하시기 바랍니다.
      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

      A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

      클로저는 함수와 함수가 선언된 어휘적 환경의 조합을 말한다.
      이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.

    여기서의 키워드는 "함수가 선언""어휘적(lexical) 환경"입니다. 
    특이하게도 자바스크립트는 함수가 호출되는 환경와 별개로, 기존에 선언되어 있던 환경 - 어휘적 환경 - 을 기준으로 변수를 조회하려고 합니다.
    유어클레스 영상에서 언급되는 "외부함수의 변수에 접근할 수 있는 내부함수"를 클로져 함수로 부르는 이유도 그렇습니다.

    클로저는 내부(inner) 함수가 외부(outer) 함수의 지역 변수에 접근할 수 있습니다.
    이를 유념하시고 클로저의 유즈 케이스를 검색해 보시기 바랍니다. 아래 검색 키워드를 활용합니다.
      function factories
      namespacing private variables/functions


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

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

이거는 무슨 개념이지?


  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'); 
    
    ->reference가 전달되어서 copiedObj는 카피본이다.

    obj.henchwoman = 'Harley';
    expect(copiedObj.henchwoman).to.equal('Adam West'); 
    
    ->왜냐하면 위에 passedByReference에서 obj를 변경해주었고.
    -> copied는 121번째 줄에서 다시 만들어 주었고 obj는 원본이고 copiedObj는 복사본인데 이게 다른거니까. 위에서 변한 copied의 값을 가져온다.

    delete obj.twins['Jared Leto'];
    expect('Jared Leto' in copiedObj.twins).to.equal(false);
    
    ->함수 실행 위치를 잘 봐야한다. copiedObj는 delete보다 먼저 실행되었다.
    ///읭???

    
    마지막 테스트 코드의 결과가 예상과는 달랐을 수도 있습니다.
    'Object.assign'을 통한 복사는 reference variable은 주소만 복사하기 때문입니다. 
    이와 관련하여 얕은 복사(shallow copy)와 깊은 복사(deep copy)에 대해서 학습하시기 바랍니다.
    가이드가 될 만한 학습자료를 첨부합니다.
      https://scotch.io/bar-talk/copying-objects-in-javascript
      https://medium.com/watcha/깊은-복사와-얕은-복사에-대한-심도있는-이야기-2f7d797e008a
    
  });
});

이거 가 중요하다...

https://scotch.io/bar-talk/copying-objects-in-javascript

The Naive Way of Copying Objects

function copy(mainObj) {
  let objCopy = {}; // objCopy will store a copy of the mainObj
  let key;

  for (key in mainObj) {
    objCopy[key] = mainObj[key]; // copies each property to the objCopy object
  }
  return objCopy;
}

const mainObj = {
  a: 2,
  b: 5,
  c: {
    x: 7,
    y: 4,
  },
}

console.log(copy(mainObj));

let obj = {
  a: 1,
  b: {
    c: 2,
  },
}
let newObj = Object.assign({}, obj);
console.log(newObj); // { a: 1, b: { c: 2} }

obj.a = 10;
console.log(obj); // { a: 10, b: { c: 2} }
obj는 바뀌었다.
console.log(newObj); // { a: 1, b: { c: 2} }
newObj는 안바뀌었다.

newObj.a = 20;
console.log(obj); // { a: 10, b: { c: 2} }
obj는 안바뀌었다.
console.log(newObj); // { a: 20, b: { c: 2} }
newObj는 바뀌었다.

newObj.b.c = 30;
console.log(obj); // { a: 10, b: { c: 30} }
obj가 왜 바뀌지?
console.log(newObj); // { a: 20, b: { c: 30} }
newObj는 바뀌었다.

// Note: newObj.b.c = 30; Read why..
let obj = {
  a: 1,
  b: 2,
};
let objCopy = Object.assign({}, obj);
console.log(objCopy);
// Result - { a: 1, b: 2 }
let obj = {
  a: 1,
  b: 2,
};
let objCopy = Object.assign({}, obj);

console.log(objCopy); // result - { a: 1, b: 2 }
objCopy.b = 89;
console.log(objCopy); // result - { a: 1, b: 89 }
console.log(obj); // result - { a: 1, b: 2 }
  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'],
    });
  });

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

이거 어렵다.

    function getAllParamsByRestParameter(...args) {
      return args;
    }
    const restParams = getAllParamsByRestParameter('first', 'second', 'third'); 
    expect(restParams).to.deep.equal(['first','second','third']); ////// ...args 를 했으니까 이게 배열이 되는거야
    // 그러니까 restPrams는 ...args를 썼고 그걸 그대로 가져왔어 ...arg를 쓰니까. ['first','second','third']가 나왔어.
    expect(Array.isArray(restParams)).to.deep.equal(true);//이거는 배열이라는거지
    

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

    expect(Object.keys(argumentsObj)).to.deep.equal(['0','1','2']); /// 오 key가 string type으로 나오는구나
    expect(Object.values(argumentsObj)).to.deep.equal(['first','second','third']);
    /// arguments도 쓰니까 ['first','second','third'] 가 나왔어..
    // arguments와 rest parmeter를 통해 배열로 된 인자(args)의 차이를 확인하시기 바랍니다.
    expect(Array.isArray(argumentsObj)).to.deep.equal(false); 

이거는 객체라는건가?

    

    expect(restParams === argumentsObj).to.deep.equal(false);

    expect(typeof restParams).to.deep.equal('object'); // 이거는 배열인데 배열의 상위 개념이니까 객체이고
    expect(typeof argumentsObj).to.deep.equal('object'); // 이거는 그냥 객체 이고



    const argsArr = Array.from(argumentsObj);
    //이거는 뭐야?
    
       expect(restParams === argumentsObj).to.deep.equal(false);

    expect(typeof restParams).to.deep.equal('object'); // 이거는 배열인데 배열의 상위 개념이니까 객체이고
    expect(typeof argumentsObj).to.deep.equal('object'); // 이거는 그냥 객체 이고



    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); //다른 주소다.

요약:arguments가 배열로 만들어줌,

restParameter가 배열로 만들어줌.

Array.from()

Array.from() 메서드는 유사 배열 객체(array-like object)나반복 가능한 객체(iterable object)를 얕게 복사해새로운Array 객체를 만듭니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from

map이랑 filter 차이 위에건 filter 아랫건 map

Array.from과 화살표 함수 사용하기
// Using an arrow function as the map function to
// manipulate the elements
Array.from([1, 2, 3], x => x + x);
// [2, 4, 6]

// Generate a sequence of numbers
// Since the array is initialized with `undefined` on each position,
// the value of `v` below will be `undefined`
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]

  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);
  });
profile
임지택입니다.

0개의 댓글