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

《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​​​​​

上述代码没有彻底实现自定义子类型的意愿。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值