继承,就是A的属性方法可以继承给B,B可以继续往下传。同时我们还希望
- B能够新增自己的属性和方法
- B能够修改继承来的属性和方法,同时不影响A也不干扰同代
JavaScript想实现继承的目的:重复利用另外一个对象的属性和方法
1.原型链的继承
构造函数、原型和实例之间的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个原型对象的指针
function parent() {
this.show = true;
this.info = {
name: '张三',
age: 18
}
}
parent.prototype.getInfo = function () {
console.log(this.info);
console.log(this.show);
}
function child() { }
child.prototype = new parent();
let child1 = new child();
child1.info.gender = '男'
child1.getInfo() //{name:'张三',age:18,gender:'男'} true
原型链方案存在的缺点:多个实例对引用类型的操作会被篡改
2.借用构造函数继承
function Person(name, age) {
this.name = '张三',
this.age = 18
}
function fn(name, age) {
Person.call(this, name, age);
this.job = '赚钱'
}
let obj = new fn()
console.log(obj.name,obj.age,obj.job);//张三 18 赚钱
fn()中的实例都会将Person中的属性复制一份
缺点:
- 只能继承父类的属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
3.原型式继承
let Person = {
color: ['pink', 'black', 'red']
}
let anotherColor = Object(Person);
anotherColor.color.push('white')
console.log(Person.color); //['pink','black','red','white']
缺点:
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
- 无法传递参数
4.ES6类继承extends
extends关键字主要用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类。
class Father{
constructor(){
}
money(){
console.log(111);
}
}
class Son extends Father{
}
let son = new Son();
son.money(); //111
5.寄生式继承
核心:在原型式继承的基础上,增强对象,返回构造函数
function newFn(original) {
let newObj = Object(original); //通过调用object()函数创建一个新对象
newObj.say = function () { // 以某种方式开增强对象
console.log('111');
}
return newObj; //返回这个对象
}
let Person = {
name: 'aaa',
friends: ['aa', 'bb', 'cc']
}
let anotherFn = newFn(Person)
anotherFn.say()
函数的主要作用是为构造函数新增属性和方法,以增强函数
缺点:
- 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
- 无法传递参数
6.组合继承
组合继承综合了原型链继承和借用构造函数继承,将两者有点结合了起来 基本的思路就是使用原型链继承原型上的属性和方法,而通过构造函数继承实例属性,这样既可以把方法定义在原型上以实现使用,又可以让每个实例都有自己的属性
function Parent(name) {
this.name = name
this.colors = ["red", "blue", "yellow"]
}
Parent.prototype.sayName = function () {
console.log(this.name);
}
function Child(name, age) {
// 继承父类属性
Parent.call(this, name)
this.age = age;
}
// 继承父类方法
Child.prototype = new Parent();
Child.prototype.sayAge = function () {
console.log(this.age);
}
let child1 = new Child("zhangsan", 19);
child1.colors.push("pink");
console.log(child1.colors); // ["red", "blue", "yellow", "pink"]
child1.sayAge(); // 19
child1.sayName(); // "zhangsan"
上面例子中,parent构造函数定义了name,colors两个属性,接着又在他的原型上添加了个sayName()方法。child构造函数内部调用了parent构造函数,同时传入了name参数,同时child.prototype也被赋值为parent实例,然后又在他的原型上添加了个sayAge()方法,这样就可以创建child1实例,让这个实例有自己的属性,包括colors,同时还共享了父类的sayName方法
优点
- 父类的方法可以复用
- 可以在child构造函数中向parent构造函数中传参
- 父类构造函数中的引用属性不会被共享
喜欢点个赞叭