实现继承是ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的
- 基本思想是通过原型继承多个引用类型的属性和方法
- 构造函数、原型和实例的关系: 构造函数有一个原型对象(prototype),原型对象有一个属性(construtor)指向构造函数,实例有一个__proto__指向构造函数的原型
const F1 = function (){}
// 构造函数F1中的原型对象的constructor执向构造函数F1本身
console.log('F1 === F1.prototype.constructor :>> ', F1 === F1.prototype.constructor);
//true
const f =new F1
// 实例f的__proto__ 指向 构造函数F1的原型对象
console.log('f.__proto__===F1.prototype :>> ', f.__proto__===F1.prototype);
//true
原型链继承的思想就是 :构造函数的原型指向被继承的实例对象的属性和方法,在实例和原型之间构造了一条原型链
function Father(){
this.name="张三"
}
Father.prototype.say= function(){
console.log(`我是${this.name}`);
}
function Son(){
this.name = "张三的儿子"
}
Son.prototype = new Father
Son.prototype.say = function(){
console.log(`我是${this.name}`);
}
const p = new Son
console.log('p :>> ', p); // Son {name: "张三的儿子"}
console.log('p.name :>> ', p.name); // p.name :>> 张三的儿子
console.log('p.__proto__.name :>> ', p.__proto__.name); //p.__proto__.name :>> 张三
p.say() // 我是张三的儿子
p.__proto__.say() // 我是张三
缺点:
- 主要问题出现在原型中包含引用值的时候。原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会定义在原型上的原因。
- 原型链的第二个问题是,子类型在实例化时不能给父类型的构造函数传参。