一个javascript类包装器

首先在js中如此创建一个类:

var MyClass = function () {
    /* ... */
};

MyClass.prototype.method = function() {
    /* ... */
};

要创建一个继承Base的子类:

var temp = function () {};
temp.prototype = Base.prototype;

var MyClass = function () {
    /* ... */
};
MyClass.prototype = new temp();
MyClass.prototype.method = /* ... */;

不能直接写MyClass.prototype = Base.prototype是因为后面给prototype添加method时会同时改变Base的prototype, 所以要用Base的一个实例当作MyClass的prototype.

这个实例有个隐藏的__proto__属性指向了Base的prototype, 所有直接在实例里找不到的属性都会从__proto__里找, 于是这个实例就包含了Base的全部属性成员和方法. 对这个当作MyClass的prototype的实例添加新属性也不会影响到Base的prototype, 并且能够正常的override.

一开始还创建一个空的temp构造函数是为了避免直接调用Base的构筑函数可能产生的副作用. new temp()会返回一个__proto__指向Base的prototype的实例, 但又不会执行Base构造函数.

每创建一个类都这样写真是太丑太麻烦了, 所以需要一个类包装器来方便的创建类.

首先可以写一个函数来完成new temp()的部分:

    P.create = function (func) {
        var r;
        if (typeof func !== ‘function‘) {
            func = func.constructor;
        }
        r = function () {
        };
        r.prototype = func.prototype;
        return new r;
    };

P是个人用的namespace. 如果输入的参数不是一个构筑函数而是一个普通的object, 那么会先取这个object的构造函数.

下面会用到一个浅拷贝的用来混合两个object的函数:

var _oEmpty = {};

P.mix = function (oTarget, oMix) {
    for (var i in oMix) {
        if (!(i in _oEmpty) || _oEmpty[i] !== oMix[i]) {
            oTarget[i] = oMix[i];
        }
    }
    return oTarget;
};

mix会将oMix对象中的所有属性都拷贝到oTarget对象中. 不过, 拷贝前会先将for-in取得的item与一个空object比对, 当且仅当item和空object中的元素不相同时才拷贝到oTarget中. 这样如果oMix修改了默认的toString等属性也可以拷贝到oTarget中, 反之则不会.

需要浅拷贝一个对象也可以用这个函数完成: newObj = P.mix({}, oldObj);

现在可以用mix来扩展MyClass的prototype了:

extend = function (func, obj) {
        var p = func.prototype;
        P.mix(p, obj);
        p.constructor = func;
        return func;
    };

mix之后重新把func.prototype.constructor赋值为func, 避免指向obj的constructor.

类包装函数如下:

create = function (fBase, fCons, oProto, oStatic) {
        var i, l;
        fBase = fBase || [Object];
        if (P.typeOf(fBase) !== ‘array‘) {
            fBase = [fBase];
        }
        fCons = fCons || function () {
        };
        fCons.superclass = fBase[0];
        fCons.prototype = P.create(fBase[0]);
        for (i = 1, l = fBase.length; i < l; ++i) {
            extend(fCons, fBase[i].prototype);
        }
        oProto && extend(fCons, oProto);
        oStatic && P.mix(fCons, oStatic);
        return fCons;
    };

共有4个参数:

fBase是基类的构造函数, 或者是一个多基类的数组[base, otherBase, ...], 如果输入null等就以Object为基类. 多个基类时, 用排在后面的类的属性覆盖前面的, 但以第一个作为superclass

可选参数fCons是要创建的类的构筑函数, 如果为空就用一个空函数代替

可选参数oProto是成员列表object

可选参数oStatic是静态成员列表object, 即MyClass.xxx

完整的代码:

(function (P) {
    ‘use strict‘;

    var C = function () {
        return C.create.apply(C, arguments);
    };
    C.extend = function (func, obj) {
        var p = func.prototype;
        P.mix(p, obj);
        p.constructor = func;
        return func;
    };
    C.create = function (fBase, fCons, oProto, oStatic) {
        var i, l;
        fBase = fBase || [Object];
        if (P.typeOf(fBase) !== ‘array‘) {
            fBase = [fBase];
        }
        fCons = fCons || function () {
        };
        fCons.superclass = fBase[0];
        fCons.prototype = P.create(fBase[0]);
        for (i = 1, l = fBase.length; i < l; ++i) {
            C.extend(fCons, fBase[i].prototype);
        }
        oProto && C.extend(fCons, oProto);
        oStatic && P.mix(fCons, oStatic);
        return fCons;
    };
    return P.Class = C;
})(pngx);

一个用这个类包装器创建类的例子:

(function (P, undefined) {
    ‘use strict‘;

    P.require(‘class‘);
    P.require(‘3d/vector3d‘);

    var M;
    M = P.Class(
        Array,
        function () {
            var i;
            this.length = 16;
            if (arguments.length === 0) {
                for (i = 16; i--;) {
                    this[i] = (i % 5 === 0) - 0;
                }
            } else {
                for (i = 16; i--;) {
                    this[i] = (arguments[i] - 0) || 0;
                }
            }
        },
        {
            clone: function () {
                var ret = new M;
                for (var i = 16; i--;) {
                    ret[i] = this[i];
                }
                return ret;
            },
            append: function (oM3D) {
                var ret = new M;
                for (var i = 16, x, y; i--;) {
                    x = (i / 4) | 0;
                    y = i % 4;
                    ret[i] = 0;
                    for (var j = 4; j--;) {
                        ret[i] += this[4 * x + j] * oM3D[4 * j + y];
                    }
                }
                return ret;
            },
            appendScale: function (nSx, nSy, nSz) {
                return new M(
                        this[0] * nSx, this[1] * nSx, this[2] * nSx, this[3] * nSx,
                        this[4] * nSy, this[5] * nSy, this[6] * nSy, this[7] * nSy,
                        this[8] * nSz, this[9] * nSz, this[10] * nSz, this[11] * nSz,
                    this[12], this[13], this[14], this[15]
                );
            },
            appendRotateX: function (nRad) {
                var s = Math.sin(nRad), c = Math.cos(nRad);
                return new M(
                    this[0], this[1], this[2], this[3],
                        this[4] * c - this[8] * s, this[5] * c - this[9] * s, this[6] * c - this[10] * s, this[7] * c - this[11] * s,
                        this[4] * s + this[8] * c, this[5] * s + this[9] * c, this[6] * s + this[10] * c, this[7] * s + this[11] * c,
                    this[12], this[13], this[14], this[15]
                );
            },
            appendRotateY: function (nRad) {
                var s = Math.sin(nRad), c = Math.cos(nRad);
                return new M(
                        this[0] * c + this[8] * s, this[1] * c + this[9] * s, this[2] * c + this[10] * s, this[3] * c + this[11] * s,
                    this[4], this[5], this[6], this[7],
                        this[8] * c - this[0] * s, this[9] * c - this[1] * s, this[10] * c - this[2] * s, this[11] * c - this[3] * s,
                    this[12], this[13], this[14], this[15]
                );
            },
            appendRotateZ: function (nRad) {
                var s = Math.sin(nRad), c = Math.cos(nRad);
                return new M(
                        this[0] * c - this[4] * s, this[1] * c - this[5] * s, this[2] * c - this[6] * s, this[3] * c - this[7] * s,
                        this[0] * s + this[4] * c, this[1] * s + this[5] * c, this[2] * s + this[6] * c, this[3] * s + this[7] * c,
                    this[8], this[9], this[10], this[11],
                    this[12], this[13], this[14], this[15]
                );
            },
            appendTranslate: function (nX, nY, nZ) {
                return new M(
                        this[0] + nX * this[12], this[1] + nX * this[13], this[2] + nX * this[14], this[3] + nX * this[15],
                        this[4] + nY * this[12], this[5] + nY * this[13], this[6] + nY * this[14], this[7] + nY * this[15],
                        this[8] + nZ * this[12], this[9] + nZ * this[13], this[10] + nZ * this[14], this[11] + nZ * this[15],
                    this[12], this[13], this[14], this[15]
                );
            },
            transformVector: function (oV3D) {
                return new P.Vector3D(
                        this[0] * oV3D.x + this[1] * oV3D.y + this[2] * oV3D.z + this[3],
                        this[4] * oV3D.x + this[5] * oV3D.y + this[6] * oV3D.z + this[7],
                        this[8] * oV3D.x + this[9] * oV3D.y + this[10] * oV3D.z + this[11]
                );
            },
            transformVectors: function (aV3D) {
                var ret = [];
                for (var i = aV3D.length; i--;) {
                    ret[i] = this.transformVector(aV3D[i]);
                }
                return ret;
            },
            det: function () {
                return this[0] * this[5] * this[10] * this[15]
                    - this[0] * this[5] * this[11] * this[14]
                    - this[0] * this[9] * this[6] * this[15]
                    + this[0] * this[9] * this[7] * this[14]
                    + this[0] * this[13] * this[6] * this[11]
                    - this[0] * this[13] * this[7] * this[10]
                    - this[4] * this[1] * this[10] * this[15]
                    + this[4] * this[1] * this[11] * this[14]
                    + this[4] * this[9] * this[2] * this[15]
                    - this[4] * this[9] * this[3] * this[14]
                    - this[4] * this[13] * this[2] * this[11]
                    + this[4] * this[13] * this[3] * this[10]
                    + this[8] * this[1] * this[6] * this[15]
                    - this[8] * this[1] * this[7] * this[14]
                    - this[8] * this[5] * this[2] * this[15]
                    + this[8] * this[5] * this[3] * this[14]
                    + this[8] * this[13] * this[2] * this[7]
                    - this[8] * this[13] * this[3] * this[6]
                    - this[12] * this[1] * this[6] * this[11]
                    + this[12] * this[1] * this[7] * this[10]
                    + this[12] * this[5] * this[2] * this[11]
                    - this[12] * this[5] * this[3] * this[10]
                    - this[12] * this[9] * this[2] * this[7]
                    + this[12] * this[9] * this[3] * this[6];
            },
            inverse: function () {
                var det = this.det();
                return new M(
                        (this[5] * this[10] * this[15] - this[5] * this[11] * this[14] - this[9] * this[6] * this[15] + this[9] * this[7] * this[14] + this[13] * this[6] * this[11] - this[13] * this[7] * this[10]) / det,
                        (-this[1] * this[10] * this[15] + this[1] * this[11] * this[14] + this[9] * this[2] * this[15] - this[9] * this[3] * this[14] - this[13] * this[2] * this[11] + this[13] * this[3] * this[10]) / det,
                        (this[1] * this[6] * this[15] - this[1] * this[7] * this[14] - this[5] * this[2] * this[15] + this[5] * this[3] * this[14] + this[13] * this[2] * this[7] - this[13] * this[3] * this[6]) / det,
                        (-this[1] * this[6] * this[11] + this[1] * this[7] * this[10] + this[5] * this[2] * this[11] - this[5] * this[3] * this[10] - this[9] * this[2] * this[7] + this[9] * this[3] * this[6]) / det,
                        (-this[4] * this[10] * this[15] + this[4] * this[11] * this[14] + this[8] * this[6] * this[15] - this[8] * this[7] * this[14] - this[12] * this[6] * this[11] + this[12] * this[7] * this[10]) / det,
                        (this[0] * this[10] * this[15] - this[0] * this[11] * this[14] - this[8] * this[2] * this[15] + this[8] * this[3] * this[14] + this[12] * this[2] * this[11] - this[12] * this[3] * this[10]) / det,
                        (-this[0] * this[6] * this[15] + this[0] * this[7] * this[14] + this[4] * this[2] * this[15] - this[4] * this[3] * this[14] - this[12] * this[2] * this[7] + this[12] * this[3] * this[6]) / det,
                        (this[0] * this[6] * this[11] - this[0] * this[7] * this[10] - this[4] * this[2] * this[11] + this[4] * this[3] * this[10] + this[8] * this[2] * this[7] - this[8] * this[3] * this[6]) / det,
                        (this[4] * this[9] * this[15] - this[4] * this[11] * this[13] - this[8] * this[5] * this[15] + this[8] * this[7] * this[13] + this[12] * this[5] * this[11] - this[12] * this[7] * this[9]) / det,
                        (-this[0] * this[9] * this[15] + this[0] * this[11] * this[13] + this[8] * this[1] * this[15] - this[8] * this[3] * this[13] - this[12] * this[1] * this[11] + this[12] * this[3] * this[9]) / det,
                        (this[0] * this[5] * this[15] - this[0] * this[7] * this[13] - this[4] * this[1] * this[15] + this[4] * this[3] * this[13] + this[12] * this[1] * this[7] - this[12] * this[3] * this[5]) / det,
                        (-this[0] * this[5] * this[11] + this[0] * this[7] * this[9] + this[4] * this[1] * this[11] - this[4] * this[3] * this[9] - this[8] * this[1] * this[7] + this[8] * this[3] * this[5]) / det,
                        (-this[4] * this[9] * this[14] + this[4] * this[10] * this[13] + this[8] * this[5] * this[14] - this[8] * this[6] * this[13] - this[12] * this[5] * this[10] + this[12] * this[6] * this[9]) / det,
                        (this[0] * this[9] * this[14] - this[0] * this[10] * this[13] - this[8] * this[1] * this[14] + this[8] * this[2] * this[13] + this[12] * this[1] * this[10] - this[12] * this[2] * this[9]) / det,
                        (-this[0] * this[5] * this[14] + this[0] * this[6] * this[13] + this[4] * this[1] * this[14] - this[4] * this[2] * this[13] - this[12] * this[1] * this[6] + this[12] * this[2] * this[5]) / det,
                        (this[0] * this[5] * this[10] - this[0] * this[6] * this[9] - this[4] * this[1] * this[10] + this[4] * this[2] * this[9] + this[8] * this[1] * this[6] - this[8] * this[2] * this[5]) / det
                );
            }
        },
        {
            createRotateTo: function (oVec0, oVec1) {
                var x, y, z, c, s;
                x = oVec0.y * oVec1.z - oVec0.z * oVec1.y;
                y = oVec0.z * oVec1.x - oVec0.x * oVec1.z;
                z = oVec0.x * oVec1.y - oVec0.y * oVec1.x;
                c = (oVec0.x * oVec1.x + oVec0.z * oVec1.z)
                    / Math.sqrt((oVec0.x * oVec0.x + oVec0.y * oVec0.y + oVec0.z * oVec0.z)
                        * (oVec1.x * oVec1.x + oVec1.y * oVec1.y + oVec1.z * oVec1.z));
                s = Math.sqrt(1 - c * c);
                return new M(
                        c + (1 - c) * x * x, (1 - c) * x * y - s * z, (1 - c) * x * z + s * y, 0,
                        (1 - c) * y * z + s * z, c + (1 - c) * y * y, (1 - c) * y * z - s * x, 0,
                        (1 - c) * x * z - s * y, (1 - c) * y * z + s * x, c + (1 - c) * z * z, 0,
                    0, 0, 0, 1
                );
            }
        }
    );
    return P.Matrix3D = M;
})(pngx);
时间: 2024-10-12 15:21:18

一个javascript类包装器的相关文章

类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器

 1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPushButton> #include <QLabel> template<class T> class run { public: T w; void show() { w.show(); } void settext() { w.setText("A"); }

从易到难,写一个JavaScript加载器之一

先上代码: 1 (function(global) { 2 var createScript, insertScript, makeLoadQueue; 3 createScript = function(src) { 4 var script; 5 script = document.createElement('SCRIPT'); 6 script.src = "" + src + ".js"; 7 return script; 8 }; 9 insertScr

你需要知道的 JavaScript 类(class)的这些知识

作者: Dmitri Pavlutin译者:前端小智来源:dmitripavlutin 点赞再看,养成习惯 本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料.欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西. JavaScript 使用原型继承:每个对象都从原型对象继承属性和方法. 在Java或Swift等语言中使用的传统类作为创建对象的蓝图,在 JavaScript 中不

自己实现的一款在线Javascript正则表达式测试器——JRE-Parser

本文最初发布于我的个人博客:http://jerryzou.com/posts/jreparser/ 昨天在看<正则表达式30分钟入门教程>的时候,看到博主自己实现了一个C#写的正则测试器,看上去挺方便的样子.但是我自己又不太喜欢乱装东西,所以寻思着能不能自己实现一个javascript正则表达式测试器.于是几十行代码实现了这样一个正则测试器. 先展示一下0.1版本的效果图吧~ 页面还比较简单,但是基本功能算是有了.可以正常使用~. 关于怎么从用户的输入中提取正则表达式的过程多亏@依云大神提点

第九章:Javascript类和模块

(过年了,祝大家新年好!) 第6章详细介绍了javascript对象,每个javascript对象都是一个属性集合,相互之间没有任何联系.在javascript中也可以定义对象的类,让每个对象都共享某些属性,这种“共享”的特性是非常有用的.类的成员或实例都包含一些属性,用以存放它们的状态,其中有些属性定义了它们的行为(通常称为方法).这些行为通常是由类定义的,而且为所有实例所共享.例如,假如有一个名为complex的类用来表示复数,同时还定义了一些复数运算.一个complex实例应当包含复数的实

java基础类型、包装器

char a = 'h';  //类包装器 Character aobj = a ;//自动装箱 byte b = 6; Byte bobj = b; short s = 234; Short sobj = s; boolean b = true; Boolean bobj = b; int i = 100; Integer iobj = i; long l = 567L; Long lobj = l; float f = 8.99F; Float fobj = f; double d = 4.

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

Canvas---Canvas图像加载、利用javascript回调机制实现一个图片加载器

canvas的drawImage方法有个缺点,就是当图片还未加载完成时调用它将无效. 当然,在高速运转的游戏主循环中,可以直接忽略这个问题,或者用 img.complete == true来做下判断. 在游戏循环之外的地方,可以用 img.onload = function (){};这样的回调解决. 但是,如果需要实现预先大量图片的加载,并且将加载进度告知用户,这时就需要一个图片加载器. 一.图片加载器原理 1.对于每张图片,开启对应的一个线程去负责加载,加载完成后修改一个变量的值-loade

java基本类型和包装器类

java是一种面向对象语言,java中的类把方法与数据连接在一起,并构成了自包含式的处理单元.但在java中不能定义基本类型(primitive type),为了能将基本类型视为对象来处理,并能连接相关的方法,java为每个基本类型都提供了包装类,这样,我们便可以把这些基本类型转化为对象来处理了.这些包装类有:Boolean,Byte,Short,Character,Integer,Long,Float,Double,Void共9个(注意:Date不是,无其基本类型). 一. 包装类(Wrapp