在ECMAScript中实现继承的方式主要是通过原型链实现的。
通过原型链继承的基本思想是:通过原型,继承引用类型的属性和方法。
注意:所有的引用类型都继承自Object。
两个函数:Animal、Dog
一个Dog实例:dog
通过原型链继承,实现让dog调用sayName()方法
function Animal(name) { this.name = name; } Animal.prototype.sayName = function () { console.log('my name is ', this.name); } function Dog(name, color, age) { this.name = name; this.color = color; this.age = age } // 原型链继承 Dog.prototype = new Animal(); //修改Dog原型中的constructor指针指向 Dog.prototype.constructor = Dog; Dog.prototype.sayColor = function () { console.log('my color is ', this.color); } let dog = new Dog('小白', '白色', 2) dog.sayColor(); //白色 dog.sayName(); //小白 成功调用该方法 console.log(Dog.prototype.constructor); //[Function: Dog]
当Dog的原型成为Animal的实例时,就实现了原型链的继承。但是Dog里面的constructor指针就会销毁,那么当我们查找dog实例的构造函数时就会向上找到Animal原型的constructor指针,这时,dog的构造函数就为Animal。
但是,dog的构造函数明明是Dog,通过原型链继承,改变这个指向,所以,我们要手动的修改回来,让他指向回Dog。
此时,我们就能调用Animal中的sayName()方法。
例如:我们在Dog的原型中添加了一个sayColor()方法,需要在Dog原型的constructor指向改变之后再添加。
Dog.prototype = { getDogName() { console.log(this.name); }, someOtherMethod() { return false; } }; console.log(Dog.prototype.constructor); //[Function: Object]
我们都知道,通过instanceof操作符可以判断一个实例是否属于某个构造函数,即该实例的原型链中是否出现某个构造函数。
isPrototypeOf()
通过isPrototype()这个方法,我们可以判断某个构造函数的原型链中是否包含某个实例,是则返回true,不是则返回false。
//true console.log(Object.prototype.isPrototypeOf(dog)); //true console.log(Animal.prototype.isPrototypeOf(dog)); //true console.log(Dog.prototype.isPrototypeOf(dog));
经典继承又称盗用构造函数,用于解决原型包含引用值导致的继承问题。
用法:在子构造函数中使用call()或apply()方法,改变this指向,指向当前子构造函数并调用父构造函数。这样之后每个实例都会拥有自己的引用值类型数据,就不会共享而导致出现问题。
// 父'类' function Animal() { this.name = 'aaa' this.categorys = ['cat', 'dog'] } // 子'类' function Dog() { // 改变this指向 继承属性 Animal.call(this); }
注意:不能使用instanceof操作符和isPrototypeOf()方法判断继承的父构造函数,因为只继承了父构造函数的实例方法、属性,没有继承父构造函数原型对象中的属性、方法。
又称伪经典继承,结合了原型链继承和经典继承的优点,是JS使用最多得继承模式。
用法:通过原型链继承原型上的属性和方法;通过经典继承继承实例属性。
优点:将方法定义在原型上,实现重用;还可以让每个实例都拥有自己的实例
function Animal() { this.name = 'aaa' this.categorys = ['cat', 'dog'] } Animal.prototype.sayName = function () { console.log(this.name); } // 子'类' function Dog() { // 改变this指向 继承属性 Animal.call(this); } // 继承方法 Dog.prototype = new Animal() var d1 = new Dog(); d1.categorys.push('rabbit') var d2 = new Dog(); console.log(d1.categorys); //[ 'cat', 'dog', 'rabbit' ] console.log(d2.categorys); //[ 'cat', 'dog'] d1.sayName() //aaa