您的位置:首页 > Web前端 > JavaScript

《JS高级程序设计》第6章读书笔记:对象继承(一)原型链

2017-08-25 22:39 197 查看
《JS高级程序设计》第6章的读书笔记

创建对象(一)工场模式和构造函数模式

创建对象(二)原型模式和组合模式

创建对象(三)再探原型

对象继承(一)原型链

对象继承 (二)借用构造函数和组合继承

对象继承(三)原型式继承和寄生式继承

对象继承(四)寄生组合式继承

1 前言

我前后写了3篇博文阐述创建对象的4种方式。

更为可怕的是:《JS高级程序设计》阐述6种对象的方式,虽然其中只有一种方式是常用的。学习了这部分内容,我觉得,如此繁杂的继承方式,即使当初创造JS的作者也会觉得吃惊。

2 原型链(继承)

原型链自然是基于原型的。我在之前的博客:JS高级程序设计》第6章读书笔记:创建对象(二)原型模式和组合模式以及《JS高级程序设计》第6章读书笔记:创建对象(三)再探原型 两篇文章阐述了原型的概念和细节。

还是直接看实现原型链的代码吧

function SuperType() {
this.property = true;
}

SuperType.prototype.getSuperValue = function() {
return this.property;
}

function SubType() {
this.subproperty = false;
}

SubType.prototype = new SuperType(); // 这里是关键

SubType.prototype.getSubValue = function() {
return this.subproperty;
}

var instance = new SubType();
console.log(instance.getSuperValue()); // true


我们可以看到子类型的实例
instance
能够调用父类型的方法
getSuperValue
,所以我们可以说子类型继承了父类型。

继承后的结果如下图:



而实现继承的关键在于这行代码

SubType.prototype = new SuperType(); // 这里是关键


用自然语言表述的话:重写子类的原型对象为父类的实例对象。

注意一个异常:继承之后,instance.constructor现在指向SuperType,这是因为子类型原型被重写后,子类原型没有constructor这个属性了。

造成的结果:原型搜索结果被扩展,访问属性时,会先后搜索实例对象,子类原型对象,父类原型对象,Object的原型

确定原型和实例的关系

第一种方式:instanceof操作符

基于最上面的基础代码

console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
console.log(instance instanceof SubType); //true


第二种方式:isPropertyOf方法

基于最上面的基础代码

console.log(Object.prototype.isPrototypeOf(instance)); //true
console.log(SuperType.prototype.isPrototypeOf(instance)); //true
console.log(SubType.prototype.isPrototypeOf(instance)); //true


谨慎地定义方法

在需要覆盖或者添加超类型中不存在的某个方法时,一定要在替换原型的语句之后

SubType.prototype.getSubValue = function(){ //添加超类型之后不存在的某个方法
return this.subproperty;
}

SubType.prototype.getSuperValue = functipn(){ //覆盖超类型方法
return false;
}


注意:通过原型链实现继承时,不能使用对象字面量方法创建原型方法

function SuperType() {
this.property = true;
}

SuperType.prototype.getSuperValue = function() {
return this.property;
}

function SubType() {
this.subproperty = false;
}

SubType.prototype = new SuperType();

SubType.prototype = {  //
getSubValue: function() {
return this.subproperty;
},
someOtherMethod: function() {
return false;
}
}

SubType.prototype.getSubValue = function() {
return this.subproperty;
}

var instance = new SubType();
console.log(instance.getSuperValue()); // instance.getSuperValue is not a function


很简单:重写原型后,SubType.prototype就没有[[prototype]]属性指向父类型的原型对象

原型链的问题

第1个问题

原型链的问题和原型的问题紧密相关。我们知道,原型问题是包含引用类型值的原型属性会被所有实例共享。所以,我们要在构造函数中,而不是在原型对象中定义属性。因而,构造函数模式和原型模式相结合的组合模式解决了这个问题,成为最常用的创建对象的模式。

但是在用原型链实现集成继承时,原先的实例属性成了子类型的原型属性。(因为子类型的原型是父类型的实例。)

具体看下面这段代码:

function SuperType() {
this.colors = ['red', 'blue', 'green'];
}

function SubType() {}

SubType.prototype = new SuperType();

let instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); //​​​​​[ 'red', 'blue', 'green', 'black' ]​​​​​

let instance2 = new SubType();
console.log(instance2.colors); //​​​​​[ 'red', 'blue', 'green', 'black' ]


第2个问题

无法再不影响所有对象实例的情况下给超类型传递参数。因为子类型实例共享了子类型原型的属性。

具体看代码:

function SuperType(name) {
this.name = name;
}

function SubType() {}

SubType.prototype = new SuperType('achao');

let instance1 = new SubType();

console.log(instance1.name); //​​​​​achao​​​​​

let instance2 = new SubType();

console.log(instance2.name); //​​​​​achao​​​​​


上述代码没有彻底实现自定义子类型的意愿。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐