构造函数的继承:三种
第一种:原型链继承(会将引用类型的值修改)
就是将父构造函数的实例赋给子构造函数的原型
//父构造函数
function Person() {
this.uname = 'zs';
this.fruits = ['苹果','桃子','橘子']
this.run = function() {
console.log(this.uname+'跑了');
}
}
// 子构造函数
function Star(id) {
this.id = id
}
//将子构造函数的原型指向父构造函数的实例
Star.prototype = new Person()
let Dlira = new Star()
console.log(Dlira.uname);
Dlira.run()
console.log(Dlira.fruits);
Dlira.uname = 'li';
Dlira.fruits.push('香蕉')
console.log(Dlira.fruits); //['苹果','桃子','橘子','香蕉']
let taile = new Star()
console.log(taile.uname);
console.log(taile.fruits); //['苹果','桃子','橘子','香蕉']
console.log(taile.fruits === Dlira.fruits); // true
第二种 call()继承(浪费内存)
通过 call()更改this指向
function Person() {
this.uname = 'zs';
this.fruits = ['苹果','桃子','橘子'];
this.run = function() {
console.log(this.uname+'跑了');
}
}
Person.prototype.sing = function() {
console.log('ahahah');
}
function Star(id) {
this.id = id;
Person.call(this);
}
// false 每实例一个对象,都会拷贝构造函数上的属性和方法挂载到实例对象上,浪费内存
let Dlira = new Star();
console.log(Dlira.uname);
console.log(Dlira.fruits); //['苹果','桃子','橘子']
Dlira.fruits.push('石榴')
console.log(Dlira.fruits); //['苹果','桃子','橘子','石榴']
let taile = new Star();
console.log(taile.fruits); //['苹果','桃子','橘子']
console.log(Dlira.fruits === taile.fruits); false
Dlira.sing()
第三种 组合继承,将第一种和第二种合起来
function Person() {
this.uname = 'zs';
this.fruits = ['苹果','桃子','橘子'];
this.run = function() {
console.log(this.uname+'跑了');
}
}
Person.prototype.sing = function() {
console.log('ahahah');
}
Star.prototype = new Person()
// 因为 改变了Star.prototype的指向,导致没有了 constructor,因此我们要将 Star.prototype.constructor重新指向Star
Star.prototype.constructor = Star
function Star(id) {
this.id = id;
Person.call(this);
}
let Dilra = new Star();
Dilra.fruits.push('莲雾');
console.log(Dilra.fruits); //['苹果','桃子','橘子','莲雾']
let TaiLe = new Star();
console.log(TaiLe.fruits); //['苹果','桃子','橘子']
console.log(Dilra.sing === TaiLe.sing); // true
ES6 类的继承
es6 是通过 关键字extends 实现继承的
class Father {
constructor(uname,age) {
this.uname = uname;
}
run() {
console.log(this.uname+'跑了');
}
}
class Son extends Father {
}
const son1 = new Son('son1');
console.log(son1.uname); // son1
son1.run() // son1跑了
class Dau extends Father {
constructor(uname,sex) {
// super() 当我们要给子类添加其他的属性时,就要用super()拿到父类的属性和方法,如果不加super(),就会报错
super(uname);
this.sex = sex;
}
}
const dau = new Dau('Dilra','女');
console.log(dau.uname,dau.sex); //Dilra 女
dau.run() // Dilra跑了
原型链:每个实例对象都有一个__proto__属性,它指向其构造函数的原型对象;因为原型对象也是一个对象,所以它也有__proto__属性,因此它也指向它的构造函数的原型对象。因此,当我们去调用一个对象的属性或方法时,先会在其自身上寻找,如果找不到,就要通过它的__proto__所指向的原型对象上去寻找,如果还没有,就通过原型对象的__proto__所指向的其构造函数的原型对象上寻找,直到找到或者返回undefined,这就是原型链。