IIFE는?

클래스에 대해서 생성된 js는 다음과 같을 수 있습니다.:

function Point(x, y) {
    this.x = x;
    this.y = y;
}
Point.prototype.add = function (point) {
    return new Point(this.x + point.x, this.y + point.y);
};

예를 들어 즉식 호출 함수 표현식으로(IIFE) 쌓여진 이유는

(function () {

    // BODY

    return Point;
})();

상속과 관련이 있습니다. TypeScript가 기반 클래스를 변수 _super로 저장할 수 있습니다. 예를 들어

var Point3D = (function (_super) {
    __extends(Point3D, _super);
    function Point3D(x, y, z) {
        _super.call(this, x, y);
        this.z = z;
    }
    Point3D.prototype.add = function (point) {
        var point2D = _super.prototype.add.call(this, point);
        return new Point3D(point2D.x, point2D.y, this.z + point.z);
    };
    return Point3D;
})(Point);

IIFE는 TypeScript가 _super 변수에 기반 클래스 Point를 쉽게 저장할 수 있게 해주고 클래스 본체에서 일관되게 사용합니다.

__extends

클래스를 사용하자마자 TypeScript는 다음 함수를 생성합니다.:

var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};

d는 파생된 클래스를 나타내고 b는 기반 클래스를 나타냅니다. 이 함수는 두 가지 일을 합니다.:

  1. 기반 클래스의 정적 멤버를 자식 클래스에 복사합니다. 예를 들면 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 입니다.
  2. 자식 클래스 함수의 프로토타입에 부모의 proto의 멤버를 선택적으로 보게 설정합니다. 예를 들면 d.prototype.__proto__ = b.prototype 입니다.

1을 이해하는 데 어려움을 겪는 사람은 드물지만, 많은 사람은 2를 이해하는 데 어려움을 겪습니다. 이어서 설명을 합니다.

d.prototype.__proto__ = b.prototype

이를 많은 사람에게 가르쳐본 후 다음 설명이 가장 단순하다는 것을 알게 되었습니다. 먼저 __extends의 코드가 d.prototype.__proto__ = b.prototype와 같은지 설명하고 왜 이 라인이 중요한지 설명할 것입니다. 이 모든 것을 이해하려면 다음 사항을 알아야 합니다.

  1. __proto__
  2. prototype
  3. 호출된 함수 안의 this에 미치는 new의 영향
  4. prototype__proto__에 미치는 new의 영향

JavaScript의 모든 객체는 __proto__ 멤버를 가지고 있습니다. 이 멤버는 오래된 브라우저에서는 지원하지 않을 수 있습니다. (때로는 문서에서 이 마법 속성을 [[prototyp]]이라고 합니다.) 하나의 목표가 있습니다.: 만약 찾는 동안 (예를 들어 obj.property) 객체에서 속성이 발견되지 않으면 obj.__proto__.property에서 찾으려고 합니다. 그래도 찾지 못하면 obj.__proto__.__proto__.property에서 둘 중 하나를 찾으려고 반복합니다. 찾았거나 마지막 .__proto__가 null이거나. JavaScript가 프로토타입 상속을 지원한다고 말하는 이유입니다. 다음 예제를 chrome 콘솔 또는 Node.js에서 수행할 수 있습니다.

var foo = {}

// foo.__proto__와 foo 설정
foo.bar = 123;
foo.__proto__.bar = 456;

console.log(foo.bar); // 123
delete foo.bar; // 객체에서 제거
console.log(foo.bar); // 456
delete foo.__proto__.bar; // foo.__proto__에서 제거
console.log(foo.bar); // undefined

__proto__를 이해했습니다. 또 다른 유용한 정보는 JavaScript의 모든 함수prototype이라는 속성을 가지고 있고, prototype은 그 함수를 가리키는 constructor 멤버를 가지고 있습니다. 아래에 나와 있습니다.:

function Foo() { }
console.log(Foo.prototype); // {} i.e. 존재하고 정의되지 않음
console.log(Foo.prototype.constructor === Foo); // 함수를 가리키는 `constructor` 멤버를 가지고 있음

호출된 함수 안에서 this에 미치는 new의 영향을 살펴보겠습니다. 기본적으로 호출된 함수 안에서 this는 함수에서 반환될 새롭게 생성된 객체를 가리킬 것입니다. 함수 안에서 this의 속성을 변경시켜보면 간단하게 볼 수 있습니다.

function Foo() {
    this.bar = 123;
}

// new 연산자로 호출
var newFoo = new Foo();
console.log(newFoo.bar); // 123

이제 함수에서 new를 호출하는 것은 함수 호출에서 반환된 새롭게 생성된 객체의 __proto__에 함수의 prototype이 할당되는 것도 알아야 합니다. 완벽한 이해를 돕는 코드가 여기 있습니다.:

function Foo() { }

var foo = new Foo();

console.log(foo.__proto__ === Foo.prototype); // True!

이것이 전부입니다. 이제 바로 다음과 같은 __extends를 보세요. 제 맘대로 줄에 번호를 매겨놨습니다.

1  function __() { this.constructor = d; }
2   __.prototype = b.prototype;
3   d.prototype = new __();

이 함수를 뒤에서부터 보면 3번 줄에 d.prototype = new __()d.prototype = {__proto__ : __.prototype}을 의미하고 (prototype__proto__에 대한 new의 영향이기 때문에), 앞줄과 (2번 줄 __.prototype = b.prototype;) 하나로 합쳐져서 d.prototype = {__proto__ : b.prototype}이 됩니다.

그러나 잠깐, d.prototype.__proto__가 변경되고 예전 d.prototype.constructor를 유지하기를 원했습니다. 이는 첫 번째 줄(즉, function __() { this.constructor = d; })으로 충분합니다. 여기에서 (호출된 함수 안에서 this에 대한 new의 영향 때문에) 사실상 d.prototype = {__proto__ : __.prototype, d.constructor = d}이 될 것입니다. d.prototype.constructor를 원상 복구했기 때문에 실제 변경한 것은 __proto__이므로 d.prototype.__proto__ = b.prototype이 됩니다.

d.prototype.__proto__ = b.prototype 중요함

중요한 것은 멤버 함수를 자식 클래스에 추가하고 기본 클래스의 다른 것들을 상속받을 수 있다는 점입니다. 다음 간단한 예제에서 알 수 있습니다.:

function Animal() { }
Animal.prototype.walk = function () { console.log('walk') };

function Bird() { }
Bird.prototype.__proto__ = Animal.prototype;
Bird.prototype.fly = function () { console.log('fly') };

var bird = new Bird();
bird.walk();
bird.fly();

기본적으로 bird.flybird.__proto__.fly를 보고 있을 것이고 (newbird.__proto__Bird.prototype을 가리키게 만드는 것을 기억하세요) bird.walk는 (상속받은 멤버) bird.__proto__.__proto__.walk를 보고 있을 겁니다. (bird.__proto__ == Bird.protytype이고 bird.__proto__.__proto__ == Animal.prototype이기 때문)

results matching ""

    No results matching ""