JavaScript之原型链与原型链继承

原型链

定义:每个实例对象(object)都有一个私有属性(称之为 __proto__ )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为 null

  prototype:(原型对象)函数独有的属性

  constructor:(构造函数)每个函数都有一个原型对象,该原型对象有一个 constructor 属性,指向创建对象的函数本身。

  __proto__:(原型)对象的私有属性(在 JavaScript 中一切皆对象)

原型链图解:

 

继承方式(es5):

方式1:基于原型链继承

弊端:当原型中存在引用类型的值时,实例能够修改这个引用类型的值(不够安全)

// 新建父类 Base
function Base() {
    this.name = 'tomni'
    // jobInfo为一个引用类型
    this.jobInfo = {
        jobName: 'job1',
        price: 1000
    }
}

// 在原型上添加 getName 方法
Base.prototype.getName = function() {
    return this.name
}

// 创建子类
function Sub() {
    this.age = 18
}
const newBase = new Base()
/**
 * 原型链继承
 *  1. 将 Sub 的原型对象指向 newBase
 *  2. 将 Sub 原型对象的构造函数执行本身(Sub)
*/
Sub.prototype = newBase
Sub.prototype.constructor = Sub

/** *** 原型链继承的问题 *** */
const newSub = new Sub()
const newSub2 = new Sub()
// 修改实例 newSub.jobInfo 中的 jobName
newSub.jobInfo.jobName = 'job22'
// 打印 newSub2.jobInfo.jobName
// 会发现 newSub2.jobInfo 这个对象也被修改了
console.log(newSub2.jobInfo) // -> job22

方式2:更改函数 this 指向实现继承

 弊端:无法继承父对象中的原型对象(prototype)中的属性和方法,每次实例化都需要执行一遍父对象,性能欠佳

// 新建父类 Base
function Base() {
    this.name = 'tomni'
    // jobInfo为一个引用类型
    this.jobInfo = {
        jobName: 'job1',
        price: 1000
    }
}

// 在原型上添加 getName 方法
Base.prototype.getName = function() {
    return this.name
}

// 创建子类
function Sub() {
// 使用当前上下文 this 执行 Base 函数(每次对 Sub 实例化都需要执行) Base.call(this) this.age = 18 } const newSub = new Sub() // 改变this指向的方式实现继承,无法继承其原型对象(prototype)中的方法与属性 // Uncaught TypeError: newSub.getName is not a function console.log(newSub.getName())

方式3:组合式继承

 弊端:每次创建子实例,父对象原型对象中的构造函数会被执行两次

// 新建父类 Base
function Base() {
    this.name = 'tomni'
    // jobInfo为一个引用类型
    this.jobInfo = {
        jobName: 'job1',
        price: 1000
    }

    // 会执行两次(因为创建 Sub 实例的过程中,Base.prototype.constructor 被执行了两次)
    console.log('constructor')
}

// 在原型上添加 getName 方法
Base.prototype.getName = function() {
    return this.name
}

// 创建子类
function Sub() {
    // 修改 this 指向实现继承
    Base.call(this)
    this.age = 18
}

// 原型链继承
Sub.prototype = new Base()
Sub.prototype.constructor = Sub

const newSub = new Sub()
const newSub2 = new Sub()

// 父对象中 引用类型  被影响的问题得以解决
newSub.jobInfo.jobName = '1111'
console.log(newSub2.jobInfo.jobName)

// 无法继承 父对象原型对象中的属性和方法 问题得以解决
console.log(newSub.getName()) // -> tomni

    

posted @ 2019-11-10 02:58  C+V-Engineer  阅读(130)  评论(0编辑  收藏  举报