1、原型继承
function Animal() {this.color = ['black','white']}Animal.prototype.getColor = function(){return this.color}function Dog() {}Dog.prototype = new Animal()let dog1 = new Dog()dog1.colors.push('brown')let dog2 = new Dog()console.log(dog2.colors)
原型链继承存在的问题:
- 问题1:原型中包含的引用类型属性将被所有实例共享;
- 问题2:子类在实例化的时候不能给父类构造函数传参;
2、借用构造函数实现继承
function Animal(name) {this.name = namethis.getName = function () {return this.name}}function Dog(name) {Animal.call(this, name)}Dog.prototype = new Animal()
借用构造函数实现继承解决了原型链继承的 2 个问题:引用类型共享问题以及传参问题;
但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法;
3、组合继承
function Animal(name) {this.name = namethis.colors = ['black', 'white']}Animal.prototype.getName = function () {return this.name}function Dog(name, age) {Animal.call(this, name)this.age = age}Dog.prototype = new Animal()Dog.prototype.Constructor = Doglet dog1 = new Dog('奶昔', 2)dog1.colors.push('brown')let dog2 = new Dog('哈赤', 1)console.log(dog2)
优点:融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。
缺点:调用了两次构造函数,做了重复的操作。
4、寄生组合继承
// 原型链继承 + 构造函数继承// 1. 引用类型被改变,所有实例共享// 2. 无法传参// 3. 多占用了内存空间function Parent(name, actions) {this.name = name;this.actions = actions;}Parent.prototype.getName = function () {console.log(this.name + '调用了getName');}function Child() {Parent.apply(this, arguments);}// Child.prototype = Parent.prototype; // 一旦更改Child.prototype,Parent.prototype也会被修改。Child.prototype = Object.create(Parent.prototype);// Child.prototype = new Parent();// let TempFunction = function () {};// TempFunction.prototype = Parent.prototype;// Child.prototype = new TempFunction();Child.prototype.constructor = Child;// super() Childconst c1 = new Child('c1', ['eat']);const c2 = new Child('c2', ['run']);
