자바 script (3): 클래스 와 모듈 을 전혀 모 릅 니 다.

본문 은 최초 로 발표 되 었 다.http://szhshp.org/tech/2017/02/18/JavaSprite.html 전재 하 다
클래스 와 모듈
공장 함수
function range(from, to) {
    var r = inherit(range.methods);         //                    
    r.from = from;
    r.to = to;

    return r;
};


range.methods = {

    includes: function (x) {
        return this.from <= x && x <= this.to;
    },

    foreach: function (f) {
        for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
    },
    toString: function () {
        return "(" + this.from + "..." + this.to + ")";
    }
}

// Here are example uses of a range object.
var r = range(1, 3);                        // Create a range object
r.includes(2);                              // => true: 2         
r.foreach(console.log);                     // Prints 1 2 3
console.log(r);                             // Prints (1...3)
  • 여기 서 range() 함수 에 정의 류 의 원형 대상 을 신속하게 저장 하 는 속성 range.method 을 정의 했다.
  • 클래스 의 속성 fromto 은 모두 비공 유 속성 으로 계승 할 수 없습니다
  • 공장 함수 대신 구조 함수 사용
    function Range(from, to) {      //               
        this.from = from;
        this.to = to;
    }
    
    Range.prototype = {         //  prototype       
        includes: function (x) {
            return this.from <= x && x <= this.to;
        },
    
        foreach: function (f) {
            for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
        },
        toString: function () {
            return "(" + this.from + "..." + this.to + ")";
        } };
    
    var r = new Range(1, 3);                        //     obj          new
    r.includes(2);                                  // => true: 2 is in the range
    r.foreach(console.log);                         // Prints 1 2 3
    console.log(r);                                 // Prints (1...3)
    
  • 일반 함수 방법 은 일반적으로 모두 이니셜 소문 자 이지 만 구조 방법 은 이니셜 대문자
  • 가 필요 하 다.
  • 그 다음 에 호출 할 때 키워드 new 를 추가 해 야 합 니 다. 이 경우 호출 inherit() 방법 이 필요 없습니다
  • 생 성자 속성
    var F = function() {};             // This is a function object.
    var p = F.prototype;            // This is the prototype object associated with it.
    var c = p.constructor;         // This is the function associated with the prototype.
    c === F;                      // => true: F.prototype.constructor==F for any function
    //      ,F.prototype.constructor == F
    
    var o = new F();              // Create an object o of class F
    o.constructor === F;          // => true: the constructor property specifies the class
    

    클래스 확장
    원형 에 대응 하 는 방법 이 없 으 면 대응 하 는 방법 을 초기 화 합 니 다.
    // ES3       bind  
    if (!Function.prototype.bind) {
        Function.prototype.bind = function (o /*, args */) {
            // Code for the bind method goes here... };
        }
    }
    

    간단 한 예:
    var n = 3;
    n.times(function (n) {
        console.log(n + " hello");
    });
    //     Number,string/function        
    Number.prototype.times = function (f, context) {
        var n = Number(this);
        for (var i = 0; i < n; i++) f.call(context, i);
    };
    
    String.prototype.trim = String.prototype.trim || function () {
        if (!this) return this;  // Don't alter the empty string
        return this.replace(/^\s+|\s+$/g, "");  // Regular expression magic
    };
    
    Function.prototype.getName = function () {
        return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];
    };
    

    원형 에 추가 하 는 방법 은 모든 대상 이 이 방법 을 사용 할 수 있 게 한다.
    유형
    대상 클래스 를 검사 하 는 데 세 가지 방법 이 있 습 니 다.
    instanceof/isprototypeof
    단점:
  • 대상 을 통 해 클래스 명 을 얻 을 수 없고 대상 이 특정 클래스 에 속 하 는 지 검사 할 수 밖 에 없다
  • 다 중 창 과 다 중 프레임 워 크 의 웹 응용 프로그램 호 환 에 문제 가 있 음
  • Constructor
            function typeAndValue(x) {
                if (x == null) return "";
                switch (x.constructor) {
                    case Number:return "Number:" + x;
                    case String:return "String: '" + x + "'";
                    case Date:return "Date: " + x;
                    case RegExp:return "Regexp: " + x;
                    case Complex:return "Complex: " + x;
                }
            }
    

    단점:
  • 다 중 창 과 다 중 프레임 워 크 의 웹 응용 프로그램 호 환 에 문제 가 있 음
  • 주의 case 뒤의 표현 식 은 모두 함수 입 니 다.typeof 를 사용 하면 다음 과 같은 문자열 을 얻 을 수 있 습 니 다.
    function type(o) {
        var t, c, n;  // type, class, name
    // Special case for the null value:
        if (o === null) return "null";
    // Another special case: NaN is the only value not equal to itself:
        if (o !== o) return "nan";
    // Use typeof for any value other than "object".
    // This identifies any primitive value and also functions.
        if ((t = typeof o) !== "object") return t;
    // Return the class of the object unless it is "Object".
    // This will identify most native objects.
        if ((c = classof(o)) !== "Object") return c;
    // Return the object's constructor name, if it has one
        if (o.constructor && typeof o.constructor === "function" && (n = o.constructor.getName())) return n;
    // We can't determine a more specific type, so return "Object"
        return "Object";
    }
    
    
    // Return the class of an object.
    function classof(o) {
        return Object.prototype.toString.call(o).slice(8, -1);
    };
    // Return the name of a function (may be "") or null for nonfunctions
    Function.prototype.getName = function () {
        if ("name" in this) return this.name;
        return this.name = this.toString().match(/function\s*([^(]*)\(/)[1];
    };
    

    그 밖 에 모든 대상 이 Constructor 속성 을 가지 고 있 는 것 이 아니 라 익명 함수 가 전형 적 인 것 이다.
    // This constructor has no name
    var Complex = function (x, y) {
        this.r = x;
        this.i = y;
    }
    // This constructor does have a name
    var Range = function Range(f, t) {
        this.from = f;
        this.to = t;
    }
    

    JS 대상 기술
    전면적 이 고 전형 적 인 순수한 OOP 예:
    function Set() {          // This is the constructor
        this.values = {};     // The properties of this object hold the set
        this.n = 0;           // How many values are in the set
        this.add.apply(this, arguments);  // All arguments are values to add
    }
    
    // Add each of the arguments to the set.
    Set.prototype.add = function () {
        for (var i = 0; i < arguments.length; i++) {  // For each argument
            var val = arguments[i];                  // The value to add to the set
            var str = Set._v2s(val);                 // Transform it to a string
            if (!this.values.hasOwnProperty(str)) {  // If not already in the set
                this.values[str] = val;              // Map string to value
                this.n++;                            // Increase set size
            }
        }
        return this;                                 // Support chained method calls
    };
    
    // Remove each of the arguments from the set.
    Set.prototype.remove = function () {
        for (var i = 0; i < arguments.length; i++) {  // For each argument
            var str = Set._v2s(arguments[i]);        // Map to a string
            if (this.values.hasOwnProperty(str)) {   // If it is in the set
                delete this.values[str];             // Delete it
                this.n--;                            // Decrease set size
            }
        }
        return this;                                 // For method chaining
    };
    
    // Return true if the set contains value; false otherwise.
    Set.prototype.contains = function (value) {
        return this.values.hasOwnProperty(Set._v2s(value));
    };
    
    // Return the size of the set.
    Set.prototype.size = function () {
        return this.n;
    };
    
    // Call function f on the specified context for each element of the set.
    Set.prototype.foreach = function (f, context) {
        for (var s in this.values)                 // For each string in the set
            if (this.values.hasOwnProperty(s))    // Ignore inherited properties
                f.call(context, this.values[s]);  // Call f on the value
    };
    
    Set._v2s = function (val) {         //        ,              
        switch (val) {
            case undefined:
                return 'u';          // Special primitive
            case null:
                return 'n';          // values get single-letter
            case true:
                return 't';          // codes.
            case false:
                return 'f';
            default:
                switch (typeof val) {
                    case 'number':
                        return '#' + val;    // Numbers get # prefix.
                    case 'string':
                        return '"' + val;    // Strings get " prefix.
                    default:
                        return '@' + objectId(val); // Objs and funcs get @
                }
        }
    
        // For any object, return a string. This function will return a different
        // string for different objects, and will always return the same string
        // if called multiple times for the same object. To do this it creates a
        // property on o. In ES5 the property would be nonenumerable and read-only.
        function objectId(o) {
            var prop = "|**objectid**|";   // Private property name for storing ids
            if (!o.hasOwnProperty(prop))   // If the object has no id
                o[prop] = Set._v2s.next++; // Assign it the next available
            return o[prop];                // Return the id
        }
    };
    Set._v2s.next = 100;    // Start assigning object ids at this value.
    

    반환 값 을 통 해 클래스 를 설정 하 는 다른 방법
    function Test() {
        var map = 1;
        function a(){
            map = 2;
        }
        function b(){
            console.log(map);
        }
        return{
            a:a,
            b:b
        }
    }
    var t = new Test()
    

    후자 에 대해:
  • 마지막 return 에 map 가 포함 되 어 있 으 면 b () 를 어떻게 실행 하 든 이 map 의 값 은 변 하지 않 습 니 다. Obj 가 추가 공간
  • 이기 때 문 입 니 다.
  • 물론 여기 도 반환 치 를 놓 지 않 아 도 됩 니 다
  • 값 을 되 돌려 주 는 방법 은 부분 인터페이스
  • 를 닫 기 위 한 것 이다.
  • 더 큰 차이 점 은 두 번 째 모델 안의 방법 을 다시 쓰기 어렵 다 는 것 이다
  • .
    하위 클래스
    원서 의 하위 내용 이 비교적 번 거 로 우 므 로 다음 과 같은 몇 단계 로 요약 할 수 있다.
  • prototype 에서 정 의 된 속성 과 방법 을 계승 합 니 다.
  • 구조 함수 에서 정 의 된 속성 과 방법 을 계승 한다.
  • 하위 클래스 의 prototype 대상 을 수정 하 는 constructor 포인터
  • function Animal(name) {  
        this.name = name;  
    }  
    Animal.prototype.set = "female";
    Animal.prototype.info = function () {
            console.log("animal");  
    }
    
    function People(name) {  
        this.name = name;  
    }  
    People.prototype = new Animal("animal");  //              ;
    People.prototype.info = function() {  //             ;
        console.log("peopel")  
    };  
    
    //Demo
    var cat = new Animal('cat');
    
    console.log(cat instanceof Animal);    //t
    console.log(cat instanceof Object);    //t
    console.log( typeof Animal.prototype);      //object  
    console.log( typeof Animal.constructor);        //function  
    console.log(Animal.prototype.constructor == Animal);    //true  
    
    
    var mike = new People("mike");  
    console.log(mike.sex);//female  
    mike.info();//People  
    
    console.log(mike instanceof People);    //t
    console.log(mike instanceof Animal);    //t
    console.log(mike instanceof Object);    //t
    console.log( typeof Animal.prototype);      //object  
    console.log( typeof Animal.constructor);        //function  
    console.log(People.prototype.constructor == People);    //true  
    
    

    클래스 패키지
    간단 한 포장 방법:
  • 사용 var 키워드 설정 사유 속성
  • 차단 류 의 확장: 사용 Object.seal() 가능 하지만 이 경우 속성
    Object.seal(mike);
    mike.sex = 'male'; //      
    delete mike.sex; //Cannot delete property 'sex' 
    
  • 을 수정 할 수 있 습 니 다.
  • 차단 류 의 수정: Object.seal() 과 유사 하지만 Object.freeze 방법 은 인 스 턴 스 방법 을 쓸 수 없 는 것 으로 설정 한 경우 대응 방법 을 수정 하면 무효 가 됩 니 다
    Object.seal(mike);
    mike.sex = 'male'; //          
    
  • 모듈 화 모드
    우선 모듈 모드 의 기본 특징 을 살 펴 보 자.
  • 모듈 화, 재사 용 가능
  • 변수 와 function 을 봉 하여 전역 의 namaspace 와 접촉 하지 않 고 소나무 결합
  • 사용 가능 한 Public 방법 만 노출 하고 다른 사유 방법 은 모두 숨 깁 니 다
  • 기본 용법
    var Calculator = function (eq) {
        //          
    
        var eqCtl = document.getElementById(eq);
    
        return {
            //        
            add: function (x, y) {
                var val = x + y;
                eqCtl.innerHTML = val;
            }
        };
    };
    
    
    var calculator = new Calculator('eq');
    calculator.add(2, 2);
    

    익명 폐쇄
    (function () {
        // ...       function      ,                
        // ...                    
    }());
    

    익명 함수 뒤의 괄호 입 니 다. 이것 은 JavaScript 언어 가 요구 하 는 것 입 니 다. 성명 하지 않 으 면 JavaScript 해석 기 는 기본적으로 function 함수, 괄호 가 있 습 니 다. 함수 표현 식 을 만 드 는 것 입 니 다. 즉, 자체 실행 입 니 다. 사용 할 때 위 와 같이 new 에 있 지 않 아 도 됩 니 다. 물론 이렇게 설명 할 수 있 습 니 다.
    (function () {/*      */})();
    

    전역 변수 참조
    전역 변 수 를 익명 함수 필드 로 가 져 오기
    (function ($, YAHOO) {
        //   $      jQuery
    } (jQuery, YAHOO));//        ,                             
    

    익명 함수 필드 에서 전역 변 수 를 설정 합 니 다.
    var blogModule = (function () {
        var my = [1,2,3]
    
        return my;//                ,   blogModule    my    
    } ());
    

    물론 return 도 object 로 돌아 갈 수 있 습 니 다.
    var blogModule = (function () {
        var my = [1,2,3]
    
        return {
            my: my,
            you: null
        }
    } ());
    

    고급 용법
    변수 자체 확장
    var blogModule = (function (my) { // 2.           blogModule  blogModule   my
        var AddPhoto = function () {    // 3.    my      ,   blogModule      
            console.log(123);
        };
        return {AddPhoto: AddPhoto};
    } (blogModule)); //1.    blogModule    
    blogModule.AddPhoto()// 4.            
    

    소나무 결합 확장
    위의 확장 은 이것 blogModule 을 먼저 정의 해 야 합 니 다. 정의 되 지 않 았 을 때 초기 화 되 고 정 의 된 시간 에 직접 확장 하여 소나무 결합 의 목적 을 달성 할 수 있 습 니까?
    var blogModule = (function (my) {
    
        //          
        
        return my;
    } (blogModule || {}));  
    

    이렇게 하면 모듈 모드 를 순서대로 불 러 올 수 있 습 니 다.
    밀 착 결합 확장
    소나무 결합 확장 은 매우 크 지만 제한 이 있 을 수 있 습 니 다. 예 를 들 어 일부 속성 이나 함 수 를 다시 쓸 수 없고 초기 화 할 때 Module 의 속성 을 사용 할 수 없습니다.밀 착 결합 확장 은 로 딩 순 서 를 제한 하지만 다시 불 러 올 기 회 를 제공 합 니 다. 다음 과 같은 예 를 보십시오.
    var blogModule = (function (my) {
        var oldAddPhotoMethod = my.AddPhoto;
    
        my.AddPhoto = function () {
            //     ,     oldAddPhotoMethod      
        };
    
        return my;
    } (blogModule));
    

    서브 모듈
    blogModule.CommentSubModule = (function () {
        var my = {};
        // ...
    
        return my;
    } ());
    

    좋은 웹페이지 즐겨찾기