Shyno
Don't be shy,no problem!

因为面向对象,所以对象是很重要的储存工具。和面向过程一样,它也有变量名重复的风险,比如之前提到的原型污染。为了一定程度上解决这个问题,引入了子父类和继承的概念。

1.子父类

//父类
const GetObj = function () { this.b = ['1', '2'] } GetObj.prototype.getB = function () { return this.b }
//另一个类 const GetObjj = function () { this.c = ['a', 'b'] }
//变成子类
GetObjj.prototype = new GetObj()
//子类原型单独添加方法
GetObjj.prototype.getC = function () {
  return this.c
}
let objj1 = new GetObj()

  如上述例子,GetObj有个b属性,那GetObj的实例中肯定就有这个属性,GetObjj想要这个属性,可以把自己的原型变成这个实例,GetObjj就拥有这个属性了.这种方式有以下特点:1.该属性是别人的,不是它单独赋值获取的.比如GetObjj.b=[]这种方式.2.原来拥有这个属性的实例的原型本身并不会被它的操作影响.

   那么,获得属性的类就是子类,提供属性的类就是父类.这种方式就叫做继承.

2.继承的方法

继承有好几种方法

   (a:类式继承:子类原型=父类实例

就是前面说明子父类用的方法,核心代码

GetObjj.prototype = new GetObj()

   但是这个方式有个缺陷,即当父亲有多个孩子时,他会一视同仁.即一个子类对继承的属性进行修改(非值传递)的时候会影响所有的子类

onst GetObj = function () {
  this.b = ['1', '2']
}
GetObj.prototype.getB = function () {
  return this.b
}
const GetObjj = function () {
  this.c = ['a', 'b']
}
GetObjj.prototype = new GetObj()
let objj1 = new GetObjj()
let objj2 = new GetObjj()
objj1.b.push('你') //直接往堆里push
console.log('shyno', objj1.b, objj2.b) //['1','2','你']  ['1','2','你']

   (b: 构造函数继承:改变this指向

GetObj.call(this, id)

 简单来说,就是创建子类的时候,在子类内部把父类的this在子类内部指向与子类

const GetObj = function (id) {
  this.b = ['1', '2']
  this.id = id
}
GetObj.prototype.getB = function () {
  return this.b
}
console.log('你')
const GetObjj = function (id) {
  GetObj.call(this, id) //每次子类创建实例的时候,this指向都会被指向子类实例
  this.c = ['a', 'b']
}
let objj1 = new GetObjj(1)  //创建子类实例的时候,子类有了自己的b=['1','2']
let objj2 = new GetObjj(2)   //有自己的b=['1','2']
objj1.b.push('你')   //只修改了objj1的b,所以objj2的没有碰到
console.log('shyno', objj1.b, objj2.b)  //['1','2','你']  ['1','2']

 但是,这种方法也有个问题,父类原型方法不会被继承,即后续再往父类的原型上添加函数并不会被其子类继承

objj1.getB() //没法执行 is not a function

   (c:组合式继承:申明子类时将父类的this指向修改,同时子类的原型为父类实例

const GetObj = function (id) {
  this.b = ['1', '2']
  this.id = id
  this.test = function () {
    console.log('test')
  }
}
GetObj.prototype.getB = function () {  //父类原型添加方法
  console.log('getB')
  return this.b
}
console.log('你')
const GetObjj = function (id) {
  GetObj.call(this, id)  //修改this指向
  this.c = ['a', 'b']
}
GetObjj.prototype = new GetObj()  //原型指向父类实例
let objj1 = new GetObjj(1)
let objj2 = new GetObjj(2)
objj1.b.push('你')
objj1.test()  //test
objj1.getB() //getB

 因为子类原型为父类实例,所以父类原型增加函数时,父类的实例就有相关函数,也就是子类原型有了相关元素,子类实例也就有了函数.

 子类构造函数内部修改了this的指向,所以每次构造子类实例时,每个子类实例都有了自己独立的属性,互不干扰.

  (d:原型式继承和寄生式继承:构造函数依赖构造函数,构造函数起点为对象

  (e:寄生组合式继承:寄生式加构造函数式

 

继承对面向对象开发有重要意义,因为都在类中,故后续开发可通过继承的方式实现公共复用,以及私有添加.即方便又灵活.

 

posted on 2021-03-29 14:33  Shyno  阅读(249)  评论(0编辑  收藏  举报