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; } }