千锋教育-做有情怀、有良心、有品质的职业教育机构

手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

当前位置:首页  >  行业资讯  > JavaScript全解析——继承

JavaScript全解析——继承

来源:千锋教育
发布人:zyh
时间: 2023-05-25 14:16:00 1684995360

  继承

  ●要知道什么是继承

  ●要知道继承的方式有哪些

  ●每种的继承方式是如何实现的

JavaScript全解析——继承

  什么是继承

  ●继承关系出现在构造函数和构造函数之间

  ●当构造函数A 的实例使用了 构造函数B 的属性和方法

  ●我们就说 构造函数A 继承自 构造函数B

  ○管 构造函数A 叫做子类

  ○管 构造函数B 叫做父类

  ●总结 :继承就是获取存在对象已有属性和方法的一种方式  

function Person(name, age) {
this.name = name
this.age = age
}

Person.prototype.play = function () { console.log('玩游戏') }

// 将来我创建的 Person 的实例, 就会出现两个属性一个方法
const p = new Person('Jack', 18)
console.log(p)

function Student(classRoom) {
this.classRoom = classRoom
}

// 将来我创建的 Student 的实例
// 当我的 s 实例能使用 name 属性, age 属性 和 play 方法的时候
// 我们就说 Student 构造函数继承自 Person 构造函数
// Student 就是 子类
// Person 就是 父类
const s = new Student(2114)
console.log(s)

      继承的方式有哪些

  原型继承

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

  ●优点:

  ○父类构造函数体内的属性和原型上的方法都可以实现继承

  ●缺点:

  ○继承下来的属性不在自己身上, 在自己的原型上

  ○一个构造函数的实例, 需要在两个地方传递参数

  ○所有子类的实例, name 和 age 一模一样

<script>
// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.play = function() {
console.log('玩游戏')
}
// 子类
function Student(classRoom) {
this.classRoom = classRoom
}
// 实现继承
const p = new Person('Jack', 18)
Student.prototype = p
// 此时 s 的 __proto__ 指向谁 ?
// 指向所属构造函数的 prototype
// 因为 Student.prototype 就是 就是 Person 的实例
// s 的 __proto__ 就是 Person 的实例
const s = new Student(2114)
console.log(s)
// 当你访问 s 的 classRoom 成员的时候
// 自己有直接使用
console.log(s.classRoom)
// 当你访问 s 的 name 成员的时候
// 自己没有, 去到自己的 __proto__ 上查找
// 因为自己的__proto__ 就是 Person 的实例
// 其实就是去到 Person 的实例上查找
console.log(s.name)
// 当你访问 s 的 play 成员的时候
// 自己没有, 去到自己的 __proto__ 上查找
// 也就是去到 Person 的实例上查找, 发现还是没有
// 就再去 __proto__ 上查找
// 自己的 __proto__ 的 __proto__
// Person 实例 的 __proto__
// Person 实例 的 __proto__ 就是 Person.prototype
s.play()
const s2 = new Student(2115)
console.log(s2)
</script>

      借用构造函数继承

  ●核心: 把父类构造函数当做普通函数调用, 并且改变其 this 指向

  ●优点:

  ○子类的所有继承下来的属性都在自己身上

  ○子类的所有参数在一个地方传递

  ○子类的所有实例都可以给继承下来的属性赋不一样的值

  ●缺点:

  ○父类的原型上的方法没有继承下来 


// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.play = function() {
console.log('玩游戏')
}
// 子类
function Student(classRoom, name, age) {
this.classRoom = classRoom
// 实现继承
Person.call(this, name, age)
}
const s = new Student(2114, 'Jack', 18)
console.log(s)
const s2 = new Student(2115, 'Rose', 20)
console.log(s2)

      组合继承

  ●核心: 把原型继承和借用构造函数继承放在一起使用

  ●优点:

  ○都能继承下来

  ○属性在自己身上, 每一个子类实例继承的属性值都可以不一样

  ●缺点:

  ○子类的原型上多了一套属性


<script>
// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.play = function() {
console.log('玩游戏')
}
// 子类
function Student(classRoom, name, age) {
this.classRoom = classRoom
// 借用继承
// 目的: 把属性继承在自己身上
Person.call(this, name, age)
}
// 原型继承
// 目的: 继承父类原型上的方法
Student.prototype = new Person()
// 创建子类的实例
const s = new Student(2114, 'Rose', 20)
console.log(s)
</script>

      ES6类继承

  ●类的继承是ES6中提出的一种继承方式

  ●这个继承有了语法的规定,必须要按照这样的方式来继承

  ●类的继承的实现: 两个步骤实现继承

  ○书写子类的时候, 加上 extends 关键字

  ■class 子类 extends 父类 {}

  ■目的: 继承父类原型上的方法

  ○在子类的 constructor 内书写 super()

  ■super(实参)

  ■目的: 继承父类的属性

  ●注意:

  ○必须要书写 super 和 extends

  ○在子类的 constructor 内 super 必须写在 this.xxx 的前面(最前面)

  ●父类可以是构造函数,但是子类不能的构造函数因为extends和super关键字就是给类设计的


<script>
// 父类
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
play() {
console.log('玩游戏')
}
}
// 父类
// function Person(name, age) {
// this.name = name
// this.age = age
// }
// Person.prototype.play = function () { console.log('玩游戏') }
// 子类
class Student extends Person {
constructor(classRoom, name, age) {
super(name, age)
this.classRoom = classRoom
}
study() {
console.log('学习')
}
}
const s = new Student(2114, 'Jack', 18)
console.log(s)
class Teacher extends Person {
constructor(gender, name, age) {
super(name, age)
this.gender = gender
}
}
const t = new Teacher('男', 'Jack', 20)
console.log(t)
</script>

      拷贝继承

  ●利用 for in 循环遍历对象

  ●把所有的内容复制一份放在子类的原型上


// 书写 for in 循环的时候, 不光可以遍历到对象自己身上的属性, 也可以遍历到原型上的属性
// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () { console.log('hello world') }

// 创建一个父类的实例
// const p = new Person('Jack', 18)
// console.log(p)
// for (let k in p) {
// console.log(k)
// }

// 子类
function Student(gender, ...arg) {
this.gender = gender

// 创建一个父类的实例
const p = new Person(...arg)
// 利用 for in 循环继承
for (let k in p) {
// 随着循环, k 分别是 name age 和 sayHi
Student.prototype[k] = p[k]
}
}

const s = new Student('男', 'Jack', 18)
console.log(s)
console.log(s.name)
const s2 = new Student('女', 'Rose', 20)
console.log(s2)
console.log(s2.name)

      寄生式继承

   /*
寄生式继承1

*/

// 父类
function Person(name) {
this.name = name
}
Person.prototype.sayHi = function () { console.log('hello world') }

// 子类
// 构造函数内不要写 return
function Student() {
// 直接在子类里面 return 一个父类的实例
const p = new Person('Jack')
return p
}

// 创建一个子类的实例
// 看似得到的是 Student 的实例, 但是其实得到的还是 Person 的实例
const s = new Student()
console.log(s)



/*
寄生式继承2 - 对寄生式继承1 的 改造
*/

// 父类
function Person(name) {
this.name = name
}
Person.prototype.sayHi = function () { console.log('hello world') }

// 子类
// 构造函数内不要写 return
function Student(gender) {
this.gender = gender
}

// 寄生一下 父类的原型
// Student的原型指向 Person的原型
Student.prototype = Person.prototype

// 创建一个子类的实例
// Student 自己没有原型使用了, 直接使用 Person 的原型
const s = new Student('男')
console.log(s)



// 寄生式组合继承

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


// 实现继承
// 借助一个第三方构造函数
function Third() {}
// 第三方构造函数去继承 父类
// 利用寄生继承的方式来实现
// 第三方的 原型 指向 父类的原型
Third.prototype = Person.prototype
// 将来我使用第三方创建实例的时候
const t = new Third()

// 子类
function Student(...arg) {
// 利用 call 继承
Person.call(this, ...arg)
}
// 子类去想办法继承第三方的内容
// 利用原型继承去继承第三方内容
// 子类的原型指向第三方的实例
Student.prototype = new Third()
const s = new Student('Jack', 18)
console.log(s)


// 利用了一个自执行函数
// 自执行函数, 不需要名字的函数
;(function () {
var a = 100
console.log('你好 世界')
})()


// 子类
function Student(gender, ...arg) {
this.gender = gender

Person.call(this, ...arg)
}

// 把 第三方内容 放在自执行函数内
(function () {
function Third() {}
Third.prototype = Person.prototype
Student.prototype = new Third()
})()

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


      冒充式继承  


/*
冒充继承
+ 利用了一个浅拷贝 + 寄生继承
*/

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

const p = new Person('Jack', 18)

// 寄生继承
function Student(gender) {
this.gender = gender

// 创建完毕实例以后, 拷贝一个父类的实例
Object.assign(this, p)
}
Student.prototype = Person.prototype

const s = new Student('男')


console.log(s)

 

tags:
声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。
10年以上业内强师集结,手把手带你蜕变精英
请您保持通讯畅通,专属学习老师24小时内将与您1V1沟通
免费领取
今日已有369人领取成功
刘同学 138****2860 刚刚成功领取
王同学 131****2015 刚刚成功领取
张同学 133****4652 刚刚成功领取
李同学 135****8607 刚刚成功领取
杨同学 132****5667 刚刚成功领取
岳同学 134****6652 刚刚成功领取
梁同学 157****2950 刚刚成功领取
刘同学 189****1015 刚刚成功领取
张同学 155****4678 刚刚成功领取
邹同学 139****2907 刚刚成功领取
董同学 138****2867 刚刚成功领取
周同学 136****3602 刚刚成功领取
相关推荐HOT
开班信息
北京校区
  • 北京校区
  • 大连校区
  • 广州校区
  • 成都校区
  • 杭州校区
  • 长沙校区
  • 合肥校区
  • 南京校区
  • 上海校区
  • 深圳校区
  • 武汉校区
  • 郑州校区
  • 西安校区
  • 青岛校区
  • 重庆校区
  • 太原校区
  • 沈阳校区
  • 南昌校区
  • 哈尔滨校区