js 中的继承

js 中的继承

1. 原型链继承

概念

​ 让 父类的属性和方法 在 子类实例 的原型链上;

方法

让 子类的原型 指向 父类的实例,并且把 父类的实例中的 constructor 指向子类;

子类.propotype = new 父类();
子类.propotype.constructor = 子类;

特性

  1. 原型链继承 不像其他编程语言的继承一样(其他编程语言的继承一般是拷贝继承,就是 子类 继承 父类,会把父类的属性和方法都拷贝一份到子类中,供子类的实例使用);

    而原型链继承是把 父类的原型 放到 子类实例的原型链上,子类实例可以使用 __proto__ 的 查找机制完成调用;

  2. 子类可以重写父类的属性方法,但是会影响到 父类的实例;

  3. 子类要添加原型方法时,要在实现继承后添加;

  4. 父类中私有 和 公有 的属性方法,都会变成 子类 的 公有属性 和 方法;


例子1

// 父类
function A(x) {
    this.x = x
}
// 父类的原型对象
A.prototype.getX = function() {
	console.log(this.x)
};

// 子类
function B (y) {
    this.y = y
}

// 让 子类的原型 = 父类的实例, 完成继承
B.prototype = new A(100)
// 让 父类的实例的 constructor 指向 子类
B.prototype.constructor = B;

B.prototype.getY = function () {
	console.log(this.y)
}


// 生成实例
let b1 = new B(200)
console.log(b1)

在这里插入图片描述

然后他们的结构图片为:

在这里插入图片描述


例子2

// 父类
function A() {
    this.name = '你好'
    this.age = 23
    this.list = []
}
// 父类的原型方法1
A.prototype.height = 100

// 父类的原型方法2
A.prototype.push = function(p) {
    this.list.push(p)
}

// 子类
function B (js) {
    this.js = js
}

// 让 子类的原型 = 父类的实例
B.prototype = new A()
B.prototype.constructor = B

B.prototype.one = function () {
    console.log('子类的one')
}

let b1 = new B('子实例1');
console.log(b1)

// 调用子类的原型对象方法
b1.one()  // => 子类的one

// 修改 父类中的属性,是引用地址,所以会造成 影响
b1.push('子类添加1')
console.log(b1.list) // => ["子类添加1"]

let b2 = new B('子实例2')
console.log(b2.list)  // => ["子类添加1"]

2. call继承

概念

​ 在 子类 内,使用 call() ,调用 父类函数,并改变父类中的 this 指向;指向 子类的实例;

​ 在 子类 中把 父类当做普通函数执行,让 父类中的 this 执行子类的实例,相当于给 子类的实例添加了 私有属性 和 方法;


方法

function 父类 (b) {
    this.b = b
}

function 子类 (a) {
    父类.call(this, b)
    this.xx = a
}

特性

  1. 只能继承父类的 私有属性和方法(因为是把 父类当做普通函数执行的 和 类的原型对象上的属性和方法没有关系);
  2. 父类的私有 属性 和 方法,变成 子类的私有 属性 和 方法;

例子

// 父类
function A(x) {
    this.x = x
}
// 父类的原型对象
A.prototype.getX = function() {
	console.log(this.x)
}


// 子类
function B (y) {
	// 执行普通函数 A,并把 A 中的 this 改为 子类的实例  b1
	A.call(this, 100)  // => b1.x = x =>  b1.x = 100
    this.y = y
}
B.prototype.getY = function () {
	console.log(this.y)
}


// 生成实例
let b1 = new B(200)
console.log(b1)

在这里插入图片描述

3. 寄生组件 继承

概念

​ 使用 call() 和 类似原型继承;使用 call() 继承父类的私有属性方法,利用 原型 Object.create(Obj) 继承 父类的公有属性方法;


方法

function A (x) {
    this.x = x
}

function B (y) {
    A.call(this, 10)
    this.y = y
}

// 利用 Object.create 创建一个空对象,把空对象的 __propo__ 指向 A的原型;
B.prototype = Object.create(A.prototype)
// 把空对象的 constructor 指向 子类;
B.prototype.constructor = B

特征

  • 父私有和公有的属性和方法,分别是 子类 私有 和 公有的属性和方法(推荐使用);
  • 不过 Object.create() 在 ES6 中出现,IE 版本浏览器不支持;但我们可以手写一个 Object.create 函数;注意,在 IE 里是不允许操作 __proto__ 的;
Object.create = function(obj) {
    function Fn() {}
    // 空对象 的原型指向 父类
    Fn.prototype = obj;
    // new 出来的实例,就的 __proto__ 就指向 obj(父类)了。
    return new Fn();
}

例子

// 父类
function A(x) {
    this.x = x
}
// 父类的原型对象
A.prototype.getX = function() {
	console.log(this.x)
}


// 子类
function B (y) {
    	// call 继承私有属性和方法
		A.call(this, 100) 
		this.y = y
}

// Object.create 继承公有属性方法
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

/*
	以上的继承和 原型链的继承差不多,
	原型链的继承: 将 子类的原型 指向 父类的实例
	寄生组合继承: 将 子类的原型 指向 新创建的对象(就像父类的实例,只不过他没有私有属性和方法,因为新创建的对象, __proto__ 也指向 父类的原型;
*/

B.prototype.getY = function () {
	console.log(this.y)
}


// 生成实例
let b1 = new B(200)
console.log(b1)

在这里插入图片描述

他们的结构为:

在这里插入图片描述

4. ES6 中的 class 继承

概念

​ 类的继承使用 extendssuper 关键字进行 类之间的继承;

类的继承不能使用 call()子类.prototype = Object.create(父类.prototype)


方法

class{
	constructor () {
        // 私有属性和方法
    }
    // 公有方法
    xx() {}
}

classextends{
    constructor () {
        super()
    }
}

注意

extends 的功能和 子.prototype.__proto__ = 父.prototype 一致 。

子类继承父类,可以不写 constructor ,如果有写了 constructor 那么他里面的第一条代码,就必须写 super();如果不写 comstructor 浏览器会自动创建

constructor (...xx) {
    super(...xx)
}

super() 就相对于 call() 把父类当做普通函数执行,并向父类传递参数,让方法中的 this 指向 子类的实例 。


例子

// 父类
class A {
	constructor (x) {
		// 私有属性
		this.x = x
	}
	// 公有方法
	getX () {
		console.log(this.x)
	}
}
// 也可以给原型添加属性或方法
A.prototype.goA = 'A变身'


// 子类
class B extends A{
	/* 
	如果使用了 继承 extends,在子类的构造函数中要把 super() 写上,
	因为他是传递数据给 父类 的,如果没写 super() 就会报错的,因为父类中, 
	有 待传入的参数 。*/
	constructor (y) {
		super()  // 类似于 call()
		this.y = y
	}
	getY () {
		console.log(this.y)
	}
}

let b1 = new B(100);
console.log(b1)

super() 不传时,父类中接收到的参数为: undefined



学习视频地址:哔哩哔哩视频传送门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值