JavaScript实现继承的几种方法

你的名字 2023-03-13 02:11 137阅读 0赞

JavaScript实现继承的几种方法

原型链继承

prototype原型相当于一个对象的父类,所有实例都会共享原型上的属性和方法。
constructor构造函数相当于一个创建对象的函数,同时也是对象实例的标识符。bigApple,smallApple使用Apple作为构造函数,初始化就会使用Apple方法;同时这两个实例对象也属于Apple类。

  1. // 原型链继承
  2. // fruit水果类
  3. function Fruit() {
  4. this.name = "水果";
  5. this.color = ["green"];
  6. }
  7. Fruit.prototype.sayName = function () {
  8. console.log(this.name);
  9. }
  10. function Apple() { };
  11. // 继承
  12. Apple.prototype = new Fruit(); // 设置对象原型为Fruit
  13. Apple.prototype.constructor = Apple; // 将构造函数改为Apple
  14. var bigApple = new Apple();
  15. var smallApple = new Apple();
  16. bigApple.sayName(); // 水果
  17. console.log(smallApple.name); // 水果

原理:重写子类的原型对象,将父类的方法和属性继承到子类上
具体原型链如下:
format_png
对比没有继承前和继承后的结果

缺点:

1.继承的Fruit实例会被所有Apple实例(bigApple,smallApple)所共享,如果原型上有引用类型(数组,对象),一旦修改,所有Apple实例的原型都会修改

  1. bigApple.color.push("red");
  2. console.log(bigApple.color); // ["green", "red"]
  3. console.log(smallApple.color); // ["green", "red"]

2.创建子类实例(smallApple,bigApple)时,不能向父类传参。也就是说,子类初始化不能定制父类的属性和方法,父类对象在继承时,已经创建。每个子类实例的原型都一样。

借用构造函数继承

在子类构造函数内容调用父内构造函数方法

  1. // 借用构造函数继承
  2. function Fruit(name) {
  3. this.name = name;
  4. this.color = ["green"];
  5. }
  6. Fruit.prototype.sayName = function () {
  7. console.log(this.name);
  8. }
  9. function Apple(name) {
  10. Fruit.call(this,name);
  11. };
  12. const bigApple = new Apple('big');
  13. const smallApple = new Apple('small');
  14. bigApple.color.push("red");
  15. console.log(bigApple.color); // ["green", "red"]
  16. console.log(smallApple.color); // ["green"]
  17. console.log(bigApple.sayName); //undefined

修改Fruit构造函数的this指向,将其指向Apple的实例对象,给Apple实例初始化
原理:改变父类函数的this指向
优点:实例的属性不会共享,子类构造函数可以传递参数给父类
缺点:父类定义的方法不能被子类继承下来

组合继承(终点)

为了解决上述,父类的方法不能被继承下来的缺点

  1. // 借用构造函数继承
  2. function Fruit(name) {
  3. this.name = name;
  4. this.color = ["green"];
  5. }
  6. Fruit.prototype.sayName = function () {
  7. console.log(this.name);
  8. }
  9. function Apple(name) {
  10. Fruit.call(this,name);
  11. };
  12. Apple.prototype = new Fruit();
  13. Apple.prototype.constructor = Apple;
  14. const bigApple = new Apple('big');
  15. const smallApple = new Apple('small');
  16. bigApple.color.push("red");
  17. console.log(bigApple.color); // ["green", "red"]
  18. console.log(smallApple.color); // ["green"]
  19. bigApple.sayName(); //big

只要子类原型对象设置为父类实例时,子类就可以继承父类原型上的方法。
注意:修改子类原型时,必须将原型上构造函数的指向子类对象。否则实例化子类对象时,会用父类的Fruit方法去构造对象;而不是Apple方法。
优点:解决了子类继承父类方法的问题
缺点:调用两次父类构造函数方法(Fruit.call(this,name);new Fruit()

寄生组合式继承(重点)

针对上面连词使用父类构造函数方法改进
可以使用Object.create()方法替代

  1. function Fruit(name) {
  2. this.name = name;
  3. this.color = ["green"];
  4. }
  5. Fruit.prototype.sayName = function () {
  6. console.log(this.name);
  7. }
  8. function Apple(name) {
  9. Fruit.call(this,name);
  10. };
  11. Apple.prototype = Object.create(Fruit.prototype);
  12. Apple.prototype.constructor = Apple;
  13. const bigApple = new Apple('big');
  14. const smallApple = new Apple('small');

Object.create()方法,创建一个新对象,将传入的对象Fruit.prototype作为父类
原理:将子类的原型对象 指向 父类的原型对象

多重继承

理论上js不允许一个对象继承多个对象
Object.assign(); 可以将参数二对象上的属性和方法 复制给 参数一对象

  1. function Fruit(name) {
  2. this.name = name;
  3. this.color = ["green"];
  4. }
  5. Fruit.prototype.sayName = function () {
  6. console.log(this.name);
  7. }
  8. function Plant(){
  9. this.desc = "植物类"
  10. }
  11. Plant.prototype.sayHi = function () {
  12. console.log("hi");
  13. }
  14. function Apple(name) {
  15. Fruit.call(this,name);
  16. Plant.call(this);
  17. };
  18. Apple.prototype = Object.create(Fruit.prototype);
  19. // 将植物类原型上的属性和方法复制给Apple原型
  20. Object.assign(Apple.prototype,Plant.prototype);
  21. Apple.prototype.constructor = Apple;
  22. const bigApple = new Apple('big');
  23. bigApple.sayName(); // big
  24. bigApple.sayHi(); // hi

发表评论

表情:
评论列表 (有 0 条评论,137人围观)

还没有评论,来说两句吧...

相关阅读