当面试官:说说对原型链的理解时,他希望听到什么

吐槽君 分类:javascript

原型链是实现继承的一种方式,扩展了原型搜索机制,使搜索可以继承向上,搜索原型的原型。

原型搜索机制

在原型搜索机制中,构造函数,实例,和原型对象的关系为,原型对象是构造函数的一个属性prototype,原型对象中有一个属性constructor指回构造函数,构造函数生成的实例中具有指针指向构造函数上的原型对象。

代码实现

// 构造函数
function person(name, color){
    this.name = name;
    this.color = color;
}
// 向默认的原型对象中添加值
person.prototype.getColor = function(){
    return this.color;
}
// 通过构造函数构建实例 实例中含有指向原型对象的指针
var personOne = new person("tom", "red");

console.log("来自构造函数中的属性", personOne.name) // "tom"
console.log("来自原型对象中的属性", personOne.getColor()) // "red"
 

结构图解

构造函数,原型对象,实例的关系如下。

图1.PNG

搜索机制

当搜索一个属性/方法时,先搜索实例本身,如果实例本身没有找到,再从指针找到其指向的原型对象,向上查找的特性与作用域链相似。

也就是说,如果在实例中设置了要查找的属性名,就不会再向上查找。

... ...
personOne.getColor = function(){
	return "实例中的属性";
}
console.log(personOne.getColor()); // "实例中的属性"
... ...
 

这时候如果没找到,并且该原型对象中也有一个指向另一个原型对象的指针,就从指针向上搜索原型的原型,直到原型链的末端,也就是原型不再包含指向另一个原型的指针为止。

原型链代码实现

从这里看出,原型链是由指向原型对象的指针将多个原型对象连接起来,上面指出,当我们new一个A实例,实例中就包含一个指向原型对象的指针。

如果我们将该实例赋值为另外一个对象实例B的原型对象,原型链就构成了,查找顺序为。

B实例−>B原型(A实例)−>A原型B实例->B原型(A实例)->A原型

代码实现

在下面的代码中,访问objB的实例对象obj时,通过原型链,最终输出了objA的原型对象中的值。

function objA(){
    this.title = 'A';
}

objA.prototype.name = "objA-prototype";

function objB(){
    this.title = 'B';
}

objB.prototype = new objA();

var obj = new objB;
console.log(obj.name); // objA-prototype
 

结构图解

图2.PNG

链条拓展

我们可以通过将B实例替换C对象实例的原型对象的方式来拓展该原型链。拓展后查找顺序为。

C实例−>C原型(B实例)−>B原型(A实例)−>A原型C实例->C原型(B实例)->B原型(A实例)->A原型

原型链就是这样实现继承的。

在上面公式中,在C实例向A原型搜索的过程中,只要在某一个地方获得了一个同名属性,就会取该属性,而不再向上搜索,也就是说,在下层原型中添加上层原型链已有的方法会覆盖方法。

原型链的缺点

原型链也有一些缺点,如原型链中的属性是共享的,当修改某一个原型对象中的值时,下层所以实例在获取该值时都会变化,因为大家都是通过指针读取原型对象中的值。

由于这种缺陷,一般不单独使用原型链继承。

回复

我来回复
  • 暂无回复内容