JS面向对象的程序设计之继承的实现 - 原型链

回滚侠
• 阅读 1227

JS面向对象的程序设计之继承的实现 - 原型链


前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下。如有纰漏或错误,会非常感谢您的指出。文中绝大部分内容引用自《JavaScript高级程序设计第三版》。


继承是OO(Object Oriented, 面向对象)语言中的一个最为人津津乐道的概念。

许多OO语言都支持两种继承方式:接口继承和实现继承。

接口继承只继承签名,而实现继承则继承实际的方法。

如前所述, 由于函数没有签名,在ECMAScript中无法实现接口继承。

前面暂时看不懂没关系,可以学学一些Java基础知识,这样回过来看,就明白说啥了!!

记住这句就行,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。

原型链

ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。

其基本思想是利用原型,让一个引用类型继承另一个引用类型的属性和方法。

简单回顾一下构造函数、原型和实例对象之间的关系:

  • 每个构造函数都有一个原型对象。
  • 原型对象都包含一个指向构造函数的指针。
  • 实例对象都包含一个指向原型对象的内部指针。
//伪代码

//构造函数
function Person(){
}

//构造函数的原型对象中constructor指向构造函数自身
Person.prototype.constructor => 指向 function Person(){}

var person1 = new Person();

//实例对象指向原型对象的内部指针。
person1.__proto__ => 指向 Person.prototype

这部分,文字描述有些晦涩!看不懂的话,先看代码例子。

假如,我们让原型对象等于另一个类型的实例对象, 结果会怎么样呢?

显然,此时原型对象将包含一个指向另一个原型的指针。

相应地, 另一个原型中也包含着一个指向另一个构造函数原型的指针。

假如,另一个原型又是另一个类型的实例对象,还是包含一个指针指向另外一个构造函数的原型,所以上述关系依然成立。

如此层层递进,就构成了实例与原型的链条。

这就是所谓原型链的基本概念。

你可以想象成 “不断认祖归宗”的过程,认祖归宗的路径连接起来,就形成了一个“血缘链”。

实现原型链的基本模式

//实现原型链的示例代码

//SuperType 父类型
function SuperType(){
    this.property = true;
}

SuperType.prototype.getSuperProperty = function() {
    console.log(this.property);
    return this.property;
}

//SubType 子类型
function SubType() {
    this.subproperty = false;
}

//子类型 继承 父类型

SubType.prototype = new SuperType();

//实际上子类型的原型是这样的。
/*SubType.prototype = {
    property: true,
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/

SubType.prototype.getSubProperty = function(){
    console.log(this.subproperty);
    return this.subproperty;
}

//那么现在子类型的原型对象是这样的

/*SubType.prototype = {
    property: true,
    getSubProperty: function()  {
    console.log(this.subproperty);
    return this.subproperty;
    },
    __proto__:  {
        constructor : SuperType,
        getSuperProperty:function() {
            console.log(this.property);
            return this.property;
        }
    }
}
*/

var subInstanceObject = new SubType();
console.log(subInstanceObject.getSuperProperty()); // true

以上代码定义了两个类型(构造函数):

SuperType(父类型)和 SubType(子类型)。

每个类型分别有一个属性和方法。

它们主要的区别是SubType继承了SuperType(子类继承父类),而继承是通过创建SuperType的实例对象, 然后将实例对象赋予SubType.prototype(子类的原型)实现的。

实现的本质是重写原型,改写为另外一个类型的实例对象,

生成另外一个类型的实例对象的过程中,实例对象中的所有属性和方法,赋予给重写的原型,

重点,这个实例对象的内部有个属性__proto__指向,构造这个实例对象的构造函数原型,

从而实现继承,

属性__proto__,确实很像一条链子!

实现原型链,本质上扩展了原型搜索机制。

当读取或者访问一个实例属性时,首先会在实例中搜索该属性,如果没有找到该属性,则会沿着去搜索实例对象内部的__proto__指向的原型。

通过原型链实现继承,搜索过程,就像沿着一条链子不断向上搜寻。

就上面的示例代码来说,subInstanceObject.getSuperProperty()会经历三次查找!

查找过程

  1. 搜索实例对象自身, 没找到该方法,沿着__proto__找。
  2. 找到(构造)实例对象的构造函数的原型对象,还是没找到该方法,继续沿着原型对象的__proto__的指向寻找。
  3. 找到生成构造函数的原型对象的构造函数,搜索其原型对象,找到了。

在找不到属性或方法的情况下,搜索过程总是要一环一环地前行到原型链末端才会停下来。

点赞
收藏
评论区
推荐文章
Souleigh ✨ Souleigh ✨
4年前
JavaScript 是什么?
前言引用《JavaScript高级程序设计第四版》中说的话——“从简单的输入验证脚本到强大的编程语言,JavaScript 的崛起没有任何人预测到。它很简单,学会用只要几分钟;它又很复杂,掌握它要很多年。要真正学好用好 JavaScript,理解其本质、历史及局限性是非常重要的”。面试官:JavaScript 是什么?我:
徐小夕 徐小夕
4年前
如何用不到200行代码写一款属于自己的js类库
前言JavaScript的核心是支持面向对象的,同时它也提供了强大灵活的OOP语言能力。本文将使用面向对象的方式,来教大家用原生js写出一个类似jQuery这样的类库。我们将会学到如下知识点:闭包:减少变量污染,缩短变量查找范围自执行函数在对象中的运用extend的实现原理如何实现跨浏览器的事件监听原型链与继承接下来我会对类库
徐小夕 徐小夕
4年前
《javascript高级程序设计》核心知识总结
此文是对js高级程序设计一书难点的总结,也是笔者在看了3遍之后的一些梳理和感想,希望能借此巩固js的基础和对一些核心概念有更深入的了解。摘要js基本的数据类型和关键点变量,作用域和内存问题垃圾回收机制面向对象的程序设计实现类与继承的经典方式BOM和DOM对象DOM扩展与高级API介绍高级编程技巧跨文档消息传递和aja
菜园前端 菜园前端
2年前
什么是面向对象编程?
原文链接:什么是面向对象编程?面向对象程序设计(ObjectOrientedProgramming,OOP)是一种计算机编程架构,也可以理解为是一种编程的思想。面向对象程序设计的核心就是对象和类,对象也是类的实例化,类是对现实对象的抽象。对象间通过消息传递
Stella981 Stella981
3年前
JavaScript学习总结(十七)——Javascript原型链的原理
一、JavaScript原型链ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript会向上遍历原型
Stella981 Stella981
3年前
Javascript 是如何体现继承的 ?
js继承的概念js里常用的如下两种继承方式:原型链继承(对象间的继承)类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现在面向对象的语言中,我们使用类来创建一个自定义对象
Wesley13 Wesley13
3年前
JS 面相对象编程
提起面向对象我们就能想到类,对象,封装,继承,多态。在《javaScript高级程序设计》(人民邮电出版社,曹力、张欣译。英文名字是:ProfessionalJavaScriptforWebDevelopers)这本书中描述的还算比较详细。我们看看JavaScript中定义类的各种方法。1.工厂方式javaScript中创建自己的类和对象,我们应
Stella981 Stella981
3年前
JavaScript 基于原型链的继承
JavaScript对象是动态的属性“包”(指其自己的属性)。JavaScript对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。遵循ECMAScript标准,someObject.Prototype
Stella981 Stella981
3年前
JavaScript面向对象编程的15种设计模式
在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”。在JavaScript中并没有类这种概念,面向对象编程不是基于类,而是基于原型去面向对象编程,JS中的函数属于一等对象,而基于JS中闭包与弱类型等特性,在实现一些设计模式的方式上与众不同。ps:本文之讲述面向对象编程的设计模式策略,JavaScript原型的基础请参考阮一峰面向
Stella981 Stella981
3年前
Javascript中,实现类与继承的方法和优缺点分析
Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承第一种方法:利用Javascript中的原型链1//首先定义一个父类23functionAnimal(name,age){4//定义父类的属性5thi