关于javascript实现继承的核心机制

时间:2022-12-28 10:00:35

一、继承的概念:

  继承的概念可以分为两个层面,一是子类可以拥有父类的一部分或全部属性或方法,二个子类还可以有自己的一些属性和方法。

二、继承实现的机制

  在javascript中实现继承的核心机制就是 -- 原型链

  既然的这里提到原型链,就不得不说一下javascript中的原型链是怎么回事。

  一个构造函数由构造函数本身和构造函数的原型对象两个部分组成(双对象法则) ,也就是构造函数有一个隐藏的属性__proto__,指向构造函数的原型对象。当构造函数被实例化时,把构造函数中的所有属性和方法拷贝到实例当中,同时,这个__proto__属性也会被拷贝,当访问实例对象当中的属性或方法时,会先从实例本身找,如果找到了,就会使用实例中的这个属性或方法;如果没有找到,就会通过__proto__属性中保存的地址找到原型对象,再从原型对象里找这个属性或方法。

  当给一个实例对象设置属性值时,会在实例对象中找有没有这个属性,如果找到,就直接把值赋给这个属性;如果没有的话,不会再去原型对象中找该属性,因为javascript语言是一种动态语言,这时会直接给这个实例对象添加一个新的属性,即使原型对象中有这个属性,也不会改变原型对象中的这个值。

  当实例对象中和原型对象中有一个同名的属性和方法时,此时只能访问到实例对象中的属性或方法(屏蔽法则),如果一定要访问,可以delete掉实例中的属性或方法,或都直接加上__proto__属性访问。

  以上就是原型链的核心机制,属性搜索机制。

  javascript语言在最初的时候并不是一门面向对象的语言,后期由于使用javascript语言的人越来截止多,再加上面向对象编程的种种好处,javascript利用原型链机制,间接的实现了继承。

三、实现继承的几种方式

  1、借用构造函数实现继承

 1 //定义一个父类构造函数
 2 function Person(name,age,gender) {
 3     this.name = name;
 4     this.age = age;
 5     this.gender = gender;
 6 }
 7 Person.prototype = {
 8     run: function() {
 9         console.log(this.name + " is running");
10     }
11 }
12 //定义子类构造函数
13 function Student (name,age,gender,id,grade) {
14     //使用apply方法借用父类构造函数,实现继承
15     Person.apply(this,arguments);
16     this.id = id;
17     this.grade = grade;
18 }
19 Student.prototye = {}

  以上代码通过使用apply方法借用父类构造函数实现继承,这种方法有一个缺点就是只能继承构造函数里的属性或方法,无法继承到原型对象里定义的方法。

  2、原型链继承

 1 // 定义父类构造函数
 2 function Person(name,age,gender) {
 3     this.name = name;
 4     this.age = age;
 5     this.gender = gender;
 6 }
 7 //父类原型对象
 8 Person.prototype = {
 9     run: function() {
10         console.log(this.name + " is running");
11     }
12 }
13 //定义子类构造函数
14 function Student (name,age,gender,id,grade) {
15     this.id = id;
16     this.grade = grade;
17 }
18 //手动将子类构造函数,指向父类构造函数的一个实例,实现继承 
19 Student.prototype = new Person();

  以上代码通过让子类的原型对象等于父类的一个实例,以实现继承,这种方法可以完全继承父类的全部方法和属性,但是不能通过传参的形式实例化对象,所有就有了第三种实现继承的方式 ,组合继承

3、组合继承

  组合继承是同时使用了上面两种方法来实现继承,代码如下

 1  // 定义父类构造函数
 2 function Person(name,age,gender) {
 3     this.name = name;
 4     this.age = age;
 5     this.gender = gender;
 6 }
 7 //父类原型对象
 8 Person.prototype = {
 9     run: function() {
10         console.log(this.name + " is running");
11     }
12 }
13  //定义子类构造函数
14 function Student (name,age,gender,id,grade) {
15   //使用apply方法借用父类构造函数,实现继承
16     Person.apply(this, arguments);
17     this.id = id;
18     this.grade = grade;
19 }
20  //手动将子类构造函数,指向父类构造函数的一个实例,实现继承
21 Student.prototype = new Person();

  组合继承完美实现了继承父类的所有方法和属性,此时如果再想给子类的原型对象添加一些方法的话,只能使用.语法的形式(或者使用[]),还有一个缺点是使用子类实例化对象时,会在实例对象和原型对象中重复定义父类构造函数中的属性或方法。

 4、使用第三方框架实现继承

  可以实现继承的第三方框架有很多,实现方式也都大同小异,可以参照各框架的源码或API,这里不再赘述。