js继承的几种方式

js想要继承,先创建一个父类。

function Person(name,age){
     this.name = name;  ----属性
     this.age = age;      
     this.sayThing = function(){  ---实例方法
    console.log('say something');
   } }

1、原型链继承

原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的。

实例对象中有__proto__,是对象,叫原型,不是标准的属性,浏览器使用,并且有的游览器不支持。
构造函数中有prototype属性,也是对象,叫原型。

注意 原型中的方法是可以互相访问的。

原型的简单语法:

1、利用原型共享数据

Person.prototype.height = '180cm';
Person.prototype.eat=function(){
   console.log('吃早餐');  
  this.play(); }

Person.prototype.play = function(){
  console.log('打球');
}

var person1 = new Person('张三',20);

2、写法二:直接这么赋值,会导致constructor构造器属性消失,需要手动修改构造器指向。

function Student(name,age,sex){
   this.name=name;
   this.age=age;
   this.sex=sex;
}
Student.prototype={
   constructor:Student, height:
"188", weight:"55kg", study:function(){ console.log("好好学习i") } } var stu=new Student("小红",20,"男") console.dir(stu)

构造函数和实例对象和原型对象之间的关系

1、构造函数可以实例化对象
2、构造函数中有一个属性叫prototype,是构造函数的原型对象
3、构造函数的原型对象(prototype)中有一个constructor 构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数
4、实例对象的原型对象(__proto__) 指向的是该构造函数的原型对象(prototype)
5、构造函数的原型对象(prototype)中的方法是可以被实例对象直接访问 

更改原型链指向:

  function Person(age) {
    this.age = age;
  }
  Person.prototype.eat = function () {
    console.log('吃萝卜');
  }

  function Student(name) {
    this.name = name;
  }
  Student.prototype.play = function () {
    console.log('打篮球');
  }

  Student.prototype = new Person(19);
  var stu = new Student('张三');
console.log('stu.age=', stu.age); --- 19 console.log('stu.name=', stu.name);  ----- 张三 console.log(stu.eat);  ----- function(){} console.log(stu.play); ----- undefined

原型链是可以更改指向的,定义的构造函数 Student, 更改原型链指向Person,则指向了Person的构造函数。Person的 eat 方法可以得到,此时的 play 方法 因为指向改变了,所以找不到为undefined。但是构造函数Person 和 Student 里面的独立属性是都继承的。

3、构造函数继承

// 定义一个动物类
function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

function
Cat(name){ Animal.call(this);
 Person.call(this); ------- 可以引用多个父类构造函数
this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true

特点:

  1. 子类实例共享父类引用属性。
  2. 创建子类实例时,可以向父类传递参数
  3. 可以实现多继承(call多个父类对象)

缺点:

  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
  3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

4、组合继承(组合原型链继承和借用构造函数继承)

  function Person(name) {
    this.name = name;
    this.sum = function () {
      return 'hello';
    }
  }

  function SubType(name) {
    Person.call(this, name)
  }
SubType.prototype = new Person(); var sub = new SubType('李四'); console.log('sub.name=', sub.name); --- 李四 console.log('sub.sum =', sub.sum()); ---- hello

重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
   2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数Person()(耗内存),子类的构造函数会代替原型上的那个父类构造函数。

  

原文地址:https://www.cnblogs.com/liumcb/p/13632043.html