IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 前端 JavaScript 之 继承 _ 原理版 -> 正文阅读

[JavaScript知识库]前端 JavaScript 之 继承 _ 原理版

目录

继承 :?

为什么需要继承???

构造函数 :?

常见的继承方案?:??

1.?原型继承?:?

?图解 :?

2.?call 继承?:

?扩展 : 第二种写法?

3.?组合继承?:?

4.?ES6?的继承语法?:

简图 :?


继承 :?

继承 :?

????????+?继承是一个关于??构造函数? 的高阶应用

????????+?继承一定是出现在?两个构造函数?之间的关系

????????+?什么是继承?:?

??????????=>?当?构造函数A?的实例,?使用了?构造函数B?原型上书写的属性和方法

??????????=>?此时,?我们就说?A?和?B?出现了继承关系

??????????=>?构造函数B?继承自?构造函数A

??????????=>?构造函数A?是?构造函数B?的父类

??????????=>?构造函数B?是?构造函数A?的子类

为什么需要继承???

????+?我们面向对象开发的核心,?是?=>? 高内聚 低耦合? <=

????+?来思考???进行假设?:?

??????=>?我书写一个?苹果类?:

????????~>?颜色,?品牌,?重量,?水分,?名称

????????~>?吃的方法:?削皮吃,?去核吃

??????=>?我书写一个?橘子类?:

????????~>?颜色,?品牌,?重量,?水分,?名称

????????~>?吃的方法:?剥皮吃,?吐籽吃

可以看到 : 苹果类 和 橘子类 有 共同的 部分

????+ 所以换一种书写方法?:?

??????=>?水果类?:?

????????~>?颜色,?品牌,?重量,?水分,?名称

??????=>?苹果类?:

????????~>?继承?水果类

????????~>?书写我独立的内容

????????~>?形状

??????=>?橘子类?:?

????????~>?继承?水果类

????????~>?书写我独立的内容

????????~>?额外用途


构造函数 :?

+?构造函数 :?

??=>?原型 ( prototype ) :

**每一个函数?天生自带一个属性,?叫做?prototype?,?是一个?对象数据类型?**

??=>?为什么需要原型 :

????~>?为了解决 构造函数 的不合理

????~>?书写 构造函数 的时候

????~>?属性 直接书写在 构造函数体内

????~>?方法 书写在 构造函数 的 原型 上

??=>?目的:?为了书写一些方法,?给到该 构造函数 的 实例 使用

????~>?把每一个实例都会用到的方法,?提取出来放在了 构造函数 的 原型 上


常见的继承方案?:??

1.?原型继承?:?

原型继承(原型链继承) :

????????+?核心:?让子类的? 原型? 指向?父类的? 实例?

????????+?语法:?子类.prototype?=?new?父类( )

??????优点:

????????+?父类的?构造函数体内的属性?和?原型?上的方法都可以继承下来

??????缺点:

????????+?本该一个构造函数完成的所有参数,?需要分开两个地方传递

????????+?同样都是给?子类实例?使用的属性,?在两个位置传递参数

????????+?继承下来的属性不在自己身上,?子类的实例的所有属性分开了两部分书写

????????+?访问的属性需要去到?__proto__?上才能找到

// 父类
function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
/*
  父类的实例 :
    const p = new Person('Jack', 18)
    p === {
      name: 'Jack',
      age: 18,
      __proto__(Person.prototype): {
        sayHi: function () {},
        constructor: Person,
        __proto__(Object.prototype): {
          __proto__: null
        }
      }
    }
  不管是谁继承了 Person 类
    + 要求继承的构造函数的实例, 可以使用 name 和 age 属性
    + 要求继承的构造函数的实例, 可以使用 sayHi 方法
*/
// 子类
function Student(gender) {
  this.gender = gender
}

//?当?Student?构造函数书写完毕以后

//?此时会伴生一个?Student.prototype?是一个对象数据类型

//?我就可以向?Student.prototype?上添加一个成员

//?因为?Student.prototype?是一个对象

//?Student.prototype.a?=?100

// 现在不直接向这个对象上添加内容了

//?而是可以把?Student.prototype?从新赋值

//?本身你的?Student.prototype?保存的是一个?对象数据类型?的地址

//?我给你赋值为一个新的?对象数据类型?的地址

//?就把你本身保存的地址覆盖了

const?obj?=?{

? ?message:?'我是自定义的?obj?对象'

?}

?Student.prototype?=?obj

//?Student.prototype?既然可以被赋值为一个对象,?那么就是任何一个对象都可以

//?那么我的?Person?的实例?p?也是一个?对象数据类型,?是父类的实例对象

//?我就可以直接把?p?赋值给?Student.prototype

//?因为这句代码的执行

//?Student?的实例可以使用?Person?书写的属性和方法了

//?我们就说?Student?继承自?Person

//?Student?是?Person?的?子类

//?Person?是?Student?的?父类

// const p = new Person('Jack', 18)
// Student.prototype = p
// 进行一下 等量代换
Student.prototype = new Person('Jack', 18)
// s 是 Student 的实例
// s 所属的构造函数是 Student
// s.__proto__ 指向 所属构造函数的 Prototype
// 因为 Student.prototype === p
// s.__proto__ === p
const s = new Student('男')
console.log(s)

?

// 根据原型链的规则
// 对象访问
// 当你需要访问 s 的 gender 成员的时候
// s 自己本身就有, 直接使用
console.log(s.gender) // 自己有的属性 => 男
// 当你需要访问 s 的 name 成员的时候
// s 自己本身没有, 需要去到 自己的 __proto__ 上查找
// s 自己本身的 __proto__ 是 p, 所以就是在使用 p 身上的 name 成员
// p 是 Person 的实例, Student 的实例使用的是 Person 构造函数体内书写的 属性
console.log(s.name)  // 打印 => Jack
// 当你需要访问 s 的 sayHi 成员的时候
// s 自己本身没有, 需要去到 自己的 __proto__ 上查找
// 因为自己的 __proto__ 上也没有, 去到再 __proto__ 上查找
// 又因为自己的 __proto__ 就是 p, 再__proto__ 就是 p.__proto__
// 其实就是去 Person.prototype 上查找的内容
// 此时 Student 的实例使用了 Person.prototype 上书写的 方法
s.sayHi()  // 打印 => hello world

?图解 :?


2.?call 继承?:

call?继承 ( 借用构造函数继承 ) :

??+?核心:?把父类构造函数体,?当做普通函数调用,

??利用?call?方法调用父类构造函数?并?改变?this?指向

??+?语法:?在子类构造函数体内书写? 父类.call(this)

优点:

??+?一个实例使用的属性可以在一个位置传递参数

??+?可以把继承来的属性直接出现在?子类的实例?身上

缺点:

??+?只能继承?父类构造函数体内?书写的内容,?父类构造函数?原型上?的内容不能继承

?call 语法 回顾 :?

?call( ) :?
? +?语法:
??????????=>?函数名.call()
??????????=>?对象名.函数名.call()
????????+?参数:
??????????=>?第一个参数:?要修改的函数内的?this?指向
??????????=>?第二个参数开始:?依次给函数内每一个 参数 赋值
????????+?特点:
??????????=>?会立即调用函数
????????+?用处:
??????????=>?在立即执行的函数时才使用
??????????=>?事件处理函数,?和?定时器处理函数,?一般不会使用这个方法
// 父类
function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }

构造函数概念 :

????+?构造函数也是一个函数

????+?是函数就可以直接调用,?可以不和?new?连用

????+?只是不和?new?连用的时候,?没有自动创建对象的能力了

????//?把?Person?当做一个普通函数调用

????//?因为当做?普通函数?调用,?Person?内的?this?指向谁 ? => window

????//?Person?函数体内的两个内容添加给?window?了

Person('Jack',?18)

console.log(window.name)???//?打印?=>?Jack

console.log(window.age)????//?打印?=>?18
// 既然 Person 可以当做普通函数调用
// call 方法就是用来调用函数, 并且改变 this 指向的
const obj = { message: '我是自定义的一个 obj 对象' }

// 在调用 Person 的时候
// 使用 call 方法, 把 Person 内的 this 改成 obj
// Person 内书写的两个代码添加的成员, 加在 obj 身上了
Person.call(obj, 'Jack', 20)
console.log(obj)

// 子类
function Student(gender, name, age) {
  this.gender = gender
}
Student.prototype.play = function () { console.log('你好 世界') }
const s = new Student('男')
// 因为 call 方法调用 Person 的时候, 把 Person 内的 this 修改为 s 了
// 所以 name 和 age 成员添加到了 s 身上
Person.call(s, 'Rose', 20)
console.log(s)

?

// 子类
function Student(gender, name, age) {
  this.gender = gender
  // 这里是 Student 的构造函数体内
  // 这里的 this 是 Student 的每个实例对象
  // 利用 call 调用 Person 构造函数, 把 Person 内的 this 修改为 Student 内的 this
  // 把 Person 内的 this 修改为 Student 的每一个实例对象
  // Person 构造函数体内书写成员就都添加到了 Student 的实例身上
  Person.call(this, name, age)
}
Student.prototype.play = function () { console.log('你好 世界') }
const s = new Student('男', '张三', 20)
console.log(s)

?

?扩展 : 第二种写法?


3.?组合继承?:?

组合继承 :?

????????+?核心:?把?原型继承?和?call 继承?合并在一起就做组合继承

????????+?优点:

??????????=>?父类构造函数体内的属性和原型上的方法都可以继承

??????????=>?继承下来的属性在子类实例对象自己的身上

????????+?缺点:

??????????=>?原型上会多一套继承下来的属性名

?原型继承 优缺点 :?

call 继承 优缺点 :?

?

// 父类
function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
// 子类
function Student(gender, name, age) {
  this.gender = gender
  // 实现 call 继承
  // 目的: 为了使用继承把父类构造函数体内的属性放到子类实例自己身上
  Person.call(this, name, age)
}

// 实现原型继承
// 目的: 为了把 Person 的 prototype 内的内容继承下来
// 利用原型继承, 继承父类构造函数身上的方法
Student.prototype = new Person()

Student.prototype.play = function () { console.log('你好 世界') }
// 创建子类的实例
const s = new Student('男', '张三', 20)
console.log(s)

?


4.?ES6?的继承语法?:

ES6?的继承方案 :

??+?ES6?官方提出了关键字来实现继承

ES6?的继承语法:

+?语法分成两个部分?:

??1.?书写子类的时候,?使用?extends?关键字

????=>?class?子类名?extends?父类?{?...?}

??2.?在子类的?constructor?内书写

????=>?super( )

??+?注意:

????=>?必须要两个条件同时书写

????=>?在?constructor?内书写?super?的时候,?必须写在所有?this?的最前面

????=>?父类如果是一个?ES5?的构造函数,?那么可以正常继承

????=>?可以继承自?ES6?的?类,?也可以继承自?ES5?的构造函数

// ES5 父类
function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }
//ES6 父类
class Person {
  constructor (name, age) {
    this.name = name
    this.age = age
  }

  sayHi () { console.log('hello world') }
}
// ES6 的类的继承
// 创建一个 继承自 Person 的 Student 类
// extends 关键字相当于原型继承
class Student extends Person {
  constructor (gender, name, age) {
    // 相当于在调用父类构造函数体, 把 name 和 age 传递过去
    // 相当于 call 继承
    super(name, age)
    this.gender = gender
  }

  play () { console.log('你好 世界') }
}

const s = new Student('男', 'Jack', 20)
console.log(s)

?

?


简图 :?

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-28 07:38:44  更:2021-07-28 07:39:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 22:30:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码