모던 자바스크립트 스터디(객체 프로퍼티 및 프로토타입)

하윤·2022년 11월 13일
0

자바스크립트

목록 보기
3/4

바인딩과 this

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

setTimeout(user.sayHi, 1000); // Hello, undefined!

이런식으로 해주게 되면, this 컨텍스트가 안먹는 일이 일어난다. 이 이유는, 브라우저 환경에서는, this가 바로, window가 할당되기에, 우리가 정했던 함수와는 아예 다른 방식으로 작동하게 된다.

이를 해결하기 위해서는

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

setTimeout(function() {
  user.sayHi(); // Hello, John!
}, 1000);

이런식으로 wrapper를 씌워주는 방식과, bind가 있다.

Bind?

function mul(a, b) {
  return a * b;
}

let double = mul.bind(null, 2);

alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10

여기서, mul을 통해서, doubled이란 함수가 새로 생기게 된다. 여기서 첫번째 인자가 3,4,5로 고정되게 되며, 2번째 인자는 기존의 2가 계속 유지되어 고정된다. 추가 인자가 그대로 적용되었기에, 이를 부분 적용 이라고 한다.

func.bind(context, ...args)는 this가 context로 고정되고 인수도 고정된 함수 func을 반환하게 된다. 추가로, 화살표 함수에는 this 자체가 존재하지 않는다!!

객체에는 키-값 구성말고 꽤 다양하고 많은 기능을 가지고 있다.

객체 프로퍼티는 값(value) 과 함께 플래그(flag)라 불리는 특별한 속성 세 가지를 갖습니다.

writable – true이면 값을 수정할 수 있습니다. 그렇지 않다면 읽기만 가능합니다.
enumerable – true이면 반복문을 사용해 나열할 수 있습니다. 그렇지 않다면 반복문을 사용해 나열할 수 없습니다.
configurable – true이면 프로퍼티 삭제나 플래그 수정이 가능합니다. 그렇지 않다면 프로퍼티 삭제와 플래그 수정이 불가능합니다.

이러한 기능이 사실은 숨겨져있었다! 디폴트값은 전부다 true이다.

Object.defineProperty(user, "name", {
  writable: false
});

user.name = "Pete"; // Error: Cannot assign to read only property 'name'

flag는 이런식으로 쓸 수 있다. writable:false 설정 때문에 이렇게 수정이 안되는 모습!

let user = {
  name: "John",
  surname: "Smith",

  get fullName() {
    return `${this.name} ${this.surname}`;
  },

  set fullName(value) {
    [this.name, this.surname] = value.split(" ");
  }
};

// 주어진 값을 사용해 set fullName이 실행됩니다.
user.fullName = "Alice Cooper";

alert(user.name); // Alice
alert(user.surname); // Cooper

이런 개념을 이용해, 객체의 getter, setter 세팅을 간단하게 할 수 있다! 이런식으로, 다른 언어처럼 객체의 getter,setter 세팅 가능

프로토타입

자바스크립트의 객체는 명세서에서 명명한 [[Prototype]]이라는 숨김 프로퍼티를 갖습니다.

let animal = {
  eats: true,
  walk() {
    alert("동물이 걷습니다.");
  }
};

let rabbit = {
  jumps: true,
  __proto__: animal
};

// 메서드 walk는 rabbit의 프로토타입인 animal에서 상속받았습니다.
rabbit.walk(); // 동물이 걷습니다.

이런식으로, '_부모 _' 문법을 통해서, 프로토타입을 상속받아서 실행할 수 있습니다. 이런식으로 자바의 클래스 처럼 부모 자식 관계를 형성 가능! 단, 중요한 것은

프로토타입은 읽기 전용이다! 또한 ,프로토타입에서 상속받은 method라도 obj.method()를 호출하면 method 안의 this는 호출 대상 객체인 obj를 가리킨다!

let arr = [1, 2, 3];

// arr은 Array.prototype을 상속받았나요?
alert( arr.__proto__ === Array.prototype ); // true

// arr(Array.Prototype)은 Object.prototype을 상속받았나요?
alert( arr.__proto__.__proto__ === Object.prototype ); // true

// 체인 맨 위엔 null이 있습니다.
alert( arr.__proto__.__proto__.__proto__ ); // null

또한, 이 코드에서 볼 수 있듯이 꼭 객체가 아니더라도 , 대부분의 타입은 prototype을 상속받아 체인을 형성한 구조인것을 확인할 수 있었다. 단, 이런 방식은 너무 구식 방식이다!

let animal = {
  eats: true
};

// 프로토타입이 animal인 새로운 객체를 생성합니다.
let rabbit = Object.create(animal);

alert(rabbit.eats); // true

alert(Object.getPrototypeOf(rabbit) === animal); // true

Object.setPrototypeOf(rabbit, {}); // rabbit의 프로토타입을 {}으로 바꿉니다.

이런식으로, 모던한 프로토타입을 만들어주는 과정을 ,브라우저에서 작업할땐 꼭 숙지하도록 하자. 얕은 복사를 할때는 Object.create이런 식으로 인자에 객체를 넣어주면 얕은 복사가 가능하다!

profile
넓은 시야를 가진 개발자를 꿈꾸는

0개의 댓글