본문으로 건너뛰기
黯羽轻扬매일 조금씩

《JavaScript 언어 정수》의 함수화

무료2026-03-05#JS#JavaScript语言精粹

서두에

많은 서평과 독서 노트에서《JavaScript 언어 정수》는 자자주玑라고 하며, 명불허전입니다.. 물론, 이해해야 하지만

사실 개인적으로 함수화 부분은 그렇게 좋지 않다고 생각합니다. 든 예가 매우 적절하지 않으며, 이전에 이해하지 못한 것은 성공적으로 오도되었기 때문입니다. 《Head First》디자인 패턴 제 1 장《전략 패턴》 과 마찬가지로, 저자가 일부 장의 테마에서 벗어나 독자가 오도되기 쉽습니다

성명: 일단 함수화 부분에서 제공된 객체를 생성하는 함수를*"창조 함수"*라고 부르겠습니다. "생성자 함수"와 구분하기 위해.. 그다지 좋은 이름은 아니지만, 참으면서 사용합시다

일.소스 코드에서 주의할 점

쉽게 소스 코드를入手할 수 있으며, 중국어판 책의 코드와 같습니다. 자세히 살펴보니 매우 교묘한 점 하나를 발견했지만, 물론, 이해하기 쉽지 않습니다

P.S. 소스 코드에 작은 문제가 있습니다: "창조 함수"cat 의 중괄호가 일치하지 않습니다. 중국어판 54 페이지, return that; 앞에};가 부족합니다

###Object 의 프로토타입 함수 superior 내부에 매우 교묘한 점이 있습니다

Object.method('superior', function (name) {
    var that = this,
        method = that[name];
    return function (  ) {
        return method.apply(that, arguments);
    };
});

하이라이트는 마지막 문장의 arguments 로, 일견 무심해 보이지만 실제로는 의도적인 것으로, superior 로 부모 클래스 메서드를 호출할 때도 매개변수를 전달할 수 있음을 나타냅니다. 물론, 매개변수를 전달하려면 호출 방식을 수정해야 합니다. 테스트 코드는 다음과 같습니다:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

var mammal = function (spec) {
    var that = {};

    that.get_name = function (  ) {
        return spec.name;
    };

    that.says = function (  ) {
        return spec.saying || '';
    };

    return that;
};

var cat = function (spec) {
    spec.saying = spec.saying || 'meow';
    var that = mammal(spec);
    that.purr = function (n) {
        var i, s = '';
        for (i = 0; i < n; i += 1) {
            if (s) {
                s += '-';
            }
            s += 'r';
        }
        return s;
    };
    that.get_name = function (  ) {
        alert("cat.get_name :" + arguments.length);///
        return that.says(  ) + ' ' + spec.name +
                ' ' + that.says(  ) + "[" + arguments.length + "]";
    };
    
    return that;
};

Object.method('superior', function (name) {
    var that = this,
        method = that[name];
    return function (  ) {
        alert("superior :" + arguments.length);///
        return method.apply(that, arguments);
    };
});

var coolcat = function (spec) {
    var that = cat(spec),
        super_get_name = that.superior('get_name');
    that.get_name = function () {
        alert("coolcat.get_name :" + arguments.length);///
        return 'like ' + super_get_name.apply(this, arguments) + ' baby';
    };
    return that;
};

var myCoolCat = coolcat({name: 'Bix'});
var name = myCoolCat.get_name(1, 2, 3);
//        'like meow Bix meow baby'


alert(name);    // 'like meow Bix meow[3] baby'

P.S. 처음에는 superior 함수의 마지막 arguments 가 저자의 실수라고 생각했고, 바깥의 arguments 객체를 안쪽이 아닌 method 에 전달해야 한다고 생각했습니다. 크게 우회하여 자신이 틀렸다는 것을 발견했습니다. 도행이 부족하여 더글라스様の 의미를 순간적으로 이해하지 못했습니다..

이.함수화의 취지

함수화 부분은 서두에서취지: 프라이빗 속성을 구현하기 위해, 마지막에 언급된 "위조 방지 객체"를 생성하는 것이라고 설명했습니다

목적은 비난의 여지가 없으며, 프라이빗 속성을 구현하는 것은 매우 필요합니다. 하지만 든 예 mammal -> cat -> coolcat 은 너무도 부적절합니다. 저자는 함수화 방식으로 상속을 구현할 수 있음을 설명하고 싶었습니다

물론, 엄밀한 의미에서의 상속은 아닙니다. 함수화 방식은 커스텀 타입을 사용하지 않았기 때문에, 서브클래스 인스턴스와 부모 클래스 인스턴스의 is-a 관계에 대해 논할 여지가 없습니다

P.S. 첫 번째로 볼 때 cat 의 예가 저를 골목으로 이끌었고, 함수화는 new 를 버리고 완전히 함수로 상속을 구현하는 것이라고 생각했습니다.. 자연스럽게 골목에서越走越深해졌습니다

삼.함수화의 사상

직접 코드를 봅시다. 코드 자신이 말합니다:

/*
 * 함수화의 사상:
 * 1.객체 생성
 * 2.프라이빗 속성 추가
 * 3.공개 인터페이스 (퍼블릭 속성 추가)
 * 4.해당 객체 반환
 */
/*
 * method: getSuper
 * @param spec 사양 설명 객체, 객체 생성에 필요한 기본 데이터 제공
 * @param my "창조 함수" 간 데이터 공유 컨테이너
 */
function getSuper(spec, my){
    var obj;            // 반환할 객체
    var my = my || {};  // 전달되지 않으면 생성
    
    // 프라이빗 속성
    var attr = spec.value;  // ���양 설명 객체에서 데이터 취득
    var fun = function(){
        alert(attr);
    }
    
    // [옵션] 다른 "창조 함수"와 공유해야 하는 데이터를 my 에装入
    
    // 객체 생성, 임의의 방식 사용 가능, 예: new, 리터럴, 다른 "창조 함수" 호출
    obj = {
        name: "SuperObject"
    };
    
    // 공개 인터페이스
    obj.fun1 = fun;
    
    // obj 반환
    return obj;
}

/*
 * method: getSub
 * 파라미터는 위와 동일
 */
function getSub(spec, my){
    var obj;
    var my = my || {};
    
    // 프라이빗 속성
    var attr = spec.value + 1;
    var fun = function(){
        alert(attr);
    }
    
    // [옵션] 공유
    
    // 객체 생성
    obj = getSuper(spec, my);   // 직접 전달 가능, 물론 수정하여 전달하거나 다른 것 전달도 가능
    
    // 공개 인터페이스
    obj.fun2 = fun;
    
    // obj 반환
    return obj;
}

// 테스트
var spec = {
    value: 1
};
var sub = getSub(spec); // my 를 전달할 필요 없음, my 는 "창조 함수" 간에만 사용해야 함
sub.fun1(); // 1
sub.fun2(); // 2

P.S. 또 "객체 생성 -> 강화 -> 새로운 객체 반환" 이套路입니다. 니콜라스가 말한 더글라스가 발명한 "모듈 패턴"이 아닙니까?

사.위조 방지 객체 (지속성의 객체)

함수화 부분의 핵심은 이것입니다. 위 예의 공개 인터페이스 방식에 주의하십시오:

// 프라이빗 속성
var myFun = function(){/* ... */};
// 공개 인터페이스
obj.fun = myFun;

직접 다음을 사용하는 것이 아니라:

// 공개 인터페이스
obj.fun = function(){/* ... */};

첫 번째 방식*더 안전*합니다. 외부에서 fun 을 수정해도, 내부의 다른 myFun 을 호출하는 메서드는 계속 정상적으로 작동할 수 있기 때문입니다. 이러한 함수 객체가 소위*위조 방지 객체*입니다

완전한 정의:

위조 방지 객체의 속성은 치환 또는 삭제 가능하지만, 해당 객체의 완전성은 훼손되지 않습니다

지속성의 객체라고도 하며, 지속성 객체란 단순한 기능 함수의 집합입니다

후일담

이로써《JavaScript 언어 정수》의 학습 노트는 한 단락 마무리되었습니다. [함수화] 의 공백을 메웠으며, 학습 노트의 다른 부분은 [黯羽輕揚:《JavaScript 언어 정수》학습 노트](http://ayqy.net/blog/《JavaScript 언어 정粹》学习笔记/) 를 참조하십시오

댓글

아직 댓글이 없습니다

댓글 작성