浅谈javascript的原型继承

 更新时间:2012年07月25日 22:47:36   作者:  
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的补丁才行,源码相对就比较多了。
复制代码 代码如下:

// 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 网页跳转的方法

    javascript 网页跳转的方法

    昨天练习的时候正好要用到跳转代码,在网上找了一下,觉得下面几个不错...整理了一下发上来...
    2008-12-12
  • bootstrap使用validate实现简单校验功能

    bootstrap使用validate实现简单校验功能

    这篇文章主要为大家详细介绍了bootstrap使用validate实现简单校验功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • JavaScript必知必会(三) String .的方法来自何方

    JavaScript必知必会(三) String .的方法来自何方

    这篇文章主要介绍了JavaScript必知必会(三) String .的方法来自何方的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • 基于Flowplayer打造一款免费的WEB视频播放器附源码

    基于Flowplayer打造一款免费的WEB视频播放器附源码

    Flowplayer是一款免费的WEB视频播放器。它支持播放flv、swf等流媒体和图片文件,能够非常流畅的播放视频文件,支持自定义配置和扩展。下面本篇文章给大家介绍基于Flowplayer打造一款免费的WEB视频播放器,需要的朋友可以参考下
    2015-09-09
  • JS常用表单验证方法总结

    JS常用表单验证方法总结

    这篇文章主要介绍了JS常用表单验证方法,需要的朋友可以参考下
    2014-05-05
  • js+css实现红包雨效果

    js+css实现红包雨效果

    这篇文章主要为大家详细介绍了js+css实现红包雨效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • FF下zoom的替代方案 单位em

    FF下zoom的替代方案 单位em

    css 属性zoom是ie私有属性 在FF中(或者说仅实现CSS标准的其他浏览器中)无法使用,一直在网上搜索它的替代方案,但没有收获,后来听群里有朋友说em或可解决此问题,经过研究和测试,发现果然可以解决。
    2008-08-08
  • 小程序实现上下切换位置

    小程序实现上下切换位置

    这篇文章主要为大家详细介绍了小程序实现上下切换位置,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • JavaScript实现tab栏切换的几种常用方法

    JavaScript实现tab栏切换的几种常用方法

    这篇文章主要给大家介绍了关于JavaScript实现tab栏切换的几种常用方法,在Web开发中Tab切换是一个常见的功能,它允许用户在不同的页面部分之间进行切换,需要的朋友可以参考下
    2023-12-12
  • javascript计算用户打开网页的停留时间

    javascript计算用户打开网页的停留时间

    本文介绍了javascript计算用户打开网页的停留时间,大家参考使用吧
    2014-01-01

最新评论