在阅读精通JavaScript(图灵计算机科学丛书)里面有讲解javascript继承的一些东东。
其一是讲解DouglasCrockford的js
代码如下:
//简单的辅助函数,让你可以将新函数绑定到对象prototype上 Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; } //一个相当复杂的函数,允许你方便地从其他对象继承函数, //同时仍然可以调用属于父对象的那些方法 Function.method('inherits', function (parent) { var d = {}; //记录我们目前所在父层次的级数 var p = (this.prototype = new parent()); //继承父对象的方法 //创建一个新的名位uber的特权函数 //调用它时会执行所有在继承时被重写的函数 this.method("uber", function uber(name) { if (!(name in d)) { d[name] = 0; //继承级数默认为0 } var f, /*要执行的函数*/r, /*函数返回值*/t = d[name], v = parent.prototype; /*父对象的prototype*/ if (t) { //如果我们已经在某个uber函数内 上溯到必要的级数已找到原始的prototype while (t) { v = v.constructor.prototype; t -= 1; } f = v[name]; //从prototype中获得函数 } else { //uber第一次调用 从prototype获得要执行的函数 f = p[name]; if (f == this[name]) { //如果函数属于当前prototype 则改为调用父对象的prototype f = v[name]; } } d[name] += 1; //记录我们在继承堆栈中所在位置 //使用除第一个以外所有的arguments 调用函数 第一个参数是执行的匿名函数名 r = f.apply(this, Array.prototype.slice.apply(arguments, [1])); d[name] -= 1; //恢复继承堆栈 return r; }); return this; }); //只继承父对象特定的函数。而非使用new parent()的继承的所有函数 Function.method("swiss", function (parent) { for (var i = 1; i < arguments.length; i++) { var name = arguments[i]; this.prototype[name] = parent[name]; } return this; }); /* Function.prototype.method 它提供了一个简单的方法,把函数于构造函数原型关联起来。 之所以有效,是因为所有的构造函数本身都是函数,所以能获得method这个新方法 Function.prototype.inherits这一函数可以用于提供简单的对象继承,它的代码主要围绕任意对象方法中调用 this.uber(methodname)为中心,并在让这个uber方法执行它要覆盖的父对象的方法。 Function.prototype.swiss这是.method函数的增强版,可以用于单一父对象获取多个函数。如果有多个父对象上 就能获得可用的多对象继承 */
调用代码:
function Person(name) { this.name = name; } Person.method("getName", function () { return this.name; }); function User(name, password) { this.name = name; this.password = password; } User.inherits(Person); User.method("getPassword", function () { return this.password; }); User.method("getName", function () { return "My name is :" + this.uber("getName"); }); var p = new Person("123"); alert(p.getName()); var u = new User("abc", "456"); alert(u.getPassword()); alert(u.getName());
第二个工具函数是base库
/* Base.js, version 1.1a Copyright 2006-2010, Dean Edwards License: http://www.opensource.org/licenses/mit-license.php */ var Base = function() { // dummy }; Base.extend = function(_instance, _static) { // subclass var extend = Base.prototype.extend; // build the prototype Base._prototyping = true; var proto = new this; extend.call(proto, _instance); proto.base = function() { // call this method from any other method to invoke that method's ancestor }; delete Base._prototyping; // create the wrapper for the constructor function //var constructor = proto.constructor.valueOf(); //-dean var constructor = proto.constructor; var klass = proto.constructor = function() { if (!Base._prototyping) { if (this._constructing || this.constructor == klass) { // instantiation this._constructing = true; constructor.apply(this, arguments); delete this._constructing; } else if (arguments[0] != null) { // casting return (arguments[0].extend || extend).call(arguments[0], proto); } } }; // build the class interface klass.ancestor = this; klass.extend = this.extend; klass.forEach = this.forEach; klass.implement = this.implement; klass.prototype = proto; klass.toString = this.toString; klass.valueOf = function(type) { //return (type == "object") ? klass : constructor; //-dean return (type == "object") ? klass : constructor.valueOf(); }; extend.call(klass, _static); // class initialisation if (typeof klass.init == "function") klass.init(); return klass; }; Base.prototype = { extend: function(source, value) { if (arguments.length > 1) { // extending with a name/value pair var ancestor = this[source]; if (ancestor && (typeof value == "function") && // overriding a method? // the valueOf() comparison is to avoid circular references (!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) && /\bbase\b/.test(value)) { // get the underlying method var method = value.valueOf(); // override value = function() { var previous = this.base || Base.prototype.base; this.base = ancestor; var returnValue = method.apply(this, arguments); this.base = previous; return returnValue; }; // point to the underlying method value.valueOf = function(type) { return (type == "object") ? value : method; }; value.toString = Base.toString; } this[source] = value; } else if (source) { // extending with an object literal var extend = Base.prototype.extend; // if this object has a customised extend method then use it if (!Base._prototyping && typeof this != "function") { extend = this.extend || extend; } var proto = {toSource: null}; // do the "toString" and other methods manually var hidden = ["constructor", "toString", "valueOf"]; // if we are prototyping then include the constructor var i = Base._prototyping ? 0 : 1; while (key = hidden[i++]) { if (source[key] != proto[key]) { extend.call(this, key, source[key]); } } // copy each of the source object's properties to this object for (var key in source) { if (!proto[key]) extend.call(this, key, source[key]); } } return this; } }; // initialise Base = Base.extend({ constructor: function() { this.extend(arguments[0]); } }, { ancestor: Object, version: "1.1", forEach: function(object, block, context) { for (var key in object) { if (this.prototype[key] === undefined) { block.call(context, object[key], key, object); } } }, implement: function() { for (var i = 0; i < arguments.length; i++) { if (typeof arguments[i] == "function") { // if it's a function, call it arguments[i](this.prototype); } else { // add the interface using the extend method this.prototype.extend(arguments[i]); } } return this; }, toString: function() { return String(this.valueOf()); } });
调用代码:
var Person = Base.extend({ constructor: function (name) { this.name = name; }, getName: function () { return this.name; } }); var User = Person.extend({ constructor: function (name, password) { this.base(name); this.password = password; }, getPassWord: function () { return this.password; } }); var p = new Person("123"); alert(p.getName()); var u = new User("456", "abc"); alert(u.getName()); alert(u.getPassWord());
有关base的详细介绍:http://dean.edwards.name/weblog/2006/03/base/