💐💐重温经典之原型链和继承

495 阅读6分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战


大佬们好,我是江湖不渡i,前端菜鸡,react初学者。
老规矩总结放前面:

    如果让一个原型对象等于另一个类型的实例,层层递进,构成实例与原型的链条,这就是原型链。🌲
    原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。

    每当创建一个新函数,就会根据特定的规则为该函数创建一个prototype属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含可以由特定类型的 所有实例 共享的属性和方法,这个对象就是通过调用构造函数创建的对象实例的原型对象。 所有的原型对象都会默认获得一个constructor(构造函数) 属性该属性指向构造函数。 当调用构造函数创建一个实例之后,该实例内部会包含一个指针(属性),指向构造函数的原型,我们可以称这个指针为 [[Prototype]]

function Person (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name)
    }
}
var person1 = new Person(“Nicholas”, 29, “Sofware Engineer”)
var person2 = new Person(“Greg”, 27, “Doctor”)

alert(person1.constructor == Person) // true
alert(person2.constructor == Person) // true

//创建出来的所有对象即使Object的实例,同时也是Person的实例

原型链

构造函数,原型和实例的关系
    每一个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而每个实例都包含一个指向构造函数的原型对象的内部指针。

原型链
    如果让一个原型对象等于另一个类型的实例,层层递进,构成实例与原型的链条,这就是原型链。

    创建了自定义的构造函数,其原型对象默认只会取得 constructor 属性;其他方法都是从Object 继承来的 当调用构造函数创建一个实例之后,该实例内部会包含一个指针(属性),指向构造函数的原型,我们可以称这个指针为 [[Prototype]]

image.png     Function(Object)包含 prototype(原型对象指针)
    prototype(原型对象指针)包含constructor(构造函数)属性
    constructor(构造函数)属性包含指向原型对象所在函数的指针

graph LR
A[Function构造函数] -- 包含 --> B[prototype]
B -- 包含 --> C[constructorr]
C -- 包含 --> D[指向原型对象所在的构造函数]
D --> A

注意:
    如果使用如下方式给原型赋值,则constructor属性不再指向原型对象躲在的函数,指向Object构造函数。

Person.prototype = {
    name: '哈哈'
}

image.png

继承的几种方式

    注:js主要是通过原型链实现继承,原型链的构建是通过将一个类型的实例赋值给另外一个构造函数的原型实现的

原型链继承
基本代码:

function SuperType () {
    this.property = true
}
SuperType.prototype.getSuperValue = function () {
    return this.property
}
function SubType () {
    this.subproperty = false
}
// 继承了SuperType //
SubType.prototype = new SuperType()
SubType.protype.getSubValue = function () {
    return this.subproperty
}
var instance = new SubType()

实现的本质:
    重写原型对象,用一个新的类型的实例去替代。

image.png     SubType Prototype === SuperType构造函数的实例
注意:
    1.默认的原型 所有的引用类型都默认继承Object,这个继承也是通过原型链实现的。

image.png     2.原型链的问题
        a.对象实例共享所有继承的属性和方法。
        b.创建子类型的实例的时候,不能传递参数。

借用构造函数继承
基本代码:

function SuperType () {
    this.colors = ["red", "blue", "green"]
}
function SubType () {
    // 继承了SuperType
    SuperType.call(this)
    // 只能继承构造函数上的属性
}

实现的本质:
    在子类构造函数的内部调用超类型构造函数,使用aapply()和call() 方法。

注意:
    1.函数复用性不高。
    2.只能继承实例上的属性,原型上的方法不可见。

组合继承(伪经典继承)
基本代码:

function SuperType (name) {
    this.name = name
    this.colors = ["red", "blue", "green"]
}
SuperType.prototype.sayName = function () {
    alert(this.name)
}
function SubType (name, age) {
    // 继承属性
    SuperType.call(this, name)  // 第二次调用SuperType()
    this.age = age
}
//继承方法
SubType.prototype = new SuperType()  // 第一次调用 SuperType()
Subtype.prototype.sayAge = function () {
    alert(this.age)
}

实现思路:
    使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。

注意:
    组合继承避免了原型链和借用构造函数的缺陷融合了他们的优点成为js中最常用的继承方式。

原型式继承
基本代码:

function object (o) {
   function F(){}
   F.prototype = o
   return new F()
}

实现本质:
    object()函数对传入其中的对象执行了一次浅复制。

注意:
    可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制,而复制的副本还可以得到进一步的改造。
    问题还是包含引用类型的属性都会被共享。

寄生式继承
基本代码:

function createAnother (original) {
   var clone = object(original)  // 通过调用函数创建一个新对象
   clone.sayHi = function () {   // 以某种方式来增强这个对象
       alert("hi")
   }
   return clone                  // 返回这个对象
}

实现本质和寄生构造函数还有工厂模式类似。

注意:
    基于某个对象或者某些信息创建一个对象,然后增强对象,最后返回对象,为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问题,可以将这个模式与组合继承一起使用

寄生组合式继承
基本代码:

function inheritPrototype (subType, superType) {
    var prototype = object(superType.prototype)  // 创建对象
    prototype.constructor = subType              // 增强对象
    subType.prototype = prototype                // 指定对象
}

function SuperType (name) {
    this.name = name
    this.colors = {"red", "blue", "green"}
}
SuperType.prototype.sayName = function () {
    alert(this.name)
}
function SubType (name, age) {
    SuperType.call(this, name)
    this.age = age
}
inheritPrototype(SubType, SuperType)

实现本质:
    借用构造函数来继承属性,通过原型链的混成形式来继承方法。

注意:
    高效率只调用了一次构造函数,集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方式。

小结:
    JavaScript主要通过原型链实现继承。
    原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。
    使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性。

最后祝各位大佬学习进步,事业有成!🎆🎆🎆