原型链继承
// 父类
function Person(){
this.name='zs'
}
// 可以不用写
// Person.prototype.eating(){
// console.log(this.name+'food')
// }
// 子类
function Student(){
this.name='看书'
}
const p=new Person()//先使用new创建Person实例
Student.Prototype=p//实例化后的p赋值给子类的显示原型
// 可以不写
// Student.prototyp.reading=function(){
// console.log(this.name+'阅读')
// }
const stu=new Student()
原型链继承的弊端:
// 第一个弊端:以上面为例,打印stu对象,继承的属性是看不到的
console.log(stu) //需要点开才行
// 第二个弊端:创建出来两个stu对象
const stu1=new Student()
const stu2=new Student()
// 直接修改对象上的属性,是给本对象添加了一个新属性
stu1.name='ko'
consoe.lg(stu2.name)
// 获取引用,修改引用中的值会相互影响
stu1.arr.push('ko')
console.log(stu1.arr)
console.log(stu2.arr)
// 第三个弊端:在前面实现类的过程中都没有传递参数(父类里的值换不了)
const stu=new Student('li')
console.log(stu)
// 为了给父类传值,就用到了借用构造函数继承(call,apply,bind)
原型链继承弊端总体代码:
function Person(){
this.name='zs'
// 第二种弊端
this.arr=[]
}
Person.prototype.eating=function(){
console.log(this.name+'food')
}
function Student(){
this.name='读书'
}
const p=new Person()
Student.prototype=p
Student.prototype.reading=function(){
console.log(this.name+'看书')
}
// 第二种弊端(以下四行代码可都放出来查看效果)
const stu1=new Student()
// const stu2=new Student()
stu1.arr.push('ko')
// stu2.arr.push('ok')
// console.log(stu1,stu2)
// 第三种弊端
const stu=new Student('li')
console.log(stu)
借用构造函数实现继承:
function Person(age, friends) {
this.age = age
this.friends = friends
}
function Student(name, friends, sno) {
Person.call(this, name, friends)
this.sno = sno
}
var p = new Person()
Student.prototype = p
var stu = new Student(10, ['xxx'], 111)
console.log(stu)
借用构造函数的弊端:
// 子类: 特有属性和方法
function Student(name, age, friends, sno) {
Person.call(this, name, age, friends)
this.sno = 111
}
// 直接将父类的原型赋值给子类, 作为子类的原型
Student.prototype = Person.prototype
//为什么不合适?
//这种方案相当于是子类的原型对象就是父类的原型对象, 当给子类添加方法时 ,
// 相当于是全部添加到了父类的原型对象上面。 随着子类的不断增多(Teacher、Student、都可以继承自Person)
// 父类原型对象上的方法也越来越多 相当于所有子类特有的方法都被兄弟类所共享了
寄生组合式继承:
// 父类
function Person(name,friends){
// this->student对象
this.name=name
this.friends=friends
}
Person.prototype.eating(){
console.log(this.name+'food')
}
// 子类
function Student(name,friends,sno){
// this->student对象
Person.call(this,name,friends)
this.sno=sno
}
// 创建一个子类的原型对象,并让这个原型对象的__proto__指向父类的原型对象
Student.prototype=Object.create(Person.prototype)
// Student.prototypeconstructor=Student
Student.prototyp.reading=function(){
console.log(this.name+'阅读')
}
const stu=new Student('张三',[],123)
// console.log(stu.__proto__.constructor)
拓展:
默认情况下,所有的原型对象都是由Object所产生的,所以默认情况下,原型对象的隐式原型指向Object.prototype,但是唯独有一个特例:Object的原型对象,是原型链的最顶端,她的隐式原型属性值为null