继承(面试题)
类与类之间的继承 三种方式
1.原型链继承 ( extend-prototype)
原型继承 子类的原型指向父类的实例
<script>
//继承 :类与类之间的继承 三种
// 1.原型继承
//父类
function Animal(a, b) {
//属性
this.a = a;
this.b = b;
}
Animal.prototype.say = function () {
console.log('My name is ' + this.a)
}
//子类
function Dog() {
this.c = 5;
this.zy = function () {
console.log('哈哈哈');
}
}
//原型继承 子类的原型指向父类的实例
Dog.prototype = new Animal(1, 2);
var snoopy = new Dog()
console.log(snoopy); //Dog {c: 5, zy: ƒ}__proto__: Animal a: 1 b: 2
console.log(snoopy.a) // 1
snoopy.say() //My name is 1
snoopy.zy() // 哈哈哈
//instanceof:运算符。判断当前对象是否是另一个对象的实例
console.log(snoopy instanceof Dog); //true
console.log(snoopy instanceof Animal); //true
</script>
特点:
1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例
2.父类新增原型方法/原型属性,子类都能访问到
3.简单,易于实现
缺点:
1.要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
2.无法实现多继承
3.来自原型对象的引用属性是所有实例共享的
4.创建子类实例时,无法向构造函数传参
2、构造继承 (call 、apply 继承) extend-constructor
构造继承不考虑原型
把父类的构造函数当成普通函数在子类的构造函数里调用,并且修改this指向
<script>
//第二种 借用继承 寄生继承
// 父类
function Animal(a, b) {
this.a = a;
this.b = b;
this.aa = function () {
console.log(55);
return 555;
}
}
Animal.prototype.say = function () {
console.log("66")
}
// 子类
function Dog(a, b) {
this.c = 666;
// 把父类的构造函数当成普通函数在子类的构造函数里调用,并且修改this指向
// 这里Animal作为普通的全局函数再调用,所以里面的this指window
// 所以希望在调用Animal的时候把this指向外层Cat的this
// call或者apply a,b实参
// Animal.apply(this, [ a, b ])
Animal.call(this, a, b)
}
var snoopy = new Dog(1, "2");
console.log(snoopy);
console.log(snoopy.a); // 蓝色1
console.log(snoopy.b);// 黑色2
// console.log(snoopy.say());//报错 ,继承不了原型上的方法
snoopy.aa() // 55
console.log(snoopy.aa()); // 555
var rr = new Animal(1, 2)
rr.say()
// console.log( snoopy.aa());
console.log(snoopy instanceof Dog) // true
console.log(snoopy instanceof Animal) // false
</script>
特点:
1、解决了1中,子类实例共享父类引用属性的问题
2、创建子类实例时,可以向父类传递参数
3、可以实现多继承(call多个父类对象)
缺点:
1、实例并不是父类的实例,只是子类的实例
2、只能继承父类的实例属性和方法,不能继承原型属性/方法
3、无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
3、组合继承(原型链和构造继承的组合) extend-group
组合继承是原型链继承和构造继承的组合
<script>
// 组合继承是原型链继承和构造继承的组合
function Animal(name) {
this.name = name
}
Animal.prototype.say = function () {
console.log('My name is ' + this.name)
}
function Pig(name) {
Animal.call(this, name)
}
Pig.prototype = new Animal()
var peiqi = new Pig('Peiqi')
peiqi.say()
var qiaozhi = new Pig('Qiaozhi')
qiaozhi.say()
console.log(peiqi.say === qiaozhi.say) // true
console.log(peiqi instanceof Pig) //true
console.log(peiqi instanceof Animal) //true
</script>
4、ES6继承(语法糖) extend-class
extends关键字相当于实现原型链继承
Dog.prototype = new Animal('Snoopy')
super是ES6新增的方法,这个方法在继承子类的构造函数里调用
相当于Animal.call(this, name, age)
<script>
class Animal {
constructor (name, age) {
this.name = name
this.age = age
}
say () {
console.log(`My name is ${this.name}, I am ${this.age} years old`)
}
}
// extends关键字相当于实现原型链继承
class Mouse extends Animal {
constructor (name, age) {
// super是ES6新增的方法,这个方法在继承子类的构造函数里调用
// 相当于Animal.call(this, name, age)
super(name, age)
}
}
var jerry = new Mouse('Jerry', 80)
jerry.say()
console.log(jerry instanceof Mouse) // true
console.log(jerry instanceof Animal) // true
</script>
5、静态属性
// 静态属性 是指 只能有 构造函数调用,实例无法调用的属性
// 不是静态属性 则只能有 实例调用,构造函数无法调用的属性
/*
两种写法:
1.类内部 定义属性时 加上 static关键字
2,在外部通过 类.属性名 = 值 定义
*/
class Animal {
a = 10;
b = 20;
c = () => {
console.log(11)
console.log(this);
}
d = "我是一个静态afa f属性";
static e = () => {
console.log("我是静态adad方法")
}
p = function () {
console.log("bushi静态");
}
}
var pig = new Animal()
console.log(typeof Animal); // function
console.log(typeof pig); //object
// Animal.e() "我是静态adad方法"
// pig.p() "我是adad方法"
// pig.e pig.e is not a function
// Animal.p() Animal.p is not a function
// Animal().p() // 报错 在没有“new”的情况下无法调用类构造函数Animal
new Animal().p() //bushi静态
6、定义属性
第一种方法
// 定义属性的第一种方法
class Animal {
a = 10;
b = 20;
c = () => {
console.log(this, 11);
}
}
var a1 = new Animal();
console.log(a1) //Animal {a: 10, b: 20, c: ƒ}
a1.c(); //Animal {a: 10, b: 20, c: ƒ} 11
第二种方法 建议使用
class Animal {
constructor(name, age) {
// 在new 类自动调用的 this指向实例
// 属性第二种定义方法 是在constructor中定义 建议写法
this.name = name;
this.age = age;
}
a() {
console.log(this, 1)
}
}
var a2 = new Animal("小红", 20);
console.log(a2); // Animal {name: "小红", age: 20}
console.log(a2.a === Animal.prototype.a) // true
a2.a() // Animal {name: "小红", age: 20} 1