继承:
原型链实际上就是一种继承,对象直接查找属性或者方法的时候,是会顺着原型链查找的
// 原型链实现继承的弊端
// 1.打印p1对象,某些属性看不到(继承的属性)
// 2.修改父类的属性时,例如数组的push,会影响到不同的子类
// 3.Student原型中的constructor属性丢失
// 父类
function Person(){
this.name = "张三"
}
Person.prototype.eating = function(){
console.log(this.name,"在吃饭");
}
// 子类
function Student(){
this.sno = 100
}
Student.prototype = new Person()
Student.prototype.studying = function(){
console.log("学习考了",this.sno);
}
var p1 = new Student()
p1.eating() //会顺着原型链向上查找eating方法
// 借用构造函数实现的弊端
// 1.Person函数至少被调用两次
// 2.p1的原型上会多一些值为undefined的属性
// 父类
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.eating = function(){
console.log(this.name,"在吃饭");
}
// 子类
function Student(name,age,sno){
Person.call(this,name,age) //借用构造函数,给p1赋值
this.sno = sno
}
Student.prototype = new Person()
Student.prototype.studying = function(){
console.log("学习考了",this.sno);
}
var p1 = new Student("张三",18,100)
console.log('p1: ', p1);
console.log('p1: ', p1.__proto__); //p1的原型会多两个undefined的属性
想要获得一个继承于obj的空对象的三种方法:
var obj = {
name:"李斯",
age:18
}
// 方法1,通过setPrototypeOf()方法
function creatObj1(o){
var newObj = {}
Object.setPrototypeOf(newObj,o)
return newObj
}
// 方法2:通过new构造函数的方法
function creatObj2(o){
function Fn(){}
Fn.prototype = o
var newObj = new Fn()
return newObj
}
// 方法3,通过Object.create方法
function creatObj3(o){
var newObj = Object.create(o)
return newObj
}
最终方案是
//寄生组合式继承
//借用工厂函数创建一个原型为o的空对象
function createObject(o){
function Fn(){}
Fn.prototype = o
var newObj = new Fn()
return newObj
}
//将创建的空对象赋值给子类的原型对象,实现了继承
function inheritPrototype(subType,superType){
subType.prototype = createObject(superType.prototype)
Object.defineProperty(subType.prototype,"constructor",{
enumerable:false,
configurable:true,
writable:true,
value:subType
})
}
// 父类
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.eating = function(){
console.log(this.name,"在吃饭");
}
//调用继承实现封装的方法
inheritPrototype(Student,Person)
// 子类
function Student(name,age,sno){
Person.call(this,name,age)
this.sno = sno
}
Student.prototype.studying = function(){
console.log(this.name,"在学习");
}
var p1 = new Student("张三",18,100)
console.log('Student.prototype: ', Student.prototype);
console.log('p1: ', p1);
console.log('p1.__proto__: ', p1.__proto__);
p1.eating()
p1.studying()
补充:
查找对象是否有某个属性的方法
console.log(obj.hasOwnProperty("name")); //false 不顺着原型找,只找当前对象
console.log("name" in obj); //true in操作符查找 会顺着原型链
instanceof判断数据类型的原理,判断构造函数的原型是否在某个实例的原型上
[] instanceof Array // true Array.prototype 在 [] 的原型上
[] instanceof Object // true Object.prototype 在 [] 的原型上
a.isPrototypeOf(b) //a对象是否存在于b的原型链上