首页 > 语言 > JavaScript > 正文

JavaScript 继承详解(六)

2024-05-06 15:08:33
字体:
来源:转载
供稿:网友

在本章中,我们将分析Prototypejs中关于JavaScript继承的实现。
Prototypejs是最早的JavaScript类库,可以说是JavaScript类库的鼻祖。 我在几年前接触的第一个JavaScript类库就是这位,因此Prototypejs有着广泛的群众基础。

不过当年Prototypejs中的关于继承的实现相当的简单,源代码就寥寥几行,我们来看下。

早期Prototypejs中继承的实现
源码:

var Class = {      // Class.create仅仅返回另外一个函数,此函数执行时将调用原型方法initialize      create: function() {        return function() {          this.initialize.apply(this, arguments);        }      }    };        // 对象的扩展    Object.extend = function(destination, source) {      for (var property in source) {        destination[property] = source[property];      }      return destination;    };

调用方式:

var Person = Class.create();    Person.prototype = {      initialize: function(name) {        this.name = name;      },      getName: function(prefix) {        return prefix + this.name;      }    };    var Employee = Class.create();    Employee.prototype = Object.extend(new Person(), {      initialize: function(name, employeeID) {        this.name = name;        this.employeeID = employeeID;      },      getName: function() {        return "Employee name: " + this.name;      }    });    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"

很原始的感觉对吧,在子类函数中没有提供调用父类函数的途径。

Prototypejs 1.6以后的继承实现
首先来看下调用方式:

// 通过Class.create创建一个新类    var Person = Class.create({      // initialize是构造函数      initialize: function(name) {        this.name = name;      },      getName: function(prefix) {        return prefix + this.name;      }    });        // Class.create的第一个参数是要继承的父类    var Employee = Class.create(Person, {      // 通过将子类函数的第一个参数设为$super来引用父类的同名函数      // 比较有创意,不过内部实现应该比较复杂,至少要用一个闭包来设置$super的上下文this指向当前对象      initialize: function($super, name, employeeID) {        $super(name);        this.employeeID = employeeID;      },      getName: function($super) {        return $super("Employee name: ");      }    });    var zhang = new Employee("ZhangSan", "1234");    console.log(zhang.getName());  // "Employee name: ZhangSan"

这里我们将Prototypejs 1.6.0.3中继承实现单独取出来, 那些不想引用整个prototype库而只想使用prototype式继承的朋友, 可以直接把下面代码拷贝出来保存为JS文件就行了。

var Prototype = {      emptyFunction: function() { }    };    var Class = {      create: function() {        var parent = null, properties = $A(arguments);        if (Object.isFunction(properties[0]))          parent = properties.shift();        function klass() {          this.initialize.apply(this, arguments);        }        Object.extend(klass, Class.Methods);        klass.superclass = parent;        klass.subclasses = [];        if (parent) {          var subclass = function() { };          subclass.prototype = parent.prototype;          klass.prototype = new subclass;          parent.subclasses.push(klass);        }        for (var i = 0; i < properties.length; i++)          klass.addMethods(properties[i]);        if (!klass.prototype.initialize)          klass.prototype.initialize = Prototype.emptyFunction;        klass.prototype.constructor = klass;        return klass;      }    };    Class.Methods = {      addMethods: function(source) {        var ancestor = this.superclass && this.superclass.prototype;        var properties = Object.keys(source);        if (!Object.keys({ toString: true }).length)          properties.push("toString", "valueOf");        for (var i = 0, length = properties.length; i < length; i++) {          var property = properties[i], value = source[property];          if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "$super") {            var method = value;            value = (function(m) {              return function() { return ancestor[m].apply(this, arguments) };            })(property).wrap(method);            value.valueOf = method.valueOf.bind(method);            value.toString = method.toString.bind(method);          }          this.prototype[property] = value;        }        return this;      }    };    Object.extend = function(destination, source) {      for (var property in source)        destination[property] = source[property];      return destination;    };    function $A(iterable) {      if (!iterable) return [];      if (iterable.toArray) return iterable.toArray();      var length = iterable.length || 0, results = new Array(length);      while (length--) results[length] = iterable[length];      return results;    }    Object.extend(Object, {      keys: function(object) {        var keys = [];        for (var property in object)          keys.push(property);        return keys;      },      isFunction: function(object) {        return typeof object == "function";      },      isUndefined: function(object) {        return typeof object == "undefined";      }    });    Object.extend(Function.prototype, {      argumentNames: function() {        var names = this.toString().match(/^[/s/(]*function[^(]*/(([^/)]*)/)/)[1].replace(//s+/g, '').split(',');        return names.length == 1 && !names[0] ? [] : names;      },      bind: function() {        if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;        var __method = this, args = $A(arguments), object = args.shift();        return function() {          return __method.apply(object, args.concat($A(arguments)));        }      },      wrap: function(wrapper) {        var __method = this;        return function() {          return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));        }      }    });    Object.extend(Array.prototype, {      first: function() {        return this[0];      }    });            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选