码迷,mamicode.com
首页 > 编程语言 > 详细

一个javascript类包装器

时间:2015-01-29 21:07:33      阅读:353      评论:0      收藏:0      [点我收藏+]

标签:

首先在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);

 

一个javascript类包装器

标签:

原文地址:http://www.cnblogs.com/pngx/p/4260790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!