js逆向基础10面向对象继承2

继承

寄生组合继承

接着上节

这个时候就需要先介绍一个object函数了
Object.create(proto, propertiesObject)

Object.create(proto, propertiesObject)

参数一,需要指定的原型对象

参数二,可选参数,给新对象自身添加新属性以及描述器

标准的寄生组合继承

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 = Object.create(Parent.prototype)

var child1 = new Child('child1')

与组合继承的区别:

1.是有冗余的,也child.__proto__的指向下(Parent[[Prototype]])下有 this.name=undefined,而标准寄生组合继承没有冗余。

2.getName是在child.proto.__proto__下,也在parent.__proto__下。

我们使用了Object.create(Parent.prototype)创建了一个空的对象,并且这个对象的__proto__属性是指向Parent.prototype的。

Object.setPrototypeOf()方法

Object.setPrototypeOf() 静态方法可以将一个指定对象的原型(即内部的 [[Prototype]] 属性)设置为另一个对象或者 null

语法

jsCopy to Clipboard

Object.setPrototypeOf(obj, prototype)
参数

obj

要设置其原型的对象。

prototype

该对象的新原型(一个对象或 null)。

返回值

指定的对象。

function Parent (name) {

this.name = name

}

Parent.prototype.getName = function () {

console.log(this.name)

}

function Child (name) {

this.sex = 'boy'

Parent.call(this, name)

}

Object.setPrototype(Child.prototype,Parent.prototype)

Child.prototype原来的对象

Parent.prototype要继承的对象

function A(){

this.aaa = 'aaa'

}

function B(){

this.bbb = 'bbb'

A.apply(this)

}

function C(){

this.ccc = 'ccc'

B.apply(this)

}

Object.setPrototypeOf(B.prototype, A.prototype);

Object.setPrototypeOf(C.prototype, B.prototype);

c = new C()

// 再对比一下 Object.create的情况

function A(){}

function B(){

A.apply(this)

}

function C(){

B.apply(this)

}

B.prototype = Object.create(A.prototype);

C.prototype = Object.create(B.prototype);

c = new C()

对比:Object.create:c.__proto__的是A的实例化对象,没有constructor,但是可以人工指向

而Object.setPrototypeOf(B.prototype, A.prototype);c.__proto__是B的实例化对象,有constructor。

标准的寄生组合继承带有引用的情况下

function Parent(name){

this.name = name

this.face = 'cry'

this.colors = ['white', 'black']

}

Parent.prototype.features = ['cute']

Parent.prototype.getFeatures = function (){

console.log(this.features)

}

function Child(name){

Parent.call(this, name)

this.sex = 'boy'

this.face = 'smile'

}

Child.prototype = Object.create(Parent.prototype)

Child.prototype.constructor = Child

var child1 = new Child('child1')

child1.colors.push('yellow')

var child2 = new Child('child2')

child2.features = ['sunshine']

console.log(child1)

console.log(child2)

child1.getFeatures()

child2.getFeatures()

通过child1和child2(colors)结果对比,解决了内存共享的问题,是一个深拷贝。

// 寄生组合继承算是ES6之前一种比较完美的继承方式。

// 它避免了组合继承中调用两次父类构造函数,初始化两次实例属性的缺点。

// 它拥有了上述所有继承方式的优点

// 只调用了一次父类构造函数,只创建了一份父类属性

// 子类可以用到父类原型链上的属性和方法

// 能够正常的使用instanceOf和isPrototypeOf方法

原型式继承

原理是创建一个构造函数,构造函数的原型指向对象,然后调用 new 操作符创建实例,并返回这个实例,本质是一个浅拷贝

var cat = {

heart: '❤️',

colors: ['white', 'black']

}

var guaiguai = Object.create(cat)

var huaihuai = Object.create(cat)

console.log(guaiguai)

console.log(huaihuai)

console.log(guaiguai.heart)

console.log(huaihuai.colors)

同样的,对于 setPrototypeOf

var cat = {

heart: '❤️',

colors: ['white', 'black']

}

res1 = {}

Object.setPrototypeOf(res1, cat);

两者并没有什么区别

寄生式继承 在原型式继承的基础之上进行了一下优化

var cat = {

heart: '❤️',

colors: ['white', 'black']

}

function createAnother (original) {

var clone = Object.create(original);

clone.actingCute = function () {

console.log('我是一只会卖萌的猫咪')

}

return clone;

}

var guaiguai = createAnother(cat)

var huaihuai = Object.create(cat)

guaiguai.actingCute()

console.log(guaiguai.heart)

console.log(huaihuai.colors)

console.log(guaiguai)

console.log(huaihuai)

这两种模式开发和逆向不常用

混入式继承(多继承)

我们一直都是以一个子类继承一个父类,而混入方式继承就是教我们如何一个子类继承多个父类的。也就是单线继承之前讲的是单线继承 A>B>C A继承B,B继承C,现在想A>B

>C

A继承B的同时又继承C

在这边,我们需要用到ES6中的方法Object.assign()

它的作用就是可以把多个对象的属性和方法拷贝到目标对象中,若是存在同名属性的话,后面的会覆盖前面
Object.assign()

Object.assign()

Object.assign() 静态方法将一个或者多个源对象 中所有可枚举自有属性复制到目标对象,并返回修改后的目标对象。

const target = { a: 1, b: 2 };

const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

function Parent (sex) {

this.sex = sex

}

Parent.prototype.getSex = function () {

console.log(this.sex)

}

function OtherParent (colors) {

this.colors = colors

}

OtherParent.prototype.getColors = function () {

console.log(this.colors)

}

function Child (sex, colors) {

Parent.call(this, sex)

OtherParent.call(this, colors) // 新增的父类

this.name = 'child'

}

Child.prototype = Object.create(Parent.prototype)

Object.assign(Child.prototype, OtherParent.prototype) // 新增的父类原型对象

Child.prototype.constructor = Child

var child1 = new Child('boy', ['white'])

child1.getSex()

child1.getColors()

console.log(child1)

修改方法

console.log(Child.prototype.proto === Parent.prototype)

console.log(Child.prototype.proto === OtherParent.prototype)

console.log(child1 instanceof Parent)

console.log(child1 instanceof OtherParent)

class中的继承

主要是依靠两个关键词:extends super

class Parent {

constructor (name) {

this.name = name

}

getName () {

console.log(this.name)

}

}

class Child extends Parent {

constructor (name) {

super(name)

this.sex = 'boy'

}

}

var child1 = new Child('child1')

console.log(child1 instanceof Child)

console.log(child1 instanceof Parent)

// 对比一下寄生组合继承

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 = Object.create(Parent.prototype)

Child.prototype.constructor = Child

var child1 = new Child('child1')

console.log(child1)

child1.getName()

console.log(child1 instanceof Child)

console.log(child1 instanceof Parent)

// class的继承方式完全满足于寄生组合继承

// extends从字面上来看还是很好理解的,对某个东西的延伸,继承。

// 如果不用super看看效果

class Parent {

constructor (name) {

this.name = name

}

getName () {

console.log(this.name)

}

}

class Child extends Parent {

// constructor (name) {

// super(name)

// this.sex = 'boy'

// }

sex = 'boy' // 实例属性sex放到外面来

}

var child1 = new Child('child1')

console.log(child1)

child1.getName()

// class可以通过extends关键字实现继承父类的所有属性和方法

// 若是使用了extends实现继承的子类内部没有constructor方法,则会被默认添加constructor和super。

class Parent {

constructor () {

this.name = 'parent'

}

}

class Child extends Parent {

constructor () {

// super(name) // 把super隐去

}

}

var child1 = new Child()

console.log(child1)

child1.getName()

// 报错,必须得在constructor中调用一下super函数

// super其实有两种用法,一种是当作函数来调用,还有一种是当做对象来使用。

// 之前那道题就是将它当成函数来调用的,而且我们知道在constructor中还必须得执行super()。

// 其实,当super被当作函数调用时,代表着父类的构造函数。

// 虽然它代表着父类的构造函数,但是返回的却是子类的实例,也就是说super内部的this指向的是Child。

class Parent {

constructor () {

console.log(new.target.name)

}

}

class Child extends Parent {

constructor () {

var instance = super()

console.log(instance)

console.log(instance === this)

}

}

var child1 = new Child()

var parent1 = new Parent()

console.log(child1)

console.log(parent1)

// super当成函数调用时,代表父类的构造函数,且返回的是子类的实例,也就是此时super内部的this指向子类。

// 在子类的constructor中super()就相当于是Parent.constructor.call(this)

// super当成函数调用时的限制: 子类constructor中如果要使用this的话就必须放到super()之后

// super当成函数调用时只能在子类的construtor中使用

class Parent {

constructor (name) {

this.name = name

}

}

class Child extends Parent {

constructor (name) {

this.sex = 'boy'

super(name)

}

}

var child1 = new Child('child1')

console.log(child1)

// 报错

// super当成对象来使用时

// 在子类的普通函数中super对象指向父类的原型对象

// 在子类的静态方法中super对象指向父类

class Parent {

constructor (name) {

this.name = name

}

getName () {

console.log(this.name)

}

}

Parent.prototype.getSex = function () {

console.log('boy')

}

Parent.getColors = function () {

console.log(['white'])

}

class Child extends Parent {

constructor (name) {

super(name)

super.getName()

}

instanceFn () {

super.getSex()

}

static staticFn () {

super.getColors()

}

}

var child1 = new Child('child1')

child1.instanceFn()

Child.staticFn()

console.log(child1)

// super当成对象调用父类方法时this的指向

class Parent {

constructor () {}

}

Parent.prototype.sex = 'boy'

Parent.prototype.getSex = function () {

console.log(this.sex)

}

class Child extends Parent {

constructor () {

super()

this.sex = 'girl'

super.getSex()

}

}

var child1 = new Child()

console.log(child1)

// ES6规定,通过super调用父类的方法时,super会绑定子类的this

相关推荐
远望清一色4 分钟前
基于MATLAB的实现垃圾分类Matlab源码
开发语言·matlab
confiself13 分钟前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言
ZL不懂前端19 分钟前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x22 分钟前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
XiaoLeisj25 分钟前
【JavaEE初阶 — 多线程】Thread类的方法&线程生命周期
java·开发语言·java-ee
杜杜的man28 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*29 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
半桶水专家30 分钟前
go语言中package详解
开发语言·golang·xcode
llllinuuu31 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s31 分钟前
Golang--协程和管道
开发语言·后端·golang