Skip to content

Kyunghwa Yoo

YOU DON'T KNOW JS - this, 객체, 프로토타입

javascript2 min read

this

1function foo(num) {
2 console.log('foo: ' + num);
3 this.count++;
4}
5
6foo.count = 0;
7var i;
8
9for (i=0; i<10; i++) {
10 if (i>5) {
11 foo(i);
12 }
13}
14
15console.log(foo.count);
  • arguments.callee 는 실행 중인 함수 객체를 가리키지만 권장하지 않는다. 자기 참조가 필요하다면 이름 붙은 함수 표현식을 사용해야 한다.

  • this 는 작성 시점이 아닌 런타임 시점에 바인딩되며 함수 호출 당시 상황에 따라 컨텍스트가 결정된다

  • this 참고 규칙

    • 기본 바인딩

      • 단독으로 함수를 실행하면 전역 객체를 참조한다. (브라우저는 window를 참조한다)
    • 암시적 바인딩

      • 호출하는 쪽이 객체의 메소드 일 경우 이 객체가 this 에 바인딩된다.

      • 객체의 메소드를 다른 변수에 할당한 후 그 변수를 호출할 경우 this 가 전역객체나 undefined 로 바인딩될 수 있다.

      • 콜백에서도 암시적 바인딩을 할 경우 전역객체를 바라본다.

        1function foo() {
        2 console.log(this.a);
        3}
        4
        5function doFoo(fn) {
        6 fn();
        7}
        8
        9var obj = {
        10 a: 2,
        11 foo: foo
        12};
        13
        14var a = '엥, 전역이네';
        15
        16doFoo(obj.foo);
    • 명시적 바인딩

      • call(), apply() 로 this 를 주입할 수 있다.
    • new 바인딩

      • new 는 함수 호출 시 this를 새 객체와 바인딩한다.
  • this 확정 규칙

    1. new 로 함수 호출 시 새로 생성된 객체가 this 다.
    2. call, apply 로 함수를 호출 시 명시적으로 지정된 객체가 this 다.
    3. 객체안의 메소드 형식으로 함수를 호출했을 경우 해당 객체가 this 다.
    4. 이외에는 기본 값 (strict mode 에서는 undefined, 아니면 전역객체)
  • this 규칙 예외

    • call, apply, bind 메소드에 null / undefined 를 넘기면 기본 바인딩 규칙이 적용된다.

      • null, undefined 를 꼭 넘겨야 할 경우, 빈 껍데기 객체를 넘기는 것이 그나마 안전하다. {} 도 좋지만 Object.create(null)이 Object.prototype 으로 위임하지 않으므로 더 텅 빈 객체 라고 할 수 있다.
    • 간접 레퍼런스로 할당 표현식을 사용할 경우 기본 바인딩 규칙이 적용된다.

      1function foo() {
      2 console.log(this.a);
      3}
      4
      5var a = 2;
      6var o = {
      7 a:3,
      8 foo: foo
      9};
      10var p = {
      11 a: 4
      12};
      13
      14o.foo();
      15(p.foo = o.foo)();
  • arrow function 은 호출 당시 함수를 가리킨다. (렉시컬 스코프)

프로토타입

Shadowing

  • 객체의 프로퍼티랑 그 객체의 프로토타입 연쇄의 상위 객체의 프로퍼티가 동일한 이름을 가질 때 이 것을 Shadowing 이라고 한다.
  • 상위 객체의 프로퍼티는 항상 가려진다. 프로퍼티를 검색할 때 항상 하위 객체부터 검색하기 때문이다.
  • 상위 객체에 같은 이름의 프로퍼티가 있는데 하위 객체에 프로퍼티를 할당하려고 할 경우 다음 세 가지 경우의 수가 있다.
    1. 상위 객체의 프로퍼티가 읽기 전용이 아닐 경우(writable: true) 하위 객체에 프로퍼티가 할당되어 shadowing 이 발생한다.
    2. 상위 객체의 프로퍼티가 읽기 전용일 경우(writable: false) 아무 일도 일어나지 않는다. 엄격모드에서는 에러가 난다.
    3. 상위 객체의 프로퍼티가 [[Set]] 일 경우 이 setter가 호출된다. 할당이나 재정의 등의 일은 발생하지 않는다.

멘탈모델

  • 개발자의 머릿속에서만 그려진 일련의 로직이나 실행 흐름 등을 실제 코드가 기계어로 변환되어 물리적으로 실행되는 것과 대조하여 나타내기 위한 말

딕셔너리

Object.create(null) 로 prototype 링크가 빈 객체를 생성할 수 있다. 이 객체는 프로토타입 연쇄 자체가 존재하지 않기 때문에 instanceof 도 항상 false이다. 일차원적인 데이터저장소로 제격이므로 순수하게 프로퍼티에 데이터를 저장하는 용도로 사용되며 이를 딕셔너리 라고 부른다.

작동 위임

자바스크립트의 prototype 은 클래스 지향 디자인 패턴이 아닌 작동 위임(delegate) 디자인 패턴이다. 작동 위임은 찾으려는 프로퍼티/메소드 레퍼런스가 객체에 없으면 다른 객체로 수색 작업을 위임하는 것을 의미한다. 클래스 패턴은 메소드명을 똑가티 하여 오버라이드를 이용하지만 작동 위임 패턴은 반대로 같은 명칭이 뒤섞이는 일이 없게 해야한다. 같은 명칭이 충돌하면 레퍼런스를 정확히 가려낼 수 없다. 그래서 작동 위임 패턴에서는 각 객체의 작동 방식을 잘 설명하는 서술적인 명칭이 필요하다.

인트로스펙션

  • 인스턴스를 조사해 객체 유형을 거꾸로 유추하는 작업을 타입 인트로스펙션 이라고 한다.
  • instanceof 로 인트로스펙션을 하는건 의미 상 헷갈리고 간접적일 수 밖에 없다. (prototype과 하위객체의 연관성을 나타내는 것이므로)
  • Object.create() 를 통해서 모든 객체가 [[Prototype]] 위임을 통해 연관된다면 .isPrototypeOf()Object.getPrototypeOf() 를 통해서 타입 인트로스펙션을 할 수 있다.
© 2020 by Kyunghwa Yoo.