“动物”构造函数
function Animal() {
this.species = '动物';
}
“人”构造函数
function Person(name, color) {
this.name = name;
this.color = color;
}
如何让人继承动物?
一、 构造函数绑定
构造函数的绑定 Object.apply(this, arguments) 或 Object.call(this, arguments)。
function Animal() {
this.species = '动物';
}
function Person(name, color) {
Animal.call(this, arguments);
this.name = name;
this.color = color;
}
const p1= new Person("Tom", "skyblue");
console.log(p1.species);//动物
call() 方法是函数特有的,它用来改变this的指向;就是把一个函数的方法绑定到相应的对象上,于是这个对象就就可以调用它。利用this指向可以改变的特点,此时call()的this指向p1,。在Animal里的
this.species = '动物'
视作p1.species = '动物'
.
call()方法理解
this一般指向调用它的对象,这里this是指向p1,当无调用时,默认指向浏览器Window。
function add(num1, num2) {
console.log(`绑定对象为:${this}`);
return num1 + num2
}
const result1 = add(2, 3);
console.log(result1);
let obj1 = {};
let result2 = add.call(obj1, 4, 5);
console.log(result2);
二 、 Prototype模式
将Person的prototype对象指向一个Animal的实例。如果没有"Person.prototype = new Animal();"这一行,Person.prototype.constructor是指向Person的;加了这一行以后,Person.prototype.constructor指向Animal。
Person.prototype = new Animal();
Person.prototype.constructor = Person;
//此时的Person实例即可访问到Animal的属性和方法
let p1 = new Person();
console.log(p1.species);//动物
详解:
在继承之前,Animal与Person的原型链
当执行Person.prototype = new Animal();
时,Person的prototype对象指向Animal的实例,在任何一个prototype对象都有一个construction属性,从原先指向它的构造函数的改变成了指向Animal,即Person.prototype.constructor指向Animal。
并且,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性。
console.log(Person.prototype.constructor == Animal);//true
let p1 = new Person();
console.log(p1.species);//动物
console.log(p1.constructor == Animal);//ture
console.log(p1.constructor == Person.prototype.constructor);//true
console.log(Person.prototype.__proto__ == Animal.prototype);//true
但在这时,也会导致继承链的紊乱,因为p1是构造函数Person生成的,所以得手动纠正将Person.prototype对象的constructor值改为Person。
Person.prototype.constructor = Person;
当执行Person.prototype.constructor = Person
时,将`Person.prototype.constructor指回Person构造函数。
let p1 = new Person();
console.log(p1.species);//动物
console.log(Person.prototype.__proto__ == Animal.prototype);//true
console.log(p1.constructor == Animal);//false
三 、直接继承Prototype
将Person的prototype对象指向一个Animal.prototype。(对Prototype继承的改进)
在Animal的prototype添加属性
Animal。prototype.say = 'Hello';
将Person的prototype对象指向Animal的prototype对象
Person.prototype = Animal.prototype;
Person.prototype.constructor = Person;
优点:相较于prototype继承,效率比较高,省内存;
缺点:由于Person.prototype和Animal.prototype是指向同一个对象的,所以任何一方的修改,都会反映到另外一方;如执行Person.prototype.constructor = Person
时,Animal的prototype对象也会指向Person。
三 、利用空对象作为中介
对“直接继承prototype”缺点的改进,利用一个空对象作为中介
var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
此时的指向:
使用函数封装
function extend(Child, Parent) {
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
使用
extend(Person, Animal);
const p1 = new Person();
console.log(p1.say);//Hello