JavaScript实现继承的方式
- 类式继承
- 构造函数继承
- 组合继承
- 寄生组合式继承
- extends继承
// 声明父类
function Animal() {
this.name = 'animal';
this.type = ['pig', 'cat'];
}
// 为父类添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
}
// 声明子类
function Dog() {
this.name = 'dog';
}
// 继承父类
Dog.prototype = new Animal();
var dog = new Dog();
dog.greet('汪汪'); // "汪汪"
console.log(dog.type); // ["pig", "cat"]
Animal.prototype
原型上添加了一个greet共有方法,然后通过new
命令实例化一个Animal,并且赋值给Dog.prototype
原型。__proto__
指向了父类的原型对象,这样就拥有了父类的原型对象上的属性与方法。dog.type.push('dog');
var dog2 = new Dog();
console.log(dog2.type); // ["dog", "cat", "dog"]
function Animal(color) {
this.color = color;
}
...
Dog.prototype = new Animal('白色');
...
console.log(dog.color); // "白色"
console.log(do2.color); // "白色"
// 声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig','cat'];
this.color = color;
}
// 添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
}
// 声明子类
function Dog(color) {
Animal.apply(this, arguments);
}
var dog = new Dog('白色');
var dog2 = new Dog('黑色');
dog.type.push('dog');
console.log(dog.color); // "白色"
console.log(dog.type); // ["pig", "cat", "dog"]
console.log(dog2.type); // ["pig", "cat"]
console.log(dog2.color); // "黑色"
apply
方法的运用,它是可以更改函数的作用域,所以在上面的例子中,我们在Dog子类中调用这个方法也就是将Dog子类的变量在父类中执行一遍,这样子类就拥有了父类中的共有属性和方法。prototype
绑定的方法:dog.greet(); // Uncaught TypeError: dog.greet is not a function
// 声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig','cat'];
this.color = color;
}
// 添加共有方法
Animal.prototype.greet = function(sound) {
console.log(sound);
}
// 声明子类
function Dog(color) {
// 构造函数继承
Animal.apply(this, arguments);
}
// 类式继承
Dog.prototype = new Animal();
var dog = new Dog('白色');
var dog2 = new Dog('黑色');
dog.type.push('dog');
console.log(dog.color); // "白色"
console.log(dog.type); // ["pig", "cat", "dog"]
console.log(dog2.type); // ["pig", "cat"]
console.log(dog2.color); // "黑色"
dog.greet('汪汪'); // "汪汪"
原型链
来决定的,由于JavaScript引擎在访问对象的属性时,会先在对象本身中查找,如果没有找到,才会去原型链中查找,如果找到,则返回值,如果整个原型链中都没有找到这个属性,则返回undefined。apply
复制到子类中的,所以不会发生共享。function Animal(color) {
this.color = color;
this.name = 'animal';
this.type = ['pig', 'cat'];
}
Animal.prototype.greet = function(sound) {
console.log(sound);
}
function Dog(color) {
Animal.apply(this, arguments);
this.name = 'dog';
}
/* 注意下面两行 */
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.getName = function() {
console.log(this.name);
}
var dog = new Dog('白色');
var dog2 = new Dog('黑色');
dog.type.push('dog');
console.log(dog.color); // "白色"
console.log(dog.type); // ["pig", "cat", "dog"]
console.log(dog2.type); // ["pig", "cat"]
console.log(dog2.color); // "黑色"
dog.greet('汪汪'); // "汪汪"
Object.create()
进行一次浅拷贝,将父类原型上的方法拷贝后赋给Dog.prototype,这样子类上就能拥有了父类的共有方法,而且少了一次调用父类的构造函数。function create(obj) {
function F() {};
F.prototype = obj;
return new F();
}
constructor
属性也被重写了,所以我们要修复这一个问题:Dog.prototype.constructor = Dog;
extends
是在ES6中新增的,Class
用来创建一个类,extends
用来实现继承:class Animal {
constructor(color) {
this.color = color;
}
greet(sound) {
console.log(sound);
}
}
class Dog extends Animal {
constructor(color) {
super(color);
this.color = color;
}
}
let dog = new Dog('黑色');
dog.greet('汪汪'); // "汪汪"
console.log(dog.color); // "黑色"
constructor
方法中调用super
方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。