아리송한 타입스크립트

이전 포스트(마크다운 변환기 - 계획)에서 얘기했던 것처럼 '서버와 웹브라우저에서 같은 마크다운 엔진'을 쓰기 위해 이것저것 해보고 있다.

가장 최근 시도는 타입스크립트로 마크다운 엔진을 다시 구현하는 것이었다.

이미 세상에 엄청 많은 마크다운 엔진이 이미 존재하는데 왜 다시 구현하느냐? 마땅히 당장 취미코딩할 것이 없었다. 마음에 드는 구현체도 딱히 없었다. 가장 유력한 후보는 showdown여서 처음에 이걸 고치다가 여러 이유로 새로 구현하는 것이 낫겠다 싶었다. 자바스크립트로 구현되어 있고 + 유명한 것에 비해 버그가 많은데 + 개발자들은 바쁘고 + 쓸데없이(?) 복잡하다. 개인적으로는 마크다운 구현체가 복잡한 건 마크다운 명세에 그 잘못이 있다고 생각하는데 이는 다음 기회에 더 자세히 이야기 하자.

그러면 왜 타입스크립트(였느)냐? "타입이 맞으면 오류가 나지 않는다"고 배웠기 때문이다. 하지만 세상은 그렇게 아름답지 않다. 오늘의 이야기는 타입스크립트다.


타입스크립트는 이래서 좋고 저래서 좋고, 처음엔 잘 쓰다가 이상한 동작을 만나서 혼자 끙끙 거리다가... 등등의 서두는 했다 치고 본론으로 들어간다.

class A {
    i: number = 3;
    getLambda: () => number = () => { return this.i; }
    getLambda2: () => number = function() { return this.i; }
    getFunction(): number { return this.i; }
}

let l: () => number = (new A).getLambda;
console.log(l());

let l2: () => number = (new A).getLambda2;
console.log(l2());

let f: () => number = (new A).getFunction;
console.log(f());

A라는 클래스에 i라는 멤버가 있고 getLambda, getLambda2getFunction은 모두 i값을 가져오는 함수이다. 실행하면,

$ tsc what.ts && node what.js 
3
undefined
undefined

일단 타입 검사에는 성공한다. 하지만 결과가 이상하다? getLambda는 성공하는데 나머지는 모두 실패한다. 내가 무얼 잘못한 걸까? 변환된 자바스크립트 코드를 보면

var A = /** @class */ (function () {
    function A() {
        var _this = this;
        this.i = 3;
        this.getLambda = function () { return _this.i; };
        this.getLambda2 = function () { return this.i; };
    }
    A.prototype.getFunction = function () { return this.i; };
    return A;
}());
var l = (new A).getLambda;
console.log(l());
var l2 = (new A).getLambda2;
console.log(l2());
var f = (new A).getFunction;
console.log(f());

두 동작의 차이는 5번째 줄과 6번째 줄, 8번째 줄에서 나타난다. 함수가 호출될 때 _this는 객체 A를 가리키지만 this는 함수를 호출한 객체를 가리킨다. 결국 l2f의 실행(14, 16번째 줄)에서 부모 객체(global?)가 i 멤버를 안 갖고 있으니 undefined가 나오는 것이다.

(왜 어떤 함수는 객체 멤버로 들어가고 어떤 함수는 프로토타입으로 들어가느냐는 궁금증이 생기지만 모르는척 하자. 스펙임니다.)

물론 11, 13, 15번째 줄에서 함수를 꺼내오지 않고 바로 실행하면 (예를 들어 (new A).getFunction()) 모두 기대했던 대로 나온다. this의 오묘함 덕분에 e()var v = e; v()와 다르게 동작하는 것이다.


결론: 헤롱헤롱 모르겠다.

2019-09-08 씀.