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

来源:互联网 发布:剑三丐姐官方捏脸数据 编辑:程序博客网 时间:2024/06/06 03:02

《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); //trueconsole.log(instance instanceof SuperType); //trueconsole.log(instance instanceof SubType); //true

第二种方式:isPropertyOf方法

基于最上面的基础代码

console.log(Object.prototype.isPrototypeOf(instance)); //true console.log(SuperType.prototype.isPrototypeOf(instance)); //trueconsole.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 0
原创粉丝点击