js逆向基础9面向对象之继承1

js继承

继承就是子类可以使用父类的所有功能,并且对这些功能进行扩展。 有个构造函数A,然后又有个构造函数B,但是B想要使用A里的一些属性和方法就是利用继承 js中的继承相当麻烦和复杂
1. 原型链继承
2. 构造继承
3. 组合继承
4. 寄生组合继承
5. 原型式继承
6. 寄生继承
7. 混入式继承
8. extends继承

1... 原型链继承

先复习原型链的知识

c20282106322406ca839d59c9346373c.png

function Parent () {
this.name = 'Parent'
this.sex = 'boy'
}
Parent.prototype.getName = function () {
console.log(this.name)
console.log(this.sex)
}
function Child () {
this.name = 'child'
}
Child.prototype = new Parent()

var child1 = new Child()
child1.getName()
console.log(child1)
console.log(Child.prototype.__proto__ == Parent.prototype)

fa6b9267d5d44b7d97c195c6e0e44128.png

a7c7eebfe42f4e35b821d94458d82228.png
// 这种方式就叫做原型链继承 将子类的原型对象指向父类的实例

78b8bf6ec9894508ba9681b3b9b77e2c.png

27a1df5547c04fbb93755abd1722675a.png

e37eb1ccb6d14c52be7a7f3867ed506b.jpeg

上半部分

9117400ebe8c4adb9945e50d87548bdf.png

下半部分
d0efe449aa244bcabe2a756d2e50e38e.png

6634735a2de04d1e81b757ba763d3b10.png// 缺陷1:
function A () {}
function B () {
this.name = 'anlan'
}
function C () {}
B.prototype = new C()
A.prototype = new B()
a = new A()
console.log(a.name)

ba2a8155d05a479994d4c8a8776cc845.png

先讲push方法:

496f5ff6ea294f298e63ab2a62d2daf7.png

深拷贝和浅拷贝

浅拷贝的话,如果要是改变原始的内容,浅拷贝的值也会变,指向了同一个内存地址
深拷贝的话,如果要是改变原始的内容,深拷贝的值不会变,重新复制了一份,并开辟了新的内存地址

function Parent (name) {
this.name = name
this.sex = 'boy'
this.colors = ['white', 'black']
}
function Child (name) {
this.name = name
this.feature = ['cute']
}
var parent = new Parent('parent')
Child.prototype = parent

var child1 = new Child('child1')
child1.sex = 'girl'
child1.colors.push('yellow')
child1.feature.push('sunshine')

var child2 = new Child('child2')

console.log(child1)
console.log(child2)

console.log(child1.name)
console.log(child2.colors)

console.log(parent)

ecb0f7a5c297443f85abedeb7adfac4b.png

1cd575a56dca4dc4af2178b71d7876fe.png

1d5088d5e4234d458436ef419a7882cd.png

优点 继承了父类的模板,又继承了父类的原型对象
 缺点 1. 如果要给子类的原型上新增属性和方法,就必须放在Child.prototype = new Parent()这样的语句后面
 2. 无法实现多继承, 多个原型指向同一个实例,当有多个实例化子对象时,修改一个会影响其他对象
3. 来自原型对象的所有属性都被共享了【浅拷贝】
4. 创建子类时,无法向父类构造函数传参数

Object.prototype.isPrototypeOf()方法这是对象才有的方法,因为在构造函数的原型上

也就是原型对象中的方法。

isPrototypeOf() 方法用于检查一个对象是否存在于另一个对象的原型链中。

备注: isPrototypeOf() 与 instanceof 运算符不同。在表达式 object instanceof AFunction 中,会检查 object 的原型链是否与 AFunction.prototype 匹配,而不是与 AFunction本身匹配。

 

11cf342ef800453096d1eb7e3d8ed55c.png

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

function Parent () {
this.name = 'parent'
}
function Child () {
this.sex = 'boy'
}
Child.prototype = new Parent()
var child1 = new Child()

console.log(Child.prototype.isPrototypeOf(child1))
console.log(Parent.prototype.isPrototypeOf(child1))
console.log(Object.prototype.isPrototypeOf(child1))98538c66f4f748fd9d0e2667b55140f4.png

2. 构造继承

 

基本原理

复习.call的用法
function Parent (name) {
this.name = name
}
function Child () {
this.sex = 'boy'
Parent.call(this, 'child')
// this.Parent = Parent('child')
}
Child()

6c3b5db8680b4f4f88faa305886fe74a.png

function Parent (name) {
this.name = name
}
function Child () {
this.sex = 'boy'
Parent.call(this, 'child')
// this.Parent = Parent('child')
}
var child1 = new Child()
console.log(child1)

3c55d85fe5e145478a91a91fb75f7bf5.png

变种

function Parent (name) {
this.name = name
}
function Child () {
this.sex = 'boy'
Parent.call(this, 'good boy')
this.name = 'bad boy'
}
var child1 = new Child()
console.log(child1.name)

0dda80de7f92471c876c12734203e958.png

涉及到引用类型

function Parent (name, sex) {
this.name = name
this.sex = sex
this.colors = ['white', 'black']
}
function Child (name, sex) {
Parent.call(this, name, sex)
}
var child1 = new Child('child1', 'boy')
child1.colors.push('yellow')

var child2 = new Child('child2', 'girl')
console.log(child1)
console.log(child2)

24bfee141286420da42e9bb340931bb8.png

构造继承的缺点

function Parent (name) {
this.name = name
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child () {
this.sex = 'boy'
Parent.call(this, 'good boy')
}
Child.prototype.getSex = function () {
console.log(this.sex)
}
var child1 = new Child()
console.log(child1)
child1.getSex()
child1.getName()
// 缺点1:构造继承只能继承父类的实例属性和方法,不能继承父类原型的属性和方法

console.log(child1 instanceof Parent)
// 缺点2:实例并不是父类的实例,只是子类的实例

06b0a5141d7e4babb04dec8bd2b8c07a.png

b4dfdfa579434e79a5c818eab8db338d.png

组合继承 【原型链继承 + 构造继承】

// 使用原型链继承来保证子类能继承到父类原型中的属性和方法
// 使用构造继承来保证子类能继承到父类的实例属性和方法

function Parent (name) {
this.name = name
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name) {
this.sex = 'boy'
Parent.call(this, name)
}
Child.prototype = new Parent()
Child.prototype.getSex = function () {
console.log(this.sex)
}

var child1 = new Child('child1')
var parent1 = new Parent('parent1')
console.log(child1)
console.log(parent1)
child1.getName()
child1.getSex()
parent1.getName()
parent1.getSex()

e853abfb54ca4304922017bd348bcc43.png

constructor

function Parent (name) {
this.name = name
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child (name) {
this.sex = 'boy'
Parent.call(this, name)
}
Child.prototype = new Parent()
Child.prototype.getSex = function () {
console.log(this.sex)
}

var child1 = new Child('child1')
var parent1 = new Parent('parent1')
console.log(child1.constructor)
console.log(parent1.constructor)

// constructor 其实只是个标识作用,再实际的代码中并没有实际意义,所以是否在组合继承中修复这个地方取决于自己

bc73419c164c4f63bfad20e9192bc412.png7f2c84ea57fb4aaab0ce1551da36bdf7.png

组合继承的思维导图

49ec7e9f9ab54bdfa6f71d1194742fd4.jpeg

b1d85b2428ba47eaa2b5442673f4b53f.png

247b936730984ce0ac499bb8be79adf5.png

思考题

var a;
(function () {
function A () {
this.a = 1
this.b = 2
}
A.prototype.logA = function () {
console.log(this.a)
}
a = new A()
})()

87a892982f0c4e5ba5d3d189915f1e2b.png

a.logA()
// 现在我想要在匿名函数外给A这个构造函数的原型对象中添加一个方法logB用以打印出this.b

9a8d267251c34778a1578bc3c0888e3c.png

d6f4110fee4a477cb13c0e53668e11f4.png

a.constructor.prototype.logB = function () {
console.log(this.b)
}
a.logB()

// 这样也是可以的,但是在任何时候都不建议去人工修改隐式原型

a.__proto__.logB = function () {
console.log(this.b)
}
a.logB()

 

组合继承关于引用对象的处理

function Parent (name, colors) {
this.name = name
this.colors = colors
}
Parent.prototype.features = ['cute']
function Child (name, colors) {
this.sex = 'boy'
Parent.apply(this, [name, colors])
}
Child.prototype = new Parent()
Child.prototype.constructor = Child

var child1 = new Child('child1', ['white'])
child1.colors.push('yellow')
child1.features.push('sunshine')
var child2 = new Child('child2', ['black'])

console.log(child1)
console.log(child2)
console.log(Child.prototype)

1c1bbb4c4c06403f94dcd4eeaa8c647b.png

3113f6f8f5bd4de4a550fd80e0676ad2.png

// 组合继承的优点
// 可以继承父类实例属性和方法,也能够继承父类原型属性和方法
// 弥补了原型链继承中引用属性共享的问题
// 可传参,可复用
// 缺点:

function Parent (name) {
console.log(name)
this.name = name
}
function Child (name) {
Parent.call(this, name)
}
Child.prototype = new Parent()
var child1 = new Child('child1')

console.log(child1)
console.log(Child.prototype)

// 原型链继承和构造继承的时候都会调用一次 console.log(name)
// 1. 使用组合继承时,父类构造函数会被调用两次
// 2. 并且生成了两个实例,子类实例中的属性和方法会覆盖子类原型(父类实例)上的属性和方法,所以增加了不必要的内存。

... 注意坑~

function Parent (name, colors) {
this.name = name
this.colors = colors
}
Parent.prototype.features = ['cute']
function Child (name, colors) {
Parent.apply(this, [name, colors])
}
Child.prototype = new Parent()
Child.prototype.constructor = Child

var child1 = new Child('child1', ['white'])
child1.colors.push('yellow')
child1.features.push('sunshine')
var child2 = new Child('child2', ['black'])

console.log(child1.colors)
console.log(child2.colors)
console.log(child1.features)
console.log(child2.features) // 滴滴


// features是定义在父类构造函数原型对象中的,是比new Parent()还要更深一层的对象、
// 它只能解决原型(匿名实例)中引用属性共享的问题。features是Parent.prototype上的属性,相当于是爷爷那一级

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值