zoukankan      html  css  js  c++  java
  • 浅谈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;
        }
    }

     

  • 相关阅读:
    GIT 相关
    createFile
    值传递、指针传递、引用传递
    Sightseeing trip
    find the longest of the shortest
    Laurenty and Shop
    Dima and Lisa
    Marina and Vasya
    Kolya and Tanya
    Two Substrings
  • 原文地址:https://www.cnblogs.com/xpbb/p/2607827.html
Copyright © 2011-2022 走看看