JS--继承,多种继承方式
1. 原型链继承
// -----原型链继承-----
function Parent(){
this.name = ["原型链继承"];
}
// 原型上挂载方法
Parent.prototype.getName = function(){
console.log(this.name);
}
function Chind(){
}
// 原型链继承
Chind.prototype = new Parent();
Chind.prototype.constructor = Chind;
let myChild1 = new Chind();
let myChild2 = new Chind();
myChild1.name[0] = "咕咕咕";
console.log(myChild1.name); //["咕咕咕"]
myChild2.getName(); //["咕咕咕"]
子实例可继承:子构造函数的属性、父类构造函数的属性,父类原型上的属性。(子类实例不会继承父类实例的属性!)
缺点:在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子实例的时候不能向父类的构造函数传递参数。
2. 构造函数继承
// ----构造方法继承-----
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
// 原型上挂载方法
Parent.prototype.getName = function () {
console.log(this.name);
}
function Chind() {
Parent.call(this, "fct");
}
let myChild1 = new Chind();
let myChild2 = new Chind();
myChild1.name = "咕咕咕";
myChild1.colors.push("green");
console.log(myChild1.name); //"咕咕咕"
console.log(myChild1.colors); // ['red', 'blue', 'green']
console.log(myChild2.name); // fct
console.log(myChild2.colors); // ['red', 'blue']
myChild2.getName(); //报错,构造方法继承不能继承父类原型上的属性和方法
通过在子类型的函数中调用父类型的构造函数来实现的。
可继承:只能继承父类构造函数的属性。
这一种方法解决了不能向父类型传递参数的缺点,但是它存在的一个问题就是无法实现构造函数的复用(每次用每次都要重新调用),并且父类型原型定义的方法,子类型也没有办法访问到。每个新实例都有父类构造函数的副本,臃肿。
3. 组合继承(常用)
function Parent(name){
this.name = name;
}
Parent.prototype.getName = function (){
console.log(this.name);
}
function Child(){
Parent.call(this,"小桃子");// 第二次调用Parent
}
Child.prototype = new Parent(); // 第一次调用Parent
Child.prototype.constructor = Child;
let myChild1 = new Child();
let myChild2 = new Child();
myChild1.name = "咕咕咕";
console.log(myChild1.name); // 咕咕咕
console.log(myChild2.name); // 小桃子
myChild2.getName(); // 小桃子
组合继承是将原型链和借用构造函数组合起来使用的一种方式。可继承父类原型上的属性、可传参、可复用。
这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以父类型的实例来作为子类型的原型,缺点:所以调用了两次父类的构造函数,耗内存。
4. 原型式继承
function CreateObj(o) {
function F() { }
F.prototype = o;
return new F();
}
var person = {
name: 'xiaopao',
friend: ['daisy', 'kelly']
}
var person1 = CreateObj(person);
var person2 = CreateObj(person);
person1.name = 'person1';
console.log(person1.name); // person1
console.log(person2.name); // xiaopao
person1.friend.push('taylor');
console.log(person1.friend); // ["daisy", "kelly", "taylor"]
console.log(person2.friend); // ["daisy", "kelly", "taylor"]
console.log(person); // {name: "xiaopao", friend: Array(3)}
person1.friend = ['lulu'];
console.log(person1.friend); // ["lulu"]
console.log(person2.friend); // ["daisy", "kelly", "taylor"]
console.log(person.friend); // ["daisy", "kelly", "taylor"]
// 注意: 这里修改了person1.name的值,person2.name的值并未改变,并不是因为person1和person2有独立的name值,而是person1.name='person1'是给person1添加了name值,并非修改了原型上的name值
原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的
Object.create()
方法就是原型式继承的实现。缺点:和原型链继承类似,所有实例都会继承原型上的属性。无法实现复用。(新实例属性都是后面添加的)
5.寄生式继承
// ----寄生式继承-----
function content(obj) { // 原型式继承
function Fn() { }
Fn.prototype = obj;
Fn.prototype.constructor = Fn;
return new Fn();
}
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function () {
console.log(this.name);
}
let sup = new Parent();
function subObject(obj) { // 扩展
let sub = content(obj);
sub.name = "fct";
return sub;
}
let sup2 = subObject(sup);
console.log(sup2.name); // fct
sup2.getName();// fct
寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。就是给原型式继承外面套了个壳子。这个扩展的过程就可以理解是一种继承。
优点:没有创建自定义类型,因为只是套了个壳子返回这个对象,这个函数顺理成章就成了创建的新对象。
缺点:是没有用到原型,无法实现函数的复用。
6. 寄生式组合继承
// ----寄生式组合继承-----
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function () {
console.log(this.name);
}
function Child() {
Parent.call(this, "卿云");
}
Child.prototype = Object.create(Parent.prototype);//寄生
Child.prototype.constructor = Child;
Child.prototype.print = function () {
console.log("我是child");
}
let myChild1 = new Child();
let myChild2 = new Child();
let myParent = new Parent();
myChild1.name = "咕咕咕";
console.log(myChild1.name); // 咕咕咕
console.log(myChild2.name); // 卿云
myChild2.getName(); // 卿云
myParent.getName(); //undefined
myChild1.print(); //我是child
myParent.print(); //报错:myParent.print is not a function
组合继承的缺点就是使用父类型的实例做为子类型的原型,调用多次构造函数。
寄生式组合继承的方式是使用父类型的原型的副本来作为子类型的原型,这样就可避免多次调用父级构造函数。修复了组合继承的问题。
寄生:在函数内部返回对象然后调用
组合:函数原型等于另一个实例,函数内部调用另一个构造函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步