JavaScript系列--浅析原型链与继承 (3)

寄生式继承的思路与(寄生)构造函数和工厂模式类似, 即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象. 如下.

function createAnother(original){ var clone = object(original);//通过调用object函数创建一个新对象 clone.sayHi = function(){//以某种方式来增强这个对象 alert("hi"); }; return clone;//返回这个对象 }

这个例子中的代码基于person返回了一个新对象–anotherPerson. 新对象不仅具有 person 的所有属性和方法, 而且还被增强了, 拥有了sayH()方法.

注意: 使用寄生式继承来为对象添加函数, 会由于不能做到函数复用而降低效率;这一点与构造函数模式类似.

 

七、寄生组合式继承

前面讲过,组合继承是 JavaScript 最常用的继承模式; 不过, 它也有自己的不足. 组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数: 一次是在创建子类型原型的时候, 另一次是在子类型构造函数内部.

寄生组合式继承就是为了降低调用父类构造函数的开销而出现的

其背后的基本思路是: 不必为了指定子类型的原型而调用超类型的构造函数

function extend(subClass,superClass){ var prototype = object(superClass.prototype);//创建对象 prototype.constructor = subClass;//增强对象 subClass.prototype = prototype;//指定对象 }

extend的高效率体现在它没有调用superClass构造函数,因此避免了在subClass.prototype上面创建不必要,多余的属性. 于此同时,原型链还能保持不变; 因此还能正常使用 instanceof 和 isPrototypeOf() 方法。

 

综上所述有:原型链继承,构造函数继承(经典继承),组合继承,寄生继承,寄生组合继承五种方法,寄生组合式继承,集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方法。

 

下面我们来看下extend的另一种更为有效的扩展.

function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; subClass.superclass = superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } }

我一直不太明白的是为什么要 "new F()", 既然extend的目的是将子类型的 prototype 指向超类型的 prototype,为什么不直接做如下操作呢?

subClass.prototype = superClass.prototype;//直接指向超类型prototype

显然, 基于如上操作, 子类型原型将与超类型原型共用, 根本就没有继承关系.

 

八、new操作符

为了追本溯源, 我顺便研究了new运算符具体干了什么?发现其实很简单,就干了三件事情.

var obj = {}; obj.__proto__ = F.prototype; F.call(obj);

第一行,我们创建了一个空对象obj;

第二行,我们将这个空对象的__proto__成员指向了F构造函数的prototype对象;

第三行,我们将F函数对象的this指针替换成obj,然后再调用F函数.

 

 new 操作符调用构造函数的时候,函数内部实际上发生以下变化:

1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

2、属性和方法被加入到 this 引用的对象中。

3、新创建的对象由 this 所引用,并且最后隐式的返回 this.

 

九、属性查找

 使用了原型链后, 当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部 - 也就是 Object.prototype - 但是仍然没有找到指定的属性,就会返回 undefined。

此时若想避免原型链查找, 建议使用hasOwnProperty方法. 因为hasOwnProperty是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

console.log(instance1.hasOwnProperty('age'));//true

对比: isPrototypeOf 则是用来判断该方法实例对象是不是参数的原型对象,是则返回true,否则返回false。如

console.log(Father.prototype.isPrototypeOf(instance1));//true

 

十、instanceof && typeof

instanceof 运算符是用来在运行时指出对象是否是构造器的一个实例。

instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxyzj.html