Javascript的几种继承方式

js继承

1.第一种继承方式(原型链继承)

弊端:

  • 原型链继承当原型中存在引用类型值时,实例可以修改其值。
function Super(){ this.company = '韩创'; this.members = [1,2,3]; } Super.prototype.getName = function(){ console.log('super'+this.company) } function Sub(name,age){ this.name = name; this.age = age; } Sub.prototype = new Super(); //继承后要将构造函数也指向自己 Sub.prototype.constructor = Sub; let sub = new Sub('Bryan',18); console.log(sub.hasOwnProperty('company'));// false console.log(sub.hasOwnProperty('name'));// true console.log(Sub.prototype.isPrototypeOf(sub));// true console.log(Super.prototype.isPrototypeOf(sub));// true /**第一次打印解析 从打印结果来看 1.父类对象 Super 里的 company 属性,虽然继承到了 派生对象 sub 身上,但是不属于它的自身属性 2.父类对象的原型已经等于 派生对象 sub 的原型 */ let p1 = new Sub('p1',18); let p2 = new Sub('p2',20); p1.members.push(5); console.log(p2.members);//[1,2,3,5] /** * 第二次打印解析 * 新建了两个对象 p1 和 p2 ,并且改变 p1 的属性 members * 从打印结果来看 * 虽然改变的p1对象的members,但是p2的members也被改变了 * 所以对于 原型链继承 当原型中存在引用类型值时,实例可以修改其值。 * **/ *

2.第二种继承方式(修改构造函数的this指向)

弊端:

  • 只能继承父对象的实例属性和方法,不能继承父对象原型属性和方法
  • 无法实现函数复用,每个子对象都有父对象实例的副本,性能欠优
function Staff(){ this.company = 'abc' this.members = [1,2,3] } Staff.prototype.getCompany = function(){ console.log(this.company) } function Employee(name,age){ Staff.call(this); this.name = name; this.age = age; } Employee.prototype.say = function(){ console.log(this.name + this.age) } let user1 = new Employee('lily',19) let user2 = new Employee('lucy',20) user1.members.push(4) console.log(user2.members);//[1,2,3] console.log(user1.hasOwnProperty('company'));//true console.log(Staff.prototype.isPrototypeOf(user1));//false console.log(Staff.prototype.isPrototypeOf(user2));//false console.log(user1.getCompany());//user1.getCompany is not a function /** * 存在的问题 * 只能继承父对象的实例属性和方法, * 不能继承父对象原型属性和方法 * 无法实现函数复用,每个子对象都有父对象实例的副本,性能欠优 * **/

3.第三种继承方式(组合继承)

缺点:父类构造函数会被调用 2 次:

  • 第1次是employee.prototype = new staff();
  • 第2次是调用 staff.call(this);
function Animal(){ this.home = 'abc' this.num = [1,2,3] } Animal.prototype.say = function(){ console.log(this.home) } function Dog(name,age) { Animal.call(this); this.name = name; this.age = age; } Dog.prototype = new Animal(); Dog.prototype.constructor = Dog; Dog.prototype.move = function(){ console.log('dog move') } let dog1 = new Dog('xiaohei',1); let dog2 = new Dog('xiaobai',2); dog1.num.push(4) console.log(dog1.num);//[1,2,3,4] console.log(dog2.num)//[1,2,3] dog2.move()//dog move dog2.say()//'abc' console.log(dog1.hasOwnProperty('home'));//true console.log(dog1.hasOwnProperty('num'));//true console.log(Animal.prototype.isPrototypeOf(dog1));//true /**** 优点 可以复用原型上定义的方法 可以保证每个函数有自己的属性,可以解决原型中引用类型值被修改的问题 缺点 staff 会被调用 2 次:第 1 次是employee.prototype = new staff(); 第 2 次是调用 staff.call(this)。 ***/