美文网首页
继承的概念

继承的概念

作者: 麓语 | 来源:发表于2018-07-30 11:25 被阅读0次

上一篇:原型的基本概念
下一篇:Object 对象

继承的概念

在开发过程中, ⾯向对象是⼀种处理代码的思考⽅式. 在⾯向对象中继承就是其中⼀个⾮常重要的概念. 接下来本节详细讨论继承的概念.

为何需要使⽤继承

在开发中, 经常会发现多个不同类型的对象都有共同的⽅法. 例如代码:

var o1 = new Number(144);
console.log("打印 Number 对象 o1 = " + o1);
var o2 = new Date();
console.log("打印 Date 对象 o2 = " + o2);
var o3 = new Array(1, 4, 4);
console.log("打印 Array 对象 o3 = " + o3);
var o4 = new Error("a test");
console.log("打印 Error 对象 o4 = " + o4);
function MyConstructor() {
}
var o5 = new MyConstructor();
console.log("打印⾃定义对象 MyConstructor o5 = " + o5);

在本例中, 打印对象都有⼀个共同的操作, 即 "和字符串相连接". 该操作在执⾏的时候, 会⾃动的调⽤⼀个⽅法, 即 toSting() ⽅法. 因此, 执⾏代码

console.log("打印⾃定义对象 MyConstructor o5 = " + o5);

等价于执⾏代码:

console.log("打印⾃定义对象 MyConstructor o5 = " + o5.toString());

那么问题来了, 这个类型中没有没有定义 toString() ⽅法呢? 很显然是没有
的. 那么如何实现?

其实很简单, 就是为了 "复⽤".

在开发中常常会有重复的操作, 例如⻚⾯上很多东⻄都可以点击; ⼀个游戏中,常常会有⾓⾊可以⾛动等等. 因此将重复执⾏的代码提取出来, 不⽤再编写代码的时候每次都要将其再写⼀遍. 那么这种拿来主义就是继承.

在继承中, ⼀个对象继承⾃另⼀个对象. 继承的对象中包含被继承对象的所有成员.

例如⼈会说话, 那么将说话的功能提取出来作为⼀个对象. 继承⾃该对象的美国⼈, ⽇本⼈, 或是英国⼈就都具有说话的⽅法了.


继承图1.png

因此⼀句话总结继承, 就是 "为了偷懒, 就拿来主义".

继承的实现⽅式

继承的实现⽅式有很多种, 如今主流的继承有类继承和原型继承. 类继承的语⾔有: C++, Java, C# 等, ⽽原型继承有: Self, Io, JavaScript 等.

C# 中基于类的继承

在基于类继承的编程语⾔中, 有⼀个对象的模板, 称之为类. 需要对象则⾸先设计⼀个类, 由类来创建对象. ⽽继承是指类之间的继承.

例如写⼀个⽗类

class BaseClass {
  public void SayHello() {
    System.Console.WriteLine("你好");
  }
}

然后提供⼀个⼦类

class SubClass : BaseClass {
}

最后直接创建⼦类独享, 即可调⽤⽅法

public static void Main(string[] args) {
  SubClass o = new SubClass();
  o.SayHello(); // => 你好
}

这⾥的继承实际上是利⽤模板来实现的. 在模板 BaseClass中定义了⼀个⽅法 SayHello , 然后设计⼀个⼦类 SubClass 继承⾃ BaseClass , 在⼦类中没有规定任何东⻄. 但是由⼦类创建出来的对象具有 SayHello ⽅法, 并且可以调⽤.

这个就是利⽤类的继承. 类继承了, 那么由该类创建出来的对象就具有被继承的成员.

原型继承

与类继承不同, 在 JavaScript 中, 使⽤原型来实现继承. 在原型中定义的所有成员都会被其构造⽅法创建的对象所继承. 在 JavaScript 中不存在类的概念,因此实现继承的⽅式也不再唯⼀和统⼀.

还是说话的例⼦, 使⽤ JavaScript 来实现

// 定义⼀个对象, 将来作为原型对象
var proto = {
  sayHello : function() {
  console.log("你好!!!");
}};
// 定义⼀个构造函数
function Person() {
}
// 设置 Person 的原型
Person.prototype = proto;
// 创建对象, 具有 sayHello ⽅法
var p = new Person();
p.sayHello();

在本例中没有类的概念, 继承也不是模板之间的继承. ⽽是给构造⽅法设置⼀个原型对象, 由该构造函数创建出来的对象就具有该原型对象中的所有内容.我们称这个对象就继承⾃原型对象.

注意: 前⾯曾经介绍过 __proto__ 的概念, 因此实现继承的⽅法也就不统⼀了, ⽐较随意.

值得说明的是, 所有由该类创建出来的对象, 都具有了原型中定义的属性 (⽅法). 与定义和设置的顺序⽆关. 但是如果重新设置属性就不正确了.

例如, 下⾯的代码可以正常执⾏.

function Person() {
}
var p1 = new Person();
Person.prototype.sayHello = function() {
  console.log("hello, 你好 JavaScript!");
};
var p2 = new Person();
p1.sayHello(); // => hello, 你好 JavaScript!
p2.sayHello(); // => hello, 你好 JavaScript!

上⾯的代码, 给 Person 的原型添加了⼀个 sayHello ⽅法, 因此两个Person 对象都可以调⽤该⽅法.

如果是直接重新设置构造函数 Person 的原型对象, 那么就会报⼀个TypeError 异常.

function Person() {
}
var p1 = new Person();
Person.prototype = { sayHello : function() {
  console.log("hello, 你好 JavaScript!");
}};
var p2 = new Person();
p1.sayHello(); // => 异常
p2.sayHello();

原因很简单, 这个原型赋值修改了构造函数 Person 的原型对象类型.

function Person() { }
var p1 = new Person();
Person.prototype = { sayHello : function() {
  console.log("hello, 你好 JavaScript!");
}};
var p2 = new Person();
console.log(p1.constructor); // => function Person() { }
console.log(p2.constructor); // => function Object() { [native code]

可⻅修改后, 原型不再是 Person 类型的了, ⽽是 Object 类型.

Object.prototype

JavaScript 中, 每⼀个对象都有原型. ⽽且每⼀个原型都直接, 或间接的继承⾃ Object.prototype 对象.

function Person() {}

定义了⼀个构造函数, 那么他就有⼀个 Object 类型的原型对象被设置给了Person.prototype

console.log(Person.prototype);
console.log(Person.prototype instanceof Object); // => true
// note: 可⻅ Person.prototype 是 Object 类型的

如此, 由 Person 创建出来的对象就继承⾃ Object 类型的对象. ⽽Person.prototype 也是⼀个对象. ⾃然也有⼀个原型对象.

在 Chrome 中可以使⽤ __proto__ 引⽤. 因此可以获得 Person.prototype的原型对象

console.log(Person.prototype.__proto__); // => Object {}

那么从逻辑上就有下⾯的继承模型:

继承图2.png
需要注意的是, Object 类型的原型对象的原型对象为 null
console.log(Person.prototype.__proto__.__proto__ === null);
// => true

⼀种继承的实现

有了上⾯的分析, 实现继承就可以分为三个步骤:

    1. 获得构造函数 F
    1. 设置 F 的原型为被继承的对象
    1. F 创建继承对象

简单的实现为:

// 被继承对象
var pareObj = {
  sayHello: function() {
    console.log("Hello, jk");
  }
};
// 创建构造函数
function F() {
}
// 设置原型对象
F.prototype = pareObj;
// 创建继承对象
var obj = new F();

但是这么写太过于繁琐, 因此⼤师 Douglas Crockford 在他的 《JavaScript: The Good Parts》中给出了下⾯的做法:

if (!Object.create) { // ECMAScript 5 中已经⽀持该⽅法
  Object.prototype.create = function (pare) {
  function F() {}
    F.prototype = pare;
    return new F();
  }
}

上一篇:原型的基本概念
下一篇:Object 对象

⼩结

  • 所谓继承就是拿来主义, 将重复的东⻄进⾏复⽤
  • JavaScript 中继承就是给构造函数的 prototype 设置对象
  • 每⼀个对象都有⼀个原型对象
  • ⼀个经典的继承⽅法
    此系列笔记均参考自 蒋坤 笔记

相关文章

  • 继承的概念

    上一篇:原型的基本概念下一篇:Object 对象 继承的概念 在开发过程中, ⾯向对象是⼀种处理代码的思考⽅式. ...

  • java基础面向对象之继承性(六-2)

    一、继承概念 二、继承的优点 三、继承体现

  • 1.6 继承

    本小节知识点: 继承基本概念 OC中的继承关系 OC中如何实现继承 1.继承基本概念 现实生活中的继承 交通工具类...

  • 第六章:面向对象高级——继承的基本实现。

    本章目标 掌握继承的机泵概念及实现 掌握继承实现的各种限制 1、具体内容 1.1、继承的基本概念 在讲解集成的概念...

  • 继承的概念(补)

    一、继承作用:实现代码的复用性(体现在设计)1.所谓的继承就是用子类(派生类)继承父类(基类,超类).2.使用ex...

  • Java之继承

    继承的概念 继承的格式 继承示例 继承中成员变量的访问特点 继承中成员方法的访问特点

  • C++学习笔记(五)继承和派生(上)

    1、继承的概念及语法 继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承(例如儿子继承父亲财产)...

  • Java-继承

    继承 继承(inheritance)是面向对象的重要概念。继承是除组合(composition)之外,提高代码重复...

  • 类的继承

    继承基本概念 继承关系可以解决代码的重复问题。 单继承;不能多重继承,允许多层继承。 继承类图表示:实线箭头,箭头...

  • 2018-08-31继承学习简要描述

    继承的概念在生活中举例: 儿子可以继承父亲的财产,但是儿子以后也会拥有自己的财产 在java继承的概念来说,子类可...

网友评论

      本文标题:继承的概念

      本文链接:https://www.haomeiwen.com/subject/manxvftx.html