浅谈javascript的原型继承

javascript的继承在很多框架中都有运用,尤其是原型式继承。首先要理解一个概念,什么是原型式继承?所谓的原型式继承,就是在函数内部先创建一个临时性的构造函数,然后将传入的对象做这个构造函数的原型,最后返回这个临时类型的新实例。

请看源码:

function clone(o) {

    var F = function(){};

    F.prototype = o;

    return new F();

}

 

首先看ext(4.1的1896行开始)的原型式继承。

var TemplateClass = function(){};

var ExtObject = Ext.Object = {

    chain: function (object) {

        TemplateClass.prototype = object;

        var result = new TemplateClass();

        TemplateClass.prototype = null;

        return result;

    }



}

这里清除了object的prototype。

再看一下jquery是怎么玩的继承。

var jQuery = function( selector, context ) {

        return new jQuery.fn.init( selector, context, rootjQuery );

    };





-----------------------



jQuery.fn = jQuery.prototype = {

    constructor: jQuery,

    init: function( selector, context, rootjQuery ) {

        -----------------------

        }



}



-------------------

jQuery.fn.init.prototype = jQuery.fn;

jquery玩的就比较高,借助jQuery.fn.init来完成,但是思路一样。

 

司徒正美的mass里也有类似的继承,在lang_fix.js里面第17行:

create: function(o){

            if (arguments.length > 1) {

                $.log(" Object.create implementation only accepts the first parameter.")

            }

            function F() {}

            F.prototype = o;

            return new F();

        }

 

查看了一下es5的官方,找到了他的兼容补丁:

 

// ES5 15.2.3.5

// http://es5.github.com/#x15.2.3.5

if (!Object.create) {

    Object.create = function create(prototype, properties) {

        var object;

        if (prototype === null) {

            object = { "__proto__": null };

        } else {

            if (typeof prototype != "object") {

                throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");

            }

            var Type = function () {};

            Type.prototype = prototype;

            object = new Type();

            // IE has no built-in implementation of `Object.getPrototypeOf`

            // neither `__proto__`, but this manually setting `__proto__` will

            // guarantee that `Object.getPrototypeOf` will work as expected with

            // objects created using `Object.create`

            object.__proto__ = prototype;

        }

        if (properties !== void 0) {

            Object.defineProperties(object, properties);

        }

        return object;

    };

}

 

上面的代码考虑的就比较全面,但是需要另外引入Object.defineProperties的补丁才行,源码相对就比较多了。

 

View Code
// ES5 15.2.3.6

// http://es5.github.com/#x15.2.3.6



// Patch for WebKit and IE8 standard mode

// Designed by hax <hax.github.com>

// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5

// IE8 Reference:

//     http://msdn.microsoft.com/en-us/library/dd282900.aspx

//     http://msdn.microsoft.com/en-us/library/dd229916.aspx

// WebKit Bugs:

//     https://bugs.webkit.org/show_bug.cgi?id=36423



function doesDefinePropertyWork(object) {

    try {

        Object.defineProperty(object, "sentinel", {});

        return "sentinel" in object;

    } catch (exception) {

        // returns falsy

    }

}



// check whether defineProperty works if it's given. Otherwise,

// shim partially.

if (Object.defineProperty) {

    var definePropertyWorksOnObject = doesDefinePropertyWork({});

    var definePropertyWorksOnDom = typeof document == "undefined" ||

        doesDefinePropertyWork(document.createElement("div"));

    if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {

        var definePropertyFallback = Object.defineProperty;

    }

}



if (!Object.defineProperty || definePropertyFallback) {

    var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";

    var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "

    var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +

                                      "on this javascript engine";



    Object.defineProperty = function defineProperty(object, property, descriptor) {

        if ((typeof object != "object" && typeof object != "function") || object === null) {

            throw new TypeError(ERR_NON_OBJECT_TARGET + object);

        }

        if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) {

            throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);

        }

        // make a valiant attempt to use the real defineProperty

        // for I8's DOM elements.

        if (definePropertyFallback) {

            try {

                return definePropertyFallback.call(Object, object, property, descriptor);

            } catch (exception) {

                // try the shim if the real one doesn't work

            }

        }



        // If it's a data property.

        if (owns(descriptor, "value")) {

            // fail silently if "writable", "enumerable", or "configurable"

            // are requested but not supported

            /*

            // alternate approach:

            if ( // can't implement these features; allow false but not true

                !(owns(descriptor, "writable") ? descriptor.writable : true) ||

                !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||

                !(owns(descriptor, "configurable") ? descriptor.configurable : true)

            )

                throw new RangeError(

                    "This implementation of Object.defineProperty does not " +

                    "support configurable, enumerable, or writable."

                );

            */



            if (supportsAccessors && (lookupGetter(object, property) ||

                                      lookupSetter(object, property)))

            {

                // As accessors are supported only on engines implementing

                // `__proto__` we can safely override `__proto__` while defining

                // a property to make sure that we don't hit an inherited

                // accessor.

                var prototype = object.__proto__;

                object.__proto__ = prototypeOfObject;

                // Deleting a property anyway since getter / setter may be

                // defined on object itself.

                delete object[property];

                object[property] = descriptor.value;

                // Setting original `__proto__` back now.

                object.__proto__ = prototype;

            } else {

                object[property] = descriptor.value;

            }

        } else {

            if (!supportsAccessors) {

                throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);

            }

            // If we got that far then getters and setters can be defined !!

            if (owns(descriptor, "get")) {

                defineGetter(object, property, descriptor.get);

            }

            if (owns(descriptor, "set")) {

                defineSetter(object, property, descriptor.set);

            }

        }

        return object;

    };

}



// ES5 15.2.3.7

// http://es5.github.com/#x15.2.3.7

if (!Object.defineProperties) {

    Object.defineProperties = function defineProperties(object, properties) {

        for (var property in properties) {

            if (owns(properties, property) && property != "__proto__") {

                Object.defineProperty(object, property, properties[property]);

            }

        }

        return object;

    };

}

 

EcmaScript6的类继承。

class module extends Base {

    constructor() {

    }

}

越玩越像java了,不过es6很多浏览器还不支持。

 

最后推荐的写法:

if (!Object.create) {

    Object.create = function create(o) {

        var F = function(){};

        F.prototype = o;

        var result = new F();

        F.prototype = null;

        return result;

    }

}

 

 

 

 

 

 

 

你可能感兴趣的:(JavaScript)