JS原型、原型链、继承

举报
猫先生c 发表于 2022/11/20 22:15:18 2022/11/20
【摘要】 实例对象p不能调用构造函数Parent的方法和属性,只能调用Parent的原型对象的方法和属性
function Parent() {
    this.name = 'red';
    this.eat = function () {
        console.log('走这里了吗')
    }
}
Parent.prototype.start = function () {
    console.log(this.name)
}
function Children() {}

Children的原型对象=Parent的原型对象

缺点:
实例对象p指向Parent;
实例对象p不能调用构造函数Parent的方法和属性,只能调用Parent的原型对象的方法和属性

//仅继承了Parent原型对象上的方法和属性
Children.prototype = Parent.prototype
let p = new Children();
console.log(p.name)//undefined
console.log(p.eat)//undefined
console.log(p.start)
//ƒ () {
//  console.log(this.name);
//}
console.log(p.constructor)
//ƒ Parent() {
//  this.name = 'red';
//  this.eat = function () {
//    console.log('走这里了吗');
//  };
}

Children.prototype = new Parent()

缺点:
实例对象p指向Parent

Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
let p = new Children();
console.log(p)//Children {}
console.log(p.name)//red
console.log(p.start)
//ƒ () {
//   console.log(this.name);
// }
console.log(p.eat)
// ƒ () {
//     console.log('走这里了吗');
//   }
console.log(p.constructor)
// ƒ Parent() {
//   this.name = 'red';
//   this.eat = function () {
//     console.log('走这里了吗');
//   };
// }

Children.prototype = new Parent()

Children.prototype.constructor = Children;

Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
Children.prototype.constructor = Children;
let p = new Children();
console.log(p.constructor);
// ƒ Children() {}

缺点

  1. 如果父构造函数中含有引用类型的属性,当某个实例改变了该引用类型的属性,则所有实例共享该实例(基本数据类型不会)
  2. 创建Children实例无法传参
function Parent() {
    this.name = 'red';
    this.arr = [1, 2, 3];
    this.eat = function () {
        console.log('走这里了吗')
    }
}
Parent.prototype.start = function () {
    console.log(this.name)
}
function Children() {
}
Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children()
let p2 = new Children()
console.log(p1.arr)
p1.name = 'blue';
p1.arr.pop();
console.log(p1.name)//blue
console.log(p2.name)//red
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[2,3]

解决缺点一(构造函数继承)

某实例改变父构造函数中引用类型属性的值,所有实例共享修改后的引用类型的属性值

function Parent() {
    this.arr = [1, 2, 3];
}
Parent.prototype.start = function () {
}
function Children() {
    Parent.apply(this)
    //相当于执行了 this.arr = [1, 2, 3];

let p1 = new Children()
let p2 = new Children()
p1.arr.pop()
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[1,2,3]

解决缺点二(构造函数继承)

生成实例时不能传参的问题

function Parent(color,name) {
    this.color = color;
    this.name = name;
    this.arr = [1, 2, 3];
    this.eat = function () {
        console.log('走这里了吗')
    }
}
Parent.prototype.start = function () {
    // console.log(this.name,'prototype')
}
function Children() {
    console.log(arguments,'arguments')
    //call传参为多个数值
    //apply传值为数组
    // Parent.apply(this,arguments)
    Parent.call(this,...arguments)
}
let p1 = new Children()
let p2 = new Children('red','zhangsan')
console.log(p2.color)//red
console.log(p2.name)//zhangsan
console.log(p1.eat===p2.eat)//false

再次出现的问题

我们每次生成实例的时候都会重新生成构造函数的属性和方法

function Children() {
    //call传参为多个数值
    //apply传值为数组
    // Parent.apply(this,arguments)
    Parent.call(this,...arguments)
}

解决重新生成实例时生成构造函数的属性和方法(组合继承:原型链继承+构造函数继承)

  • 原型链继承:
  1. 实例改变引用类型的属性,所有实例共享
  2. 不能传参。
  • 构造函数继承:
  1. 解决了以上原型链的两个问题
  2. 但是又出现了新的问题,每次生成实例都会重新生成一份构造函数的属性和方法
function Parent(color,name) {
    this.color = color;
    this.name = name;
    this.arr = [1, 2, 3];
    this.eat = function () {
        console.log('走这里了吗')
    }
}
Parent.prototype.start = function () {
    console.log(this.name,'prototype')
}
function Children() {
    console.log(arguments,'arguments')
    //call传参为多个数值
    //apply传值为数组
    // Parent.apply(this,arguments)
    // Parent.call(this,...arguments)
   //  Parent.apply(this,Array.prototype.slice.call(arguments, 1))  
   Parent.apply(this,[].slice.call(arguments, 1))  
}
Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children(1,'red','zhangsan')
let p2 = new Children(2,'red','zhangsan')
console.log(p1.eat()) 
console.log(p2.eat())
console.log(p1.start===p2.start) //true

解决了三个痛点:

  1. 不可传参数
  2. 多占内存
  3. 改变引用类型属性,所有实例共享

寄生组合继承(再次出现问题,构造函数调用两次)

1. Parent.call(this,...arguments)
...
2.Children.prototype = new Parent();
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。