[프론트엔드 스쿨 6기] 🗓️ 7월11일

유동균·2023년 7월 11일
0

프론트엔드 스쿨 6기

목록 보기
29/44
post-thumbnail

this

// 일반함수 : 나를 호출한 대상을 this로 바인딩합니다.
// 화살표함수 : this를 바인딩하지 않음. 찾아야 한다면 내 부모(상위 컨텍스트)꺼 가져옴.

// addEventListener 콜백 함수에서의 this
const btn = document.querySelectorAll('button');
btn.forEach((e) =>
  e.addEventListener('click', (t) => {
    console.log(t.currentTarget);
    console.log(this);
  })
);
btn.forEach((e) =>
  e.addEventListener('click', function () {
    console.log(this);
  })
);

// 객체 안에서의 this
// 객체의 메서드를 정의할 때는 화살표 함수보다 일반 함수가 더 좋다.
// 메서드 안에서 함수를 호출할때는 화삺표 함수가 더 좋다.
const user = {
  total: 0,
  name: 'tiger',
  age: 32,
  address: '서울시 중랑구 면목동',
  grades: [80, 90, 100],
  totalGrades: function () {
    this.grades.forEach((item) => {
      return (this.total += item);
    });
    console.log(this.total);
  },
};

user.totalGrades();

객체 Object

자바스크립트엔 여덟 가지 자료형이 있습니다. 이 중 일곱 개는 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있어 '원시형(primitive type)'이라 부릅
객체형은 원시형과 달리 다양한 데이터를 담을 수 있습니

let user = new Object(); // '객체 생성자' 문법, 생성자 함수 (constructor)

let user2 = {     // '객체 리터럴' 문법
  name: "John",  // 키: "name",  값: "John"
  age: 30        // 키: "age", 값: 30
};  

// 프로퍼티 값 얻기, 프로퍼티 값엔 모든 자료형이 올 수 있
console.log( user2.name ); // John
console.log( user2.age ); // 30
// delete 연산자를 사용하면 프로퍼티를 삭제할 수 있
delete user.age;

대괄호 표기법square bracket notation

user.likes birds = true; // Error
user["likes birds"] = true;

계산된 프로퍼티

객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티(computed property) 라고 부릅니다.

let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {};

// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 5;

단축 프로퍼티shorthand property

function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ...등등
  };
}

// 

function makeUser(name, age) {
  return {
    name, // name: name 과 같음
    age,  // age: age 와 같음
    // ...
  };
}

객체 프로퍼티 ‘for’, ‘let’, ‘return’ 같은 예약어를 사용하면 안됩니다.

함수로 객체 만들기

  • 자바스크립트에서의 함수는 값을 리턴할 수 있음
  • 그 값을 어딘가에 담아서 쓸 수 있다
  • JS에서는 원시값이 아닌, 객체도 내보낼 수 있음( return {} )
  • 객체를 입력해서 내보내게 되고 변수에 할당하면 객체가 된다
function createUser() {
  return {
    name: 'tiger',
    email: 'tiger@naver.com',
  };
}

const user = createUser();

클래스로 객체 만들기

  • 객체지향
  • new Object()를 생성
class User {
  constructor(name, email) {
    this.name = name;
    this.eamil = email;
  }
}
const user3 = new User('동혁');

참조에 의한 객체 복사

객체와 원시 타입의 근본적인 차이 중 하나는 객체는 ‘참조에 의해(by reference)’ 저장되고 복사된다는 것

let message = "Hello!";
let phrase = message;

객체의 동작 방식은 이와 다릅니다.

변수엔 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장됩니다.
객체는 메모리 내 어딘가에 저장되고, 변수 user엔 객체를 '참조’할 수 있는 값이 저장됩니다.

따라서 객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사되고 객체는 복사되지 않습니다.

let user = { name: "John" };

let admin = user; // 참조값을 복사함
let user = { name: 'John' };

let admin = user;

admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨

alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함

참조에 의한 비교

객체 비교 시 동등 연산자 ==와 일치 연산자 ===는 동일하게 동작합니다.

비교 시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환하죠.

두 변수가 같은 객체를 참조하는 예시를 살펴봅시다. 일치·동등 비교 모두에서 참이 반환됩니다.

let a = {};
let b = a; // 참조에 의한 복사

alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true

//

let a = {};
let b = {}; // 독립된 두 객체

alert( a == b ); // false

객체 복사, 병합과 Object.assign

객체가 할당된 변수를 복사하면 동일한 객체에 대한 참조 값이 하나 더 만들어진다는 걸 배웠습니다.

그런데 객체를 복제하고 싶다면 어떻게 해야 할까요? 기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면 말이죠.

방법은 있는데 자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵습니다. 사실 객체를 복제해야 할 일은 거의 없습니다. 참조에 의한 복사로 해결 가능한 일이 대다수이죠.

정말 복제가 필요한 상황이라면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사하면 됩니다.

let user = {
  name: "John",
  age: 30
};

let clone = {}; // 새로운 빈 객체

// 빈 객체에 user 프로퍼티 전부를 복사해 넣습니다.
for (let key in user) {
  clone[key] = user[key];
}

// 이제 clone은 완전히 독립적인 복제본이 되었습니다.
clone.name = "Pete"; // clone의 데이터를 변경합니다.

alert( user.name ); // 기존 객체에는 여전히 John이 있습니다.

Object.assign

Object.assign(dest, [src1, src2, src3...])
  • 첫 번째 인수 dest는 목표로 하는 객체입니다.
  • 이어지는 인수 src1, ..., srcN는 복사하고자 하는 객체입니다. ...은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타냅니다.
  • 객체 src1, ..., srcN의 프로퍼티를 dest에 복사합니다. dest를 제외한 인수(객체)의 프로퍼티 전부가 첫 번째 인수(객체)로 복사됩니다.
  • 마지막으로 dest를 반환합니다.
  • 목표 객체에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워 집니다.
let user = {
  name: "John",
  age: 30
};

let clone = Object.assign({}, user);

예시를 실행하면 user에 있는 모든 프로퍼티가 빈 배열에 복사되고 변수에 할당됩니다.

중첩 객체 복사

프로퍼티는 다른 객체에 대한 참조 값일 수도 있습니다. 이 경우는 어떻게 해야 할까요?


let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

alert( user.sizes.height ); // 182
  • clone.sizes = user.sizes로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없습니다. user.sizes는 객체이기 때문에 참조 값이 복사되기 때문입니다. clone.sizes = user.sizes로 프로퍼티를 복사하면 clone과 user는 같은 sizes를 공유하게 됩니다.
let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, 같은 객체입니다.

// user와 clone는 sizes를 공유합니다.
user.sizes.width++;       // 한 객체에서 프로퍼티를 변경합니다.
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할 수 있습니다.
  • 이 문제를 해결하려면 user[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 합니다. 이런 방식을 '깊은 복사(deep cloning)'라고 합니다.

  • 깊은 복사 시 사용되는 표준 알고리즘인 Structured cloning algorithm을 사용하면 위 사례를 비롯한 다양한 상황에서 객체를 복제할 수 있습니다.

  • 자바스크립트 라이브러리 lodash의 메서드인 _.cloneDeep(obj)을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있으므로 참고하시기 바랍니다.

0개의 댓글