본문으로 건너뛰기

《JavaScript 언어 정수》의 함수화

무료2015-05-07#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 언어 정粹》学习笔记/) 를 참조하십시오

댓글

아직 댓글이 없습니다

댓글 작성