目录
继承分为三类,分别是:原型链继承、借用构造函数继承、组合继承(原型链继承+借用构造函数继承)
从前面的学习可以知道创建单个对象有两种方法,一种是直接使用字面量 var obj = {},另一种则是使用构造函数 var obj = new Object() 来创建单个对象的。
那么,多个对象又如何创建呢?接下来,将介绍四种创建多个对象的方法。
工厂函数模式
// 工厂函数模式
function sayName(){
console.log(this.name);
}
function person(name,age,gender){
return{
name:name,
age:age,
gender:gender,
// 写在内部会造成方法冗余,每个子对象都会在堆区占据一块方法的区域
// sayName:function(){
// console.log(this.ame);
// }
// 方法写在外部
sayName:sayName
}
}
var p1 = person('jemmy',21,'male');
var p2 = person('cammy',18,'female');
console.log(p1);
console.log(p2);
p1.sayName();
p2.sayName();
function dog(name,age){
return{
name:name,
age:age
}
}
var d1 = dog('闹闹',4);
console.log(d1);
从输出结果可以看出该方法的优点和缺点:
优点:
可以批量创建对象 降低代码冗余
缺点:
无法区分对象的种类(全是object实例) 方法冗余(无法区分sayName是谁的方法)。
构造函数模式
// 构造函数
function sayName(){
console.log(this.name);
}
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = sayName;
}
var p1 = new Person('jemmy',21,'male');
var p2 = new Person('cammy',18,'female');
/**
* new关键字做了什么?
1.创建一个实例对象 var p1 = new Person(){}
2.将this指向实例对象 this -->p1
3.执行函数体 p1.name = zhangsan;
4.返回实例对象 return p1{}
*/
console.log(p1);
console.log(p2);
p1.sayName();
p2.sayName();
function Dog(name,age){
this.name = name;
this.age = age;
}
var d1 = new Dog('闹闹',4);
console.log(d1);
优点:
可以批量创建对象 可以区分种类
缺点:
方法冗余
原型对象模式
// 原型对象
function Person(){};
Person.prototype = {
constructor:Person,
name:'cammy',
age:18,
gender:'female',
sayName:function(){
console.log(this.name);
}
}
var p1 = new Person();
var p2 = new Person();
console.log(p1,p2);
console.log(p1.name,p2.name);
Person.prototype.friends = [];
p1.friends.push('tom');
console.log(p1.friends);
console.log(p2.friends);
优点:
解决了方法冗余 批量创建对象
缺点:
所有的实例属性和方法都一样(如图中给p1对象数组中添加一个元素,结果p2也添加上了)
组合模式
// 组合模式 构造函数 + 原型对象
//将实例私有属性和方法全部放在构造函数中
//将实例公共属性和方法都放在原型对象中
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.friends = [];
}
Person.prototype = {
constructor:Person,
sayName:function(){
console.log(this.name);
}
}
var p1 = new Person('jemmy',21,'male');
var p2 = new Person('cammy',18,'female');
console.log(p1,p2);
p1.friends.push('tom');
console.log(p1,p2);
p1.sayName();
p2.sayName();
instanceof
判断当前实例对象是否处在原型链上
判断是否是某一个构造函数的实例对象
/**
* instanceof 判断当前实例对象是否处在原型链上
* 判断是否是某一个构造函数的实例对象
*/
console.log(p1 instanceof Person);
console.log(p2 instanceof Person);
console.log(p1 instanceof Object);
console.log(p2 instanceof Object);
console.log(Person instanceof Object);
继承
继承分为三类,分别是:原型链继承、借用构造函数继承、组合继承(原型链继承+借用构造函数继承)
这里介绍组合继承
组合继承
// 构造创建函数 父函数
function Animal(type,age,weight){
this.type = type;
this.age = age;
this.weight = weight;
}
// 公共方法
Animal.prototype = {
constructor:Animal,
sayType:function(){
console.log(this.type);
}
}
// 借用构造函数继承
function Dog(type,age,weight,name){
// Animal.call(this,type,age,weight);
// Animal.apply(this,[type,age,weight]);
Animal.bind(this)(type,age,weight);
this.name = name;
}
// var d1 = new Dog('狗',3,'20kg','闹闹');
// console.log(d1);
// 原型链继承
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.sayName = function(){
console.log(this.name);
}
// Dog.prototype.sayType = function(){
// console.log('我是子构造函数的原型对象');
// }
var d1 = new Dog('狗',3,'20kg','闹闹');
console.log(d1);
d1.sayType();
借用构造函数继承的重点在于
// Animal.call(this,type,age,weight);
// Animal.apply(this,[type,age,weight]);
Animal.bind(this)(type,age,weight);
需要调用父构造函数并且将this指向修改为子构造函数实例,可以使用call,apply或bind来改变指向,其介绍详情见函数的基本知识_学前端的狗头苏丹的博客-CSDN博客
原型链继承的重点在于
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
通过第一句来将子构造函数的原型对象指向父构造函数的实例对象去调用父构造函数中的方法。
通过第二句来将子构造函数重新指向子构造函数。