# 继承(一)

需要掌握吗?

  1. 面试题热门问题
  2. js基础重点
  3. 面向对象编程
  4. 主流框架使用广泛 reactjs、vuejs、angularjs、rxjs....

# 什么是js继承?

JavaScript继承是指一个对象通过从另一个对象(通常是父对象或基类)获取属性和方法的过程。在继承中,子类可以重写父类的方法,也可以增加新的方法和属性。这种方式可以使代码更加复用和灵活

# 继承方式有哪些?

1. 原型继承:通过原型链的方式,让新创建的对象可以访问到其他对象的属性和方法

概念: JavaScript中的原型继承是指对象通过原型链来获取属性和方法的过程。每个对象都有一个原型对象,它是一个引用类型,包含了一个指向父对象的引用,通过它可以在父对象中查找属性和方法。如果在当前对象中找不到某个属性或方法,就会沿着原型链向上查找,直到找到为止。

  • eg.

# 1.原型链继承

// 定义一个基础对象 
 var base = { 
     name: 'base', 
     sayHello: function() { 
         console.log('Hello, ' + this.name); 
     } 
 }; 
 
 // 创建一个新对象,它的原型是base 
 var obj = Object.create(base); 
 
 // 在新对象中添加一个属性 
 obj.age = 18; 
 
 // 调用对象的方法,会沿着原型链找到基础对象的方法 
 obj.sayHello(); // 输出:Hello, base 
 
 console.log(obj.age); // 输出:18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • eg2

# 1.1 原型链继承2

  function Animal(name) {
    this.name = name;
    this.hobbies = ['running', 'playing'];
  }

  // 添加一些方法到Animal的原型对象中
  Animal.prototype.eat = function () {
    console.log(this.name + ' is eating.');
  };

  function Cat(name) {
    this.name = name;
  }

  Cat.prototype = new Animal(); //子类型的原型为父类型的一个实例对象

  //原型对象指向自己本身
  Cat.prototype.constructor = Cat;

  // 添加一些方法到Cat对象的原型对象中
  Cat.prototype.meow = function () {
    console.log(this.name + ' is meowing.');
  };

  var cat1 = new Cat('短尾'); //
  var cat2 = new Cat('折耳');
  console.log(cat1.name); //短尾
  console.log(cat2.name); //折耳
  console.log(cat1.eat()); //短尾  is eating.
  console.log(cat2.eat()); //折耳  is eating.
  console.log(cat1.meow()); //短尾 is meowing.
  console.log(cat1 instanceof Cat); //true
  console.log(cat1 instanceof Animal); //true
  cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
  console.log(cat2.hobbies); //['running','playing','eating']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

总结优缺点

  1. 优点

原型继承的优点是可以节省内存,因为新对象只需要引用原型对象,而不需要复制它。

  1. 缺点
  1. 缺点是如果原型对象中的属性被修改,那么所有继承它的对象都会受到影响。
  2. 创建子类实例时,无法向父类构造函数传参

# 2. 构造函数继承

概念: 通过在子类构造函数中调用父类构造函数的方式,让子类对象可以继承父类对象上的属性和方法;

原理:在子类构造函数中调用父类构造函数,可以在子类构造函数中使用call()apply()方法[改变this指向]

 function Animal(name, age) {
    this.name = name;
    this.age = { age };
    this.hobbies = ['running', 'playing'];
  }

  // 添加一些方法到Animal的原型对象中
  Animal.prototype.eat = function () {
    console.log(this.name + ' is eating.');
  };

  function Cat(name, age, color) {
    //通过在构造函数中调用
    Animal.call(this, name, age);
    this.color = color;
  }

  // 添加一些方法到Cat对象的原型对象中
  Cat.prototype.meow = function () {
    console.log(this.name + ' is meowing.');
  };

  var cat1 = new Cat('短尾', 1, 'blue');
  var cat2 = new Cat('折耳', 2, 'yellow');
  console.log(cat1.name); //短尾
  console.log(cat2.name); //折耳
  try {
    console.log(cat1.eat()); // TypeError: cat1.eat is not a function
    console.log(cat2.eat()); // TypeError: cat2.eat is not a function
  } catch (e) {
    console.log(e);
  }
  console.log(cat1.meow()); //短尾 is meowing.
  console.log(cat1 instanceof Cat); //true
  console.log(cat1 instanceof Animal); //false
  cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
  console.log(cat2.hobbies); //['running','playing']
  console.log(cat1.age.age); //1
  console.log(cat2.age.age); //2

  /***
   * 优点:
   * 1.可以在子类实例中直接向父类构造函数传参
   * 2.父类的引用属性不会被子类共享

    缺点:
  *1.无法继承父类原型上的属性与方法
  */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 3. 组合继承

概念: 结合原型继承和构造函数继承,既能继承父类原型上的属性和方法,也能继承父类构造函数中定义的属性和方法

原理: 组合上述两种方法就是组合继承。用原型链实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的继承


  function Animal(name) {
    this.name = name;
    this.hobbies = ['running', 'playing'];
  }

  // 添加一些方法到Animal的原型对象中
  Animal.prototype.eat = function () {
    console.log(this.name + ' is eating.');
  };

  function Cat(name, age) {
    Animal.call(this, name);
    this.age = age;
  }

  Cat.prototype = new Animal(); //子类型的原型为父类型的一个实例对象

  //原型对象指向自己本身
  Cat.prototype.constructor = Cat;

  // 添加一些方法到Cat对象的原型对象中
  Cat.prototype.meow = function () {
    console.log(this.name + ' is meowing.');
  };

  var cat1 = new Cat('短尾'); //
  var cat2 = new Cat('折耳');
  console.log(cat1.name); //短尾
  console.log(cat2.name); //折耳
  console.log(cat1.eat()); //短尾  is eating.
  console.log(cat2.eat()); //折耳  is eating.
  console.log(cat1.meow()); //短尾 is meowing.
  console.log(cat1 instanceof Cat); //true
  console.log(cat1 instanceof Animal); //true
  cat1.hobbies.push('eating'); // 更改一个子类的引用属性,其他子类也会受影响
  console.log(cat1.hobbies); // ['running', 'playing', 'eating']
  console.log(cat2.hobbies); // ['running', 'playing']

  /**
   * 优点:
   *  1.可以在子类实例中直接向父类构造函数传参
   *  2. 通过子类实例可以直接访问父类原型链和实例的成员
   * 缺点:
   *  1. 调用了两次supertype构造函数,一次在赋值Cat的原型时,一次在实例化子类时call调用,这次调用会屏蔽原型中的两个同名属性。
   */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

TIP

最后欢迎大家留言交流

最后更新时间: 5/15/2023, 6:25:18 PM