继承就是把已经存在的不需要多次定义的东西直接拿过来使用,例如:当一个构造函数A的实例使用了构造函数B上的属性和方法,那我们就说A继承了B,A叫子类,B叫父类。
常见的继承方式:原型继承、借用构造函数继承、组合继承、类的继承语法、拷贝继承等。
原型继承
就是把子类的原型对象指向父类的实例。也就是说父类的实例就是子类的原型对象。
优点:
既可以继承属性,也可以继承方法
缺点: 继承下来的属性不在自己的身上,在原型对象上; 书写的属性不能随意修改; 需要在多个地方传递参数; 注意:如果子类的原型对象上本身要书写方法,那该语句需要出现在继承语句之后,否则会被覆盖。
借用构造函数继承
就是把父类构造函数当作普通函数调用,通过call方法改变this的指向,在子类中调用。
优点:
继承下来的属性在子类自己身上;
可以传递任何我们想传递的参数;
缺点:
不能继承父类的方法。
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () {
console.log('我是Person上的方法');
}
function Students(classRoom,name1,age1) {
this.classRoom = classRoom
// 这里我们来调用父类构造函数
// Person.call(this要指向的那个对象, name的一个实参, age的一个实参)
// 现在 call() 方法中的第一个参数就是要指向的那个对象
// 这个对象是子类的实例 就是我们的变量 s
// 我们知道在构造函数体内 this 就是指向的实例 也就是 s变量
Person.call(this, name1, age1)
}
组合继承
就是原型继承和借用构造函数继承结合使用。
优点:
既可以继承属性也可以继承我们的方法
继承下来的属性在自己身上
也可以在一个地方传递参数
也可以传递任意的参数
缺点:
就是在子类的原型对象上多了一套属性
对我们来说没有影响
如果你给值了就是你给的那个值
如果没有给值就是 undefined
ES6的继承语法
ES6继承是一种新的语法,需要用到关键字extends。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
// 定义方法
sayHi() {
console.log('我是父类中的方法');
}
}
// 定义子类
class Students extends Person {
constructor(classRoom, name, age) {
// **先书写super()**
super(name,age)
this.classRoom = classRoom
}
play() {
console.log('我喜欢玩游戏');
}
}
拷贝继承
原理是利用for in将父类实例化对象上的属性赋值给子类的原型对象。
**in 是一个关键字,可以用来检测对象中有没有指定的属性。**
语法: 字符串 in 对象
//不仅能判断函数体中的属性,还能判断原型对象上的属性。
**hasOwnProperty()方法:**
语法:实例对象.hasOwnProperty(要检测的属性名)
//用来检测对象上有没有某个属性,但是只能检测函数体内的不能检测原型对象上的
function Person (name, age) {
this.name = name
this.age = age
}
// 在父类的原型对象上定义一个方法
Person.prototype.sayHi = function () {console.log(666);}
// 定义子类
function Students(classRoom, name, age) {
this.classRoom = classRoom
// 这里要实例化一个父类的对象
const p = new Person(name, age)
// 利用for in循环来实现
for (let k in p) {
// console.log(k, p[k]);
// 就是把拷贝下来的赋值给 子类的原型对象
Students.prototype[k] = p[k]
}
}
// 实例化一个子类
let s = new Students(2301,'Rose', 25)