JS面向对象继承创建和使用

以下只列举三种常见方式
1:拷贝继承
首先我们要知道子类究竟要继承父类的哪些特征?
答案是属性和方法。继承父类的属性。我们采用call通过对象冒充的方式。让子类具有父类的属性。那么接下来我们所说的三种方式,都是针对父类的方法。更直接一点,就是父类prototype上的方法。
那么我们就好理解。所谓拷贝继承。就是通过拷贝的方式,把父类prototype上的方法统统赋值给 子类的prototype
接下来我们看一个简单的例子。
function Person(name,age){
   this.name=name;
   this.age=age;
}
Person.prototype.eat=function(){
  console.log("eat")
}

function Student(name,age,className){
  Person.call(this,age,name)
  this.className=className
}

for(var attr in Person.prototype){
      Student.prototype[attr]=Person.prototype[attr]
}

var s1=new Student();
console.log(s1.constructor)
s1.eat();   --》eat

2 类式继承
所谓类式继承。也就是通过一个父类新建一个实例类,由于该实例是由父类new出来的,所以就具有了所有父类的属性和方法。接下来我们只需要把子类的prototype指向这个实例类。那么子类的原型上就具有了父类的方法。
function Person(name,age){
  this.name=name;
  this.age=age
}

Person.prototype.eat=function(){
  console.log("eat")
}
var p=new Person();   //所谓类式继承,就是通过父类创建一个类的实例,把子类的原型链等于这个类的实例,实现继承

function Student(name,age,className){
    Person.call(this,name,age)
    this.className="two"
}

Student.prototype=p;
var s1=new Student("sean",20);
s1.eat()  --》eat
这个有一个问题:Student.prototype=p;本质是对象的引用。所以当我们修改Student.prototype.eat里函数的内容时,父类的方法也发生了变化。这时候我们只需要通过Student.constructor=Student。修正它的构造函数指向,这样就可以避免这个问题。constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中。这个 constructor 保存了指向 function 的一个引用。也就是说constructor 的值实际上是其构造函数。

3 原型继承
所谓原型继承:其实和类式继承很相识。只不过类式继承是通过把一个父对象的实例等于子类的原型prototype属性来实现,而
原型继承则是通过一个空函数来实现,也就是把父类的原型赋值给空函数,再把该空函数返回的一个实例对象等于子类的原型prototype属性。有点绕。
基本上分3步骤:

(1)var F = function(){};
(2)F.prototype = Parent.prototype;
(3)Child.prototype = new F();

还是通过上面的例子:
function Person(name,age){
  this.name=name;
  this.age=age
}

Person.prototype.eat=function(){
  console.log("eat")
}

function Student(name,age,className){
    Person.call(this,name,age)
    this.className="two"
}


function fn(){}
fn.prototype=Person.prototype;
Student.prototype=new fn();

var s1=new Student("sean",20);
s1.eat()
原型继承还是要相比类式继承的优点在于通过空函数占用内存较小。但是它还是存在子类constructor 指向的构造函数出错的问题。所以还是要手动修正。加上Student.constructor =constructor 
function Person(name,age){
  this.name=name;
  this.age=age
}

Person.prototype.eat=function(){
  console.log("eat")
}

function Student(name,age,className){
    Person.call(this,name,age)
    this.className="two"
}


function fn(){}
fn.prototype=Person.prototype;
Student.prototype=new fn();
Student.constructor =Student
var s1=new Student("sean",20);
s1.eat()  
console.log(Student.constructor)   --->function Student(){ ..... }

es6中定义了类的概念。不需要我们每次去写一个founction FN()这样一个构造函数。而通过class关键字去申明一个类。写法简洁。但是这只是一个语法糖,写法简单了,内部还是采用es5 构造函数去定义的。es5中我们的属性都通过传参到构造函数中,es6中则把属性通过参数的形式写在了一个叫constructor的构造函数中。方法在es5中通过prototype上定义函数的形式来完成。而es6中则直接简写成类似这样的形式
eat(){
     console.log("eat")
   }

//定义一个person类
class Person{

   constructor(name,age){
      this.name=name;
      this.age=age
   }

   eat(){
     console.log("eat")
   }
}
注意:
每一个类都会有一个默认的固定的方法,这个方法名字 constructor
 constructor构造函数:对类进行初始化的,当我们通过new的方式调用该类的时候,默认执行的函数就是这个 constructor 函数,所以 constructor 其实就是通过类创建对象的时候的初始化函数,我们会通过这个函数对产生的对象进行一些初始化的工作,比如属性初始化
注意:class中的方法,其实就是一个函数,但是函数不能有function

同样上面的例子:
class Person{
   constructor(name,age){
      this.name=name;
      this.age=age
   }

   eat(){
     console.log("eat")
   }
}

class Student extends Person{

  constructor(name,age,className){
    super(name,age)                      //super关键词用来继承父类的属性,相当于在es5中call的作用
    this.className=className     //子类新的属性
  }

  test(){                              
      console.log("考试")
  }

}

var p=new Person()
var s=new Student("sean","24")
console.log(s.name)    ----》sean

ES6中类的出现。简化了写法。让我们不必再去更多的考虑写法。而是关注内容本身

原文链接
https://blog.csdn.net/baidu_41601048/article/details/78997469

猜你喜欢

转载自blog.csdn.net/HaiJun_Aion/article/details/88778449