JS 笔记 继承 原型式 + 寄生式 + 寄生式组合继承

原型式继承: 将父级对象整个赋值给一个空函数的原型,然后new这个函数,将返回值传出去。因此外面的实例可以通过[[proto]]找到构造函数的prototype,沿着原型链找到父级的属性。
基本实现:

function object(father) {
    
    
	function Fun () {
    
    }
	Fun.prototype = father
	return new Fun()
}

let fa = {
    
    
	name: 'father',
	colors: ['red', 'blue', 'green']
}
let son = object(fa)
console.log(son.__proto__.name === fa.name) // true
console.log(son.__proto__.colors === fa.colors) // true
console.log(son.__proto__ === fa) // true

前提是new的实现原理你已经了解过了。

寄生式继承: 寄生式继承算是原型式继承的改造,它的不同之处在于:创造一个原型为父类的子类,然后在子类上手动添加需要的方法和属性,问题自然就是方法不能重用。

以上两种方式都是比较偏向对象,而不是创建函数的情况。

寄生式组合继承: 该方法使用寄生式和组合式实现继承。首先用父类的原型对象创建一个原型副本,然后防止发生子类constructor丢失的问题,手动将原型副本的constructor指到子类,再将这个原型副本赋值给子类的原型,这样成功继承了:父类原型上的方法和属性。
然后我们试图继承父类的属性和内部定义方法(严谨一点吧。。。),就使用组合继承喽,在子类构造函数中调用父类的构造函数,记得this指给实例。

function object(father) {
    
    
	function Fun () {
    
    }
	Fun.prototype = father
	return new Fun()
}

function inheritPrototype(son, father) {
    
    
	let prototype = object(father.prototype)
	prototype.constructor = son
	son.prototype = prototype
}

function Father (name) {
    
    
	this.name = name
	this.colors = ['red', 'blue', 'green']
}

Father.prototype.sayName = function () {
    
    
	console.log(this.name)
} 

function Son (name, age) {
    
    
	Father.call(this, name)
	this.age = age
}

inheritPrototype(Son, Father)

// 一定放在这里 不要往上移 否则被覆盖
Son.prototype.sayAge = function () {
    
    
	console.log(this.age)
}

let instance = new Son('limuzi', 20)


instance.sayName() // limuzi
instance.sayAge() // 20

这样只会在子类创建实例的时候执行一次父类的构造函数,没有在组合继承中那样创建一个父类实例赋值给子类的原型。

我们详细观察一下:object方法中,一个函数的原型被赋值为父类的原型,然后创建了一个实例传了出去,这个实例没有prototype属性,但是有__proto__属性,指向父类的原型,然后这个实例赋值给一个所谓的原型副本,这个原型副本经过加工,覆盖了子类的原型。完成了继承。注意,子类原型方法的定义只能在继承父类之后执行,否则跟没写一样,会在继承的过程中被覆盖。
然后我们创建子类实例,请问子类的原型是谁,子类的原型的原型是谁。
答案1:子类的原型,答案2:父类的原型
也即:
instance.__proto__ === Son.prototype
instance.__proto__.__proto__ === Father.prototype
看这结构,这不就实现了继承吗。
在原型链上讲话要文明哈。

猜你喜欢

转载自blog.csdn.net/weixin_45543674/article/details/121547851