前言
就学习的js继承作一学习记录,备查.
一、继承
1.原型继承
- 子对象自动拥有父对象的属性和方法, 继承可以提高代码的复用性;
- 原型对象(每一个构造函数都有一个原型对象)的值等于另一个类型的实例
二、几种继承方式
1.原型链继承
让子对象的原型指向父对象的实例,父对象的原型指向爷爷对象的实例,依次类推,就形成了原型链
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
function Student(id,score){
this.id = id;
this.score = score;
}
Student.prototype = new Person("laowang",18);
Student.prototype.study = function(){
console.log(this.name + " study");
}
let s = new Student(1,100);
console.log(s.name,s.age,s.id,s.score);//laowang 18 1 100
s.eat();//laowang eat
s.study();//laowang study
**重点:让新实例的原型等于父类的实例
注意事项:
- 1.由父类派生给子类的属性,无法初始化;
- 2.子类对象在添加新的方式时,一定要保证,先实现继承,再添加原型方法
2.构造函数继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
function Student(id,score,name,age){
Person.call(this,name,age);//这一步相当于复制Person里this.name=name;this.age=age;
this.id = id;
this.score = score;
}
let s = new Student(1,100,"laowang",18);
console.log(s.id,s.score,s.name,s.age);//1 100 laowang 18
s.eat();//报错
**重点:用.call()和.apply()将父类构造函数引入子类函数
注意事项:
- 1.只能继承父类构造函数的属性,不能继承方法
- 2.无法实现构造函数的复用
3.组合继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
function Student(id,score,name,age){
Person.apply(this,[name,age]);
this.id = id;
this.score = score;
}
Student.prototype = new Person();
Student.prototype.study = function(){
console.log(this.name + " study");
}
let s = new Student(1,100,"laowang",18);
console.log(s.id,s.score,s.name,s.age);//1 100 laowang 18
s.eat();//laowang eat
s.study();//laowang study
**重点:结合构造函数继承和原型链继承
4.原型式继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
function fun(person){//封装一个函数容器
function F(){};
F.prototype = person;//继承传入的实例对象原型
return new F();//返回函数对象
}
let s1 = new Person("laowang",18);
let s = fun(s1);
console.log(s.name,s.age);//laowang 18
s.eat();//laowang eat
封装fun()和Object.create()一样.(ES5中新增加方法)
Object.create()方法会使用指定的原型对象及其属性去创建一个新的对象.从本质上讲,相当于对传入的对象进行了一次浅拷贝.
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
let s1 = new Person("laowang",18);
// let s = fun(s1);
let s = Object.create(s1);
console.log(s.name,s.age);//laowang 18
s.eat();//laowang eat
**重点:类似于复制一个对象,用函数来包装。
注意事项:
- 1.所有的实例都会继承原型上的属性
- 2.无法实现复用。
5.寄生式继承
寄生式继承是于原型式继承紧密相关的一种思路,既创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
let s1 = new Person("laowang",18);
function Student(s1){
let stu = Object.create(s1);
stu.id = 1;//可以为其增加属性及方法
stu.score = 100;
stu.study = function(){
console.log(stu.name + " study");
}
return stu;
}
let s = Student(s1);
console.log(s.name,s.age,s.id,s.score);//laowang 18 1 100
s.eat();//laowang eat
s.study();//laowang study
**重点:重点:就是给原型式继承外面套了个壳子
注意事项:
- 没用到原型,无法复用
6.寄生组合继承
寄生式与组合式相结合的继承方式,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
组合式继承最大的弊端是会两次调用构造函数,浪费内存.与寄生继承结合解决这一问题.
背后的基本思路:使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log(this.name + " eat");
}
function Student(id,score){
this.id = id;
this.score = score;
}
function inheritPrototype(subType,superType){
// let prototype = Object.create(superType.prototype);//创建Person类的原型对象副本
let prototype = Object.create(superType.prototype,{name:{value:"laowang"},age:{value:18}});
prototype.constructor = subType;//修改副本的属性值 ??
subType.prototype = prototype;//把生成好的对象赋值给子类原型 ??
}
// Student.prototype = new Person("laowang",18);
inheritPrototype(Student,Person);//这句与上句等价
Student.prototype.study = function(){
console.log(this.name + " study");
}
let s = new Student(1,100);
// s.name = "laowang";
// s.age = 18;
console.log(s.name,s.age,s.id,s.score);//laowang 18 1 100
s.eat();//laowang eat
s.study();//laowang study
三、ES6继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
eat(){
console.log(this.name + " eat");
}
}
class Student extends Person{
constructor(id,name,age){
super(name,age);//super一定要写在前面!!
this.id = id;
}
study(){
console.log(this.name + " study");
}
}
let s = new Student(1,"nana",18);
console.log(s.id,s.name,s.age);//1 nana 18
s.eat();//nana eat
s.study();//nana study