[TIL - 2022.7.13 Javascript Koans] Object~Destructuring

Jeong Ha Seung·2022년 7월 13일
0

부트캠프

목록 보기
16/51

헷갈렸던 부분

렉시컬 스코프

var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

위 결과를 살펴보면 함수를 어디서 정의했는지, 그리고 어디서 호출을 했는지에 따라 결과값이 또 달라질 수 있다고 예측이 가능하다.

만약 어디서 호출을 했는지에 따라 달라진다면 bar 함수의 상위 스코프는 foo 함수의 지역 스코프와 전역 스코프일 것이다. 이를 동적 스코프라고 한다.

함수를 어디서 정의했는지를 따지는 경우에는 정적 스코프라 하는데 상위 스코프가 동적으로 변하지 않고 함수가 정의되는 시점에서 스코프가 정적으로 결정이 된다.

위 코드처럼 foo 함수 내에서 bar를 호출해도 1이 나온걸로 확인하면 이는 정적 스코프를 따른 것이다.

화살표 함수에서의 this

function objFunction() {
  console.log('Inside `objFunction`:', this.foo); // 13
  return {
    foo: 25,
    bar: () => console.log('Inside `bar`:', this.foo) // 13
  };
}

objFunction.call({foo: 13}).bar();

먼저 차례대로 살펴보면 objFunction을 call 메소드를 이용해서 foo 값에 13을 집어넣은 후 bar 메소드르 호출한 상태다.

하지만 bar 메소드를 리턴해주는 시점에서는 foo값이 25이기 때문에 본래 예상대로라면 25가 나오는 게 맞을것이다.

하지만 콘솔로 찍어보면 13이 나오는데, 그 이유는 화살표 함수는 화살표 함수가 nesting된 곳에서 참조가 되는게 아니라 바로 바깥쪽에서 참조(위 예제에서는 전역)하기 때문에 원래 값인 13이 나오게 되는 것이다.

Object.assign()과 spread operator

그 동안 얘네 둘이 똑같다고 생각했었는데 아니었다...

const target = { a: 1, b: 2 };
const source = { d: 4, c: 5 };

const returnedTarget = { ...target, ...source };
const returedTarget2 = Object.assign(target, source);

console.log(returnedTarget, returedTarget2); //{a: 1, b: 2, d: 4, c: 5}, {a: 1, b: 2, d: 4, c: 5}
console.log(returnedTarget === returedTarget2); //false

Object.assign()과 spread operator를 각각 사용해봤을 때 두 값의 결과는 동일하지만
막상 서로 비교해보면 false가 나온다.

이렇게 서로 다른 이유는 JSON 객체를 이용하든, spread나 Object.assign이 전부 다 깊은 복사이고 결론적으로 새롭게 복사된 값에 새로운 메모리를 다시 할당하기 때문에 주소값이 다르므로 false가 나오는 것이다.

객체를 이용한 복사

let person = {
  name: "euneun",
  age: "2",
  language: { first: "java", second: "javscript" }
};

let copied = person;

person.age = "3";

console.log(person); 
//name: "euneun"
//age: "3"
//language: Object
//first: "java"
//second: "javscript"

console.log(copied); 
//name: "euneun"
//age: "3"
//language: Object
//first: "java"
//second: "javscript"

person 객체에 대한 age 속성을 바꿨는데 copied를 살펴보니 age가 바뀌어있다..분명 person의 복사본을 copied에 넣어줬음에도 불구하고...!

객체같은 참조형은 얕은 복사가 일어나고 서로 메모리 주소를 공유하기 때문에 위와 같은 현상이 벌어지는 것이다.

깊은 복사

원시 자료형 같은 타입이 대표적으로 깊은 복사가 가능하다.

let a = 3;
let b = a;

a = 2;

console.log(a, b); //2 3

위처럼 b값에 a의 복사본을 할당했다 하더라도 이 둘은 서로 다른 메모리 주소를 가지고 있기 때문에 값이 서로 다르다.

객체에서 깊은 복사 실현하기

얕은 복사 부분에서 객체는 얕은 복사가 가능하다 했지만 3가지 방법으로 깊은 복사 실현도 가능하다.

  1. Object.assign
  2. spread operator
  3. JSON.parse(JSON.stringify(object))

코드샌드박스를 이용해서 테스트를 좀 해봤다.

const target = {
  a: 1,
  b: {
    c: 2
  }
};

const returnedTarget = { ...target };

const returedTarget2 = Object.assign({}, target);

console.log(returnedTarget, returedTarget2, target); //{a: 1, b: 2} {a: 1, b: 2} {a: 1, b: 2}
console.log(target === returnedTarget) //false
console.log(target.b === returnedTarget.b); //true
console.log(target === returedTarget2); //false
console.log(target.b === returnedTarget.b); //true
console.log(returnedTarget === returedTarget2); //false

진행해 본 결과 1,2번 같은 경우에는 1deps 까지는 깊은 복사가 일어나지만 그 이후로는 얕은 복사가 일어난다.

참고 자료

모던 자바스크립트 딥다이브
arrow function과 this
JS - 깊은복사와 얕은복사 그리고 spread operator에 대해서

profile
블로그 이전했습니다. https://nextjs-blog-haseungdev.vercel.app/

0개의 댓글