js继承

1.原型链通过子代的原型去new 祖先的构造函数。去继承。

优点:

缺点:

  • 创建子类实例时,不能向父类的构造函数中传递参数
  • 父类中所有引用类型的属性会被所有子类实例共享,也就说一个子类实例修改了父类中的某个引用类型的属性时,其他子类实例也会受到影响

 

例子: a.pototype=new b(); // a,b都是构造函数,a继承b

下面看看修改原型链上面原始值与引用值的区别:

// 原始值
Professor.prototype.tSkill = "java"; function Professor() { } var professor = new Professor(); Teacher.prototype = professor; function Teacher() { this.mSkill = "js"; this.students = 500; this.objs = { a: 1, b: 2, }; } var teacher = new Teacher(); Student.prototype = teacher; function Student() { this.pSkill = "html" } var student = new Student(); student.students++;
// 修改原始值,原型祖先不会更改,会在自己本身新增一个属性
// student.students=student.students+1;
// 右边student.students可以通过原型链在Teacher获取到;
// 左边的这个,可以看成对象新增属性,没有这个属性,就得新增这个属性

// 引用值
列子:

student.objs.a = 11;
student.objs.c = 3;
// 修改对象值,会直接修改原型链祖先的值,不建议这样操作;十分不规范 console.log(student);
console.log(teacher);

 

不是所有的对象都继承与Object.prototype

Object.create(null);

 

2.借用构造函数继承(经典继承)

优点:

  • 在子类构造函数中可以向父类的构造函数中传递参数
  • 避免了父类中的引用类型属性在子类中共享的问题

缺点:

  • 父类原型对象上的方法子类继承不到
function Parent(age) {
  this.name = "parent";
  this.age = age;
  this.hobby = ["sing", "rap"];
}
Parent.prototype.sayHi = function() {
  console.log("Hi");
};
function Child(age) {
  Parent.call(this, age);
  this.type = "child";
}
let child1 = new Child(15);
let child2 = new Child(15);

child1.hobby.push("basketball");
console.log(child1.name); // parent
console.log(child1.age); // 15
console.log(child1.type); // child
console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ]
console.log(child2.hobby); // [ 'sing', 'rap' ]
child1.sayHi(); // 报错,child1.sayHi is not a function

 

3.组合继承

优点:

  • 在子类构造函数中可以向父类的构造函数中传递参数
  • 避免了父类中的引用类型属性在子类中共享的问题
  • 父类原型对象上的方法子类也可以继承到

缺点:

  • 父类构造函数被调用了两次
function Parent(age) {
  this.name = "parent";
  this.age = age;
  this.hobby = ["sing", "rap"];
}
Parent.prototype.sayHi = function() {
  console.log("Hi");
};
function Child(age) {
  Parent.call(this, age); // 第二次调用Parent
  this.type = "child";
}

Child.prototype = new Parent(); // 第一次调用Parent
Child.prototype.constructor = Child;

let child1 = new Child(15);
let child2 = new Child(15);

child1.hobby.push("basketball");
console.log(child1.name); // parent
console.log(child1.age); // 15
console.log(child1.type); // child
console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ]
console.log(child2.hobby); // [ 'sing', 'rap' ]
child1.sayHi(); // Hi

 

4.组合式继承优化1

优点:

  • 在子类构造函数中可以向父类的构造函数中传递参数
  • 避免了父类中的引用类型属性在子类中共享的问题
  • 父类原型对象上的方法子类也可以继承到
  • 父类构造函数也只调用了一次

缺点:

  • 向子类原型上增加属性或方法时会影响到父类原型
function Parent(age) {
  this.name = "parent";
  this.age = age;
  this.hobby = ["sing", "rap"];
}
Parent.prototype.sayHi = function() {
  console.log("Hi");
};
function Child(age) {
  Parent.call(this, age);
  this.type = "child";
}

Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;
// 向子类原型上增加testProp属性,同时会被添加到父类原型上
Child.prototype.testProp = 1;
console.log(Parent.prototype); // 1

let child1 = new Child(15);
let child2 = new Child(15);

child1.hobby.push("basketball");
console.log(child1.name); // parent
console.log(child1.age); // 15
console.log(child1.type); // child
console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ]
console.log(child2.hobby); // [ 'sing', 'rap' ]
child1.sayHi(); // Hi

 

5.组合式继承优化2

优点:

  • 实现继承最有效的方式!

缺点:

function Parent(age) {
  this.name = "parent";
  this.age = age;
  this.hobby = ["sing", "rap"];
}
Parent.prototype.sayHi = function() {
  console.log("Hi");
};
function Child(age) {
  Parent.call(this, age);
  this.type = "child";
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

let child1 = new Child(15);
let child2 = new Child(15);

child1.hobby.push("basketball");
console.log(child1.name); // parent
console.log(child1.age); // 15
console.log(child1.type); // child
console.log(child1.hobby); // [ 'sing', 'rap', 'basketball' ]
console.log(child2.hobby); // [ 'sing', 'rap' ]
child1.sayHi(); // Hi

 

posted on 2021-02-05 18:40  sss大辉  阅读(69)  评论(0编辑  收藏  举报

导航