现在的位置: 首页 > Frameworks > Backbone > 正文
Backbone之extend函数解析
2017年06月22日 Backbone ⁄ 共 3791字 评论数 1 ⁄ 被围观 229 views+

本篇博文要说的extend函数,不是jQuery或者underscore实现的用于对象之间属性拷贝的extend函数。Backbone内部实现的extend函数,作用就是提供一个简单的构造函数之间的继承方法,也就是类(构造函数)之间的继承。直接来分析源码了:

  1. /**
  2.  * 类的派生工具,用于实现类的继承
  3.  *
  4.  * 用法:
  5.  * Child = Parent.extend(protoProps, staticProps);
  6.  *
  7.  * 执行效果:
  8.  * 1、Child的静态属性 = Parent的静态属性 + staticProps;
  9.  * 2、Child.prototype = protoProps;
  10.  * 3、Child.prototype.__prop__ = Parent.prototype; 即Child原型的原型链指向Parent原型,以此达到共享Parent原型的目的(继承)
  11.  *
  12.  * 注意点:
  13.  * Parent的实例属性,Child并没有继承,如果要继承,要在Child的构造函数中借用(call,apply)父类构造函数
  14.  *
  15.  * @param protoProps 原型属性,最终都会合并到Child.prototype上,作为Child类的原型属性
  16.  * @param staticProps 静态属性,最终直接合并到Child上,作为Child类的静态方法
  17.  * @returns {派生类(子类)}
  18.  */
  19. var extend = function(protoProps, staticProps) {
  20.     var parent = this;
  21.     var child;
  22.     // protoProps.constructor用于定义Child构造函数
  23.     // 如果设置了protoProps.constructor,则protoProps.constructor === Child
  24.     // 如果不设置protoProps.constructor,则提供一个默认的Child构造函数,该默认构造函数内部调用父类构造函数
  25.     if (protoProps && _.has(protoProps, 'constructor')) {
  26.         child = protoProps.constructor;
  27.     } else {
  28.         child = function() {
  29.             return parent.apply(this, arguments);
  30.         };
  31.     }
  32.     // 把Parent类的静态属性以及staticProps的属性拷贝到Child的静态属性上
  33.     _.extend(child, parent, staticProps);
  34.     // 设置原型链,此处用了underscore的create方法,该方法是专门用于创建原型对象的
  35.     // 该方法执行后 child.prototype的原型链指向parent.prototype,即 child.prototype.__prop__ === parent.prototype
  36.     // 同时将protoProps的属性复制到child.prototype
  37.     // 这时候child.prototype.constructor === parent,这是不合理的,因为child的构造函数我们当然认为是child自身比较合理
  38.     child.prototype = _.create(parent.prototype, protoProps);
  39.     // 重置child.prototype.constructor为child
  40.     child.prototype.constructor = child;
  41.     // 不用underscore的create函数的话,以下这段代码是传统方式的经典实现
  42.     // var Surrogate = function(){ this.constructor = child; };
  43.     // Surrogate.prototype = parent.prototype;
  44.     // child.prototype = new Surrogate;
  45.     // if (protoProps) _.extend(child.prototype, protoProps);
  46.     // 记录一下parent.prototype的引用,方便需要的时候使用(__prop__属性并不是标准的API),
  47.     child.__super__ = parent.prototype;
  48.     return child;
  49. };
  50. // 父类
  51. function Animal(cls) {
  52.     this.clsName = cls || 'animal';
  53. };
  54. // 原型属性
  55. Animal.prototype.printClass = function (cls) {
  56.     console.log(this.clsName);
  57. };
  58. // 子类
  59. Animal.extend = extend;
  60. var Human = Animal.extend(
  61.     {
  62.         constructor: function (name, sex, age) {
  63.             // 借用父类构造函数,继承父类的实例属性 clsName
  64.             // 同时初始化类别为 human
  65.             Animal.call(this, 'human');
  66.             this.name = name;
  67.             this.sex = sex;
  68.             this.age = age;
  69.             this.introduce = function () {
  70.                 console.log('I am a '
  71.                 + this.sex + ', my name is '
  72.                 + this.name + ', and '
  73.                 + this.age + ' years old?');
  74.             }
  75.         },
  76.         sayHello: function() {
  77.             console.log('Hello, i am ' + this.name + ', what is your name?');
  78.         }
  79.     },
  80.     {
  81.         staticMethod: function () {
  82.             // 静态方法是无法通过this访问到实例属性name的
  83.             // 所以调用该方法的话,此处打印出 undefined
  84.             console.log(this.name);
  85.         }
  86.     }
  87. );
  88. var laoZhang = new Human('张三','man', 34);

下面来做一些测试:

  1. // 实例方法是laoZhang对象本身就持有的
  2. // 输出:true
  3. console.log(laoZhang.hasOwnProperty('introduce'));
  4. // 调用实例方法
  5. // 输出:I am a man, my name is 张三, and 34 years old?
  6. laoZhang.introduce();
  7. // sayHello方法是从Hunman.prototype继承来的,并不是自己的方法。
  8. // 但是JavaScript读对象属性的规则是沿着原型链往上查询,所以laoZhang.sayHello()可以执行
  9. // 输出:false
  10. console.log(laoZhang.hasOwnProperty('sayHello'));
  11. // 调用原型链(Human.prototype)上的方法
  12. // 输出:Hello, i am 张三, what is your name?
  13. laoZhang.sayHello();
  14. // 调用父类原型方法,即原型链的原型链 laoZhang.__proto__.__proto__.printClass
  15. // 输出:human
  16. laoZhang.printClass();
  17. // 对象实例的原型链指向类的原型
  18. // 输出:true
  19. console.log(laoZhang.__proto__ === Human.prototype);
  20. // 子类原型的原型链指向父亲的原型
  21. // 输出:true
  22. console.log(Human.prototype.__proto__ === Animal.prototype);
  23. // 对象实例访问不了类的静态方法
  24. // 输出:undefined
  25. console.log(laoZhang.staticMethod);
  26. // 类的静态方法无法访问对象实例的属性
  27. // 输出:undefined
  28. console.log(Human.staticMethod());

目前有 1 条留言 其中:访客:0 条, 博主:0 条 引用: 1

    给我留言

    留言无头像?


    ×