`
绿窗明月
  • 浏览: 3305 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

我的js类(续)

阅读更多

之前的写过一篇关于js类的《文章》,主要是贴了一下代码和用法,功能上也有些欠缺。新版的Class增加了私有属性、接口两个功能。需要注意的是继承、调用父类方法、使用私有方法都是很耗费资源的,如果非得使用尽量减少继承的层数。(本人的小demo大笑

主要贴一下私有属性和接口用法:

1、私有属性

 

//设置私有属性this.$(key,value);获取私有属性:this.$(key);
Class('Dog',{
	initialize:function(){
		//为Dog设置私有属性name
		this.$('name','dog');
	},
	speak:function(){		
		//打印Dog私有属性name
		console.log('Dog name is ',this.$('name'));
	}
	
})
Class('BlackDog',{
	superclass:Dog,
	initialize:function(){
		this.callSuper();
		//为BlackDog也设置私有属性name,检查子类和父类里的私有属性是否冲突
		this.$('name','blackdog');
	},
	speak:function(){
		this.callSuper();
		//打印BlackDog私有属性name
		console.log('BlackDog name is ',this.$('name'));
	}
})
//正确结果应该Dog里的name和BlackDog里的name没有关系,BlackDog不能覆盖Dog里的私有属性
var blackdog=new BlackDog();
blackdog.speak();

结果为:

 

Dog name is dog
BlackDog name is blackdog


2、接口

 

Interface('Animal',['eat']);//接口名称、方法
Class('Pig',{
	interfaces:[Animal]
})
Interface('Animal',['eat']);//接口名称、方法
Class('Cat',{
	interfaces:[Animal],
	eat:function(){
		
	}
})

结果为:

报错:Error: the method 'eat' need to implement in class 'Pig'!

 

下边是新版的源码:

 

(function () {
    var emptyArgs = [],
        emptyFn = function () {
        },
    //暂时未用
        noInvokeResult = {
            execute: emptyFn
        },
    //暂时未用
        invokeSuperResult = {
            execute: function () {
                var result = this.method.apply(this.obj, arguments || emptyArgs);
                this.obj = null;
                this.method = null;
                return result;
            }
        },
    //暂时未用
        enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
    //命名空间
    function namespace() { // namespace
        var a = arguments,
            al = a.length,
            o = null,
            i,
            j,
            d,
            dl,
            rt;
        for (i = 0; i < al; ++i) {
            d = a[i].split(".");
            rt = d[0];
            eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
            dl = d.length;
            for (j = 1; j < dl; ++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 bindMethods(object, methods) {
        for (var name in methods) {
            if (methods.hasOwnProperty(name)) {
                object[name] = methods[name];
            }
        }
    }

    //添加方法到原型
    function addMethods(C, methods) {
        var p = C.prototype,
            _methods_ = C._methods_;
        for (var name in methods) {
            var m = methods[name];
            p[name] = m;
            if (name != 'callSuper' && name != 'invokeSuper') {
                m['_name_'] = name;
                m['_owner_'] = C;
                if (_methods_.indexOf(name) == -1) {
                    _methods_.push(name);
                }
            }
        }
        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._wrapper_) {
                superMethod = method._wrapper_.superclass;
            } else {
                superMethod = emptyFn;
            }
            return superMethod.apply(this, arguments || emptyArgs);
        }
    }

    //暂时未用
    var staticUtil = {
        getStatic: function (name) {
            return this.constructor[name];
        }
    };

    //使用方法名调用父类方法
    var invokeSuper = (function () {
        var obj,
            superMethod,
            proxyResult = {
                execute: function () {
                    var result = superMethod.apply(obj, arguments || emptyArgs);
                    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 createPrivateClosure() {
        var privateProperties = {};
        return function (key, value) {
            if (value == undefined) {
                return privateProperties[key];
            } else {
                privateProperties[key] = value;
            }
        }
    }

    ////////////////////////////////////////////////////////////Class///////////////////////////////////////////////////////////
    //创建类
    function Class() {
        var clazz,
            options,
            initialize,
            interfaces,
            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 (options.hasOwnProperty('initialize')) {
            initialize = options['initialize'];
            delete options['initialize'];
        } else {
            initialize = function () {
            };
        }
        statics = options.hasOwnProperty('statics') ? options['statics'] : false;

        clazz = function () {
            var self = this,
            //私有属性的赋值、取值方法
                $ = function (key, value) {
                    var $method = arguments.callee,
                        caller = $method.caller,
                        callerClass = caller._owner_ || caller._wrapper_;
                    if (callerClass == $method._owner_) {
                        return $method.$$(key, value);
                    } else {
                        $method = $method._super_;
                        while ($method) {
                            if (callerClass == $method._owner_) {
                                break;
                            }
                            $method = $method._super_;
                        }
                    }
                    return $method.$$(key, value);
                };
            $.$$ = createPrivateClosure();
            $._owner_ = clazz;
            if (self.$) {
                $._super_ = self.$;
            }
            self.$ = $;

            //增加静态方法到实例本身
            statics && bindMethods(self, statics);
            initialize.apply(self, arguments);
        };
        initialize._wrapper_ = clazz;
        clazz._isClass_ = true;
        clazz._name_ = className;
        clazz._fullName_ = fullName;
        clazz._methods_ = [];
        clazz._interfaces_ = [];
        interfaces = options['interfaces'];
        mixin = options['mixin'];
        delete options['interfaces'];
        delete options['mixin'];

        //增加静态方法到类
        if (statics) {//TODO 火狐中name属性无法赋值
            for (var k in statics) {
                if (statics.hasOwnProperty(k)) {
                    clazz[k] = statics[k];
                }
            }
            delete options['statics'];
            addMethods(clazz, staticUtil);
        }

        //继承父类
        if (options.hasOwnProperty('superclass')) {
            superclass = options['superclass'];
            if (superclass) {
                inherit(clazz, superclass);
                superclass.prototype.callSuper || addMethods(clazz, {
                    callSuper: callSuper,
                    invokeSuper: invokeSuper
                });
                delete options['superclass'];
            } else {
                throw TypeError("the superclass of '" + fullName + "' is undefined!");
            }
        }

        //添加公有方法到类
        addMethods(clazz, options);

        //添加mixin方法到类
        if (mixin) {
            if (mixin.length && mixin.pop) {
                for (var i = 0; mixin[i] != undefined; i++) {
                    addMethods(clazz, mixin[i]);
                }
            } else {
                addMethods(clazz, mixin);
            }
            delete options['mixin'];
        }

        //实现、检查接口
        if (interfaces) {
            var _interfaces_ = clazz._interfaces_,
                _methods_ = clazz._methods_;
            if (!(interfaces instanceof Array)) {
                interfaces = [interfaces];
            }

            for (var i = 0, inter, methodName; interfaces[i] != undefined; i++) {
                inter = interfaces[i];
                for (var j = 0; inter[j] != undefined; j++) {
                    methodName = inter[j];
                    if (_methods_.indexOf(methodName) == -1) {
                        throw new Error("the method '" + methodName + "' need to implement in class '" + fullName + "'!");
                    }
                }
                _interfaces_.push(inter);

            }
        }
        if (className) {
            path[className] = clazz;
            path = arguments[0];
        }
        return clazz;
    }

    window.Class = Class;
    //命名空间
    Class.ns = namespace;
    //根据路径获取类
    Class.get = function (source) {
        try {
            var path = source.split('.'),
                obj = window[path[0]];
            if (path.length > 1) {
                for (var i = 1; path[i] != undefined; i++) {
                    obj = obj[path[i]];
                }
            }
            return obj;
        } catch (e) {
            throw new TypeError("no such class '" + source + "' is defined!");
        }
    };
    //为类设置别名
    Class.alias = function (source, alias) {
        var clazz,
            path = alias.split('.'),
            aliasName = path.pop(),
            aliasPath = path.join('.');
        if (typeof source == 'string') {
            clazz = Class.get(source);
        } else if (source._isClass_) {
            clazz = source;
        }
        if (clazz) {
            if (aliasPath) {
                namespace(aliasPath);
                Class.get(aliasPath)[aliasName] = clazz;
            } else {
                window[aliasName] = clazz;
            }
        }
    };
    ////////////////////////////////////////////////////////////Interface///////////////////////////////////////////////////////////
    function _interface(fullName, methods) {
        this.fullName = fullName;
        for (var i = 0; methods[i] != undefined; i++) {
            this[i] = methods[i]
        }
    }

    function Interface(fullName, methods) {
        if (methods instanceof Array) {
            var path = fullName.split("."),
                className = path.pop();
            if (path.length > 0) {
                path = namespace(path.join('.'));
            } else {
                path = window;
            }
            path[className] = new _interface(fullName, methods);
        } else {
            throw new Error("Interface '" + fullName + "' second must be Array!");
        }
    }

    window.Interface = Interface;
})();

代码还需改进,努力中奋斗

分享到:
评论

相关推荐

    Javascript 类与静态类的实现(续)

    这东西在Javascript里用得会非常的频繁,因为针对现在的网页,多个基于同一个类对象的页面不多,往往不同块对象的交互就可以解决问题了,这就需要在JS针对元素定义几个静态类就可以完事了,进入正题。

    C# 常用类代码(封装)

    7.js.cs 常用js代码 8.文件操作类 9.数据检查类 10.util.cs常用字符串操作 11.CacheManager.cs 操作缓存的类 12.CookieManager.cs Cookie管理类 13.DataToExcel.cs 导出excel 14.EnumConvert 枚举转换为详细说明的类...

    C#基类库(苏飞版)

    JsHelper--Javascript操作帮助类,输出各种JS方法,方便不懂JS的人使用,减少代码量 7.JSON 转化类 ConvertJson List转成Json|对象转成Json|集合转成Json|DataSet转成Json|DataTable转成Json|DataReader转成Json...

    如何编写高质量JS代码(续)

    继续上一篇文章《如何编写高质量JS代码》今次整理一下javascript函数知识点。 2.使用函数 函数给程序员提供了主要的抽象功能,又提供实现机制。函数可以独立实现其他语言中的多个不同的特性,例如,过程、方法、构造...

    tool-upload:SpringBoot秒传、分片、续传工具-demo样例

    uploader 大文件、断点续传、分片、秒传、普通文件上传样例工具类包封装了一些关于分片md5验证、断点续传、分片上传、等方法前端样例使用百度插件 WebUploader , 插件的源码还是有一定的问题的样例包对插件源码做了...

    基于Java的的文件图片上传-分片上传-断点续传-秒传java源码.zip

    4.图片上传部分:在文件上传部分已有功能的基础上实现了上传前缩略图预览,前台js文件后缀验证,后台代码文件后缀验证和文件类型验证(就算修改后缀名也无法成功上传),支持图片上传前压缩; 5.多选择器多文件上传...

    断点续传构件_V1.0.zip

    利用webuploader实现bs端的断点续传,利用webuploader的多线程分片上传机制,利用分片md5校验断点。请直接查看jsp和java类,无视架构问题,需要下载webuploader的js和css,jar包自行下载

    supermap学习系列之silverlight--添加可拖拽的定位图钉(方法二之超图自带类(Pushpin、InfoWindow)) 续 解决上一篇的问题

    学习笔记,方便以后查阅。解决上一篇留下的问题。拖拽图钉,弹出交互信息窗口。读取和使用交互窗口中的控件。

    C#基础类库

    JsHelper--Javascript操作帮助类,输出各种JS方法,方便不懂JS的人使用,减少代码量 7.JSON 转化类 ConvertJson List转成Json|对象转成Json|集合转成Json|DataSet转成Json|DataTable转成Json|DataReader转成Json...

    Humans_Emotions_Codes-:函数,对象和类(续... 2)和“继承”

    Humans_Emotions_Codes- 函数,对象和类(续... 2)和“继承”

    Android开发资料合集--续

    比之前的合集更丰富详细的细节;没有最新只有更新! 1、建立GPRS连接 4 2、判断网络状态是否可用 4 3、获得惯性滑动的位置 5 ...103、JS 148 104、TextView多行末尾显示省略号 148 105、竖直显示的textView 153

    fastdfs基于http协议的分布式文件系统源码,基于go和js.rar

    fastdfs基于http协议的分布式文件系统源码,基于go和js,它具有高性能、高可靠、无中心、免维护等优点。 ### 大家担心的是这么简单的文件系统,靠不靠谱,可不可以用于生产环境?答案是肯定的,正因为简单所以高效...

    iwebshop2.4.13051710

    2,解决了地区运费单独设定续重时,运费计算错误问题 3,后台首页增加了退款申请的展示 4,优化了城市js联动 5,修复了收藏夹弹出bug 6,修复了团购,抢购等js错误和计时错误问题 7,修复了退款申请拒绝时弹出退款...

    asp.net知识库

    完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎 正式发布表达式计算引擎WfcExp V0.9(附源码) 运算...

    踱步狼代码注释清理 StrollingWolfv1.0.rar

    支持c/c++, h,hpp,cxx,js,java,php等类C语言的注释清理,支持自定义后缀名 2。支持utf8,ansi,gb2312,gb18030,gbk, and gbxx 3。支持xp, win7及以上32/64 windows系统 4。支持行注释//.... 5。支持续行注释//....\ 6...

    核心:MyAEGEE的核心模块,管理用户,本地组和成员身份

    lib/server.js端点列表和实际的服务器启动lib/cron.js后台任务和运行它们的包装器lib/permission-manager.js一个用于计算权限相关内容的类我如何... ...运行测试? 只需在本地文件夹中运行npm test 。 不要忘记运行...

    30道iOS底层面试题(下)

    类簇的优缺点; App启动的完整过程; SDWebImage原理; 三次握⼿与四次挥⼿; 怎么防⽌反编译; CTMediator⽅案; Block⼀定会造成强引⽤吗; 断点续传; JS原理; 组件化过程; 分类的底层实现; 监控、优化 APP...

    vc++ 开发实例源码包

    该实例可进行局域网的聊天、一对多、多对一、和多对多的传送和续传,理论上这是我本人的实现目的,而且目前经测试已基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit的使用、最小到...

    vc++ 应用源码包_1

    该实例可进行局域网的聊天、一对多、多对一、和多对多的传送和续传,理论上这是我本人的实现目的,而且目前经测试已基本实现了上述功能,而且网速一般有几M/S。另外有只打开一个应用程序、CRichEdit的使用、最小到...

Global site tag (gtag.js) - Google Analytics