我的js类

js类有很多中写法,网上也有很多现成的库,都有各自的优缺点,但用起来都不太顺手。所以总结改进后,写了自己的类,只图用起来顺手,看起来顺眼。

比较喜欢mootools,语法和它类似。initialize为构造方法,statics为静态属性及方法,superclass为父类;在当前方法中调用父类方法使用this.callSuper(),在当前方法中调用父类的其它方法this.invokeSuper('methodName').execute(args);

js中类的写法有一个痛点,即没法完全实现私有属性方法、受保护属性方法。mootools中有相关的内容,但也只是在继承的层面上实现部分功能,并不能控制一个对象外部对私有方法、受保护方法的访问。

使用方法如下:

 

Class('myclass.A',{
	initialize:function(){
		this.name='A';
	},
	showName:function(){
		alert(this.name);
	}	
});
Class('myclass.B',{
	superclass:myclass.A,
	initialize:function(){
		this.name='B';
	},
	showSuperName:function(){
		this.invokeSuper('showName').execute();
	},
	showName:function(){
		alert('<<<')
		this.callSuper();
		alert('>>>')
	}	
});
var a=new myclass.A();
a.showName();
var b=new myclass.B();
b.showName();
var b=new myclass.B();
b.showSuperName();


源码如下,仍需完善,仅供大家参考。

 

(function () {
    var noArgs = [],
        emptyFn = function () {
        },
        noInvokeResult = {
            execute: emptyFn
        },
        invokeSuperResult = {
            execute: function () {
                var result = this.method.apply(this.obj, arguments || noArgs);
                this.obj = null;
                this.method = null;
                return result;
            }
        },
        enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];

    function namespace() { // namespace
        var a = arguments,
            o = null,
            i,
            j,
            d,
            rt;
        for (i = 0; i < a.length; ++i) {
            d = a[i].split(".");
            rt = d[0];
            eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
            for (j = 1; j < d.length; ++j) {
                o[d[j]] = o[d[j]] || {};
                o = o[d[j]];
            }
        }
        return o;
    }

    function inherit(C, superClass) {
        if (typeof(superClass) != 'function') {
            return C;
        }
        function F() {}
        F.prototype = superClass.prototype;
        C.prototype = new F();
        C.prototype.constructor = C;
        C.superclass = superClass;
        return C;
    }
    function addMethods(C, methods) {
        var p = C.prototype;
        for (var name in methods) {
            var m = methods[name];
            m['_name_'] = name;
            m['_owner_'] = C;
            p[name] = m;
        }
        return C;
    }

    //TODO 1、需增加获取静态属性、方法的方法2、增加获取祖先的方法ancestor
    function callSuper() {
        var method = arguments.callee.caller,
            superMethod;
        if (method) {
            if (method._owner_) {
                superMethod = method._owner_.superclass.prototype[method._name_];
            } else if (method.superclass) {
                superMethod = method.superclass;
            } else {
                superMethod = emptyFn;
            }
            return superMethod.apply(this, arguments || noArgs);
        }
    }

    var staticUtil = {
        getStatic: function (name) {
            return this.constructor[name];
        }
    };

    var invokeSuper = (function () {
        var obj, superMethod,
            proxyResult = {
                execute: function () {
                    var result = superMethod.apply(obj, arguments || noArgs);
                    obj = null;
                    superMethod = null;
                    return result;
                }
            };

        function proxy(name) {
            try {
                superMethod = proxy.caller._owner_.superclass.prototype[name];
                if (!superMethod) {
                    throw(0);
                }
                obj = this;
                return proxyResult;
            } catch (e) {
                throw(new Error("[invokeSuper error]: the method " + name + "'s super is not exist!"));
            }
        }

        return proxy;
    })();

    function Class() {
        var options,
            initialize,
            superclass,
            statics,
            mixin,
            fullName,
            className,
            path;
        if (arguments.length == 1) {
            options = arguments[0];
        } else if (arguments.length == 2) {
            fullName = arguments[0];
            path = fullName.split(".");
            className = path.pop();
            if (path.length > 0) {
                path = namespace(path.join('.'));
            } else {
                path = window;
            }
            options = arguments[1];
        } else {
            fullName = "";
            className = "";
        }
        if ('initialize' in options) {
            initialize = options['initialize'];
            delete options['initialize'];
        } else {
            initialize = function () {
            };
        }
        // TODO火狐中name属性无法赋值
        if (options.hasOwnProperty('statics')) {
            statics = options['statics'];
            for (var k in statics) {
                if (statics.hasOwnProperty(k)) {
                    initialize[k] = statics[k];
                }
            }
            delete options['statics'];
            addMethods(initialize, staticUtil);
        }
        if ('superclass' in options) {
            superclass = options['superclass'];
            if (superclass) {
                inherit(initialize, superclass);
                superclass.prototype.callSuper || addMethods(initialize, {
                    callSuper: callSuper,
                    invokeSuper: invokeSuper
                });
                delete options['superclass'];
            } else {
                throw TypeError("the superclass of '" + fullName + "' is undefined!");
            }
        }
        addMethods(initialize, options);
        if (options.hasOwnProperty('mixin')) {
            mixin = options['mixin'];
            if(mixin.length&&mixin.pop){
                for(var i=0;mixin[i]!=undefined;i++){
                    addMethods(initialize,mixin[i]);
                }
            }else{
                addMethods(initialize,mixin);
            }
            delete options['mixin'];
        }
        if (className) {
            path[className] = initialize;
            path = arguments[0];
        }
        initialize._isClass_ = true;
        initialize._name_ = className;
        initialize._fullName_ = fullName;
        return initialize;
    }
    window.Class = Class;
})();



你可能感兴趣的:(我的js类)