ES5实现继承
声明一个Person对象,将该对象作为父级,而子级cPerson将要继承Person的所有属性与方法。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function() {
return this.name;
}
构造函数继承
借助call方法,将父级的构造函数执行了一次,相当于将Person中的代码,在cPerson中复制了一份,其中的this指向为从Student中new出来的实例对象。call方法保证了this的指向正确,因此就相当于实现了继承。
缺点:即使实例对象拥有相同的方法,构造函数继承也会为每个实例对象创建单独的方法,浪费内存。
// 构造函数的继承
function cPerson(name, age, job) {
Person.call(this, name, age);
this.job = job;
}
原型继承
// 继承原型
cPerson.prototype = new Person(name, age)
// 添加更多方法
cPerson.prototype.getLive = function() {}
缺点:原型继承中的属性是共享的,如果一个实例对象对某属性进行了修改,那么另一个实例对象就会获取修改后的属性值。
组合继承
为了解决上面构造继承和原型继承中存在的缺点,出现了组合继承,一般不共享的属性通过构造继承,而需要共享的方法通过原型继承。
缺点:组合继承会调用两次父类构造函数的代码
function Person(name){
this.name=name;
}
Person.prototype.sayName=function(){
console.log(this.name+' '+this.gender+' '+this.age);
}
function Female(name,gender,age){
Person.call(this,name);//第一次调用父类构造函数
this.age=age;
this.gender=gender;
}
Female.prototype=new Person();//第二次调用父类构造函数
Female.prototype.constrcutor=Female;//因重写原型而失去constructor属性,所以要对constrcutor重新赋值
寄生组合继承
通过借用构造函数来继承属性,通过原型链来继承方法,不需要为子类指定原型而调用父类的构造函数,省去了上面第二次调用父类构造函数的步骤。
通过创建父类原型的副本,并为其添加constructor,最后赋值给子类的原型。从而避免调用两次父类的构造函数,为其创建多余的属性
function inheritPrototype(Female,Person){
var protoType=Object.create(Person.prototype);
protoType.constructor=Female;
Female.prototype=protoType;
}
inheritPrototype(Female,Person);
Female.prototype.sayAge=function(){
console.log(this.name+' '+this.age);
}
//取代
//Female.prototype=new Person();
//Female.prototype.constrcutor=Female
//上面的代码相当于:
Female.prototype = Object.create(Person.prototype, {
constructor: { //重新指定构造函数
value: Student
}
sayAge: {
value: function() {
return this.grade //添加新的方法
}
}
})
var fm=new Female('skila','female',19);
fm.sayName();//skila female 19
fm.sayAge();skila 19
Object.create()
创建一个新对象,使用现有对象提供创建的新对象的__proto__
function create(proto, options) {
// 创建一个空对象
var tmp = {};
// 让这个新的空对象成为父类对象的实例
tmp.__proto__ = proto;
// 传入的方法都挂载到新对象上,新的对象将作为子类对象的原型
Object.defineProperties(tmp, options);
return tmp;
}
Object.defineProperties()
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
})
ES6实现继承
class Person{
constructor(name,age){
//这里的this指的是实例对象
this.name = name
this.age = age
}
//say绑定到Person.prototype
say(){
console.log('my name is ' + this.name + ", I am " + this.age)
}
//sayHobby绑定到Person.prototype
sayHobby(){
console.log('no hobby')
}
//sayName绑定到实例对象
sayName = function(){
console.log('my name is ' + this.name)
}
//sayAge绑定到实例对象
sayAge = () => {
console.log('I am ' + this.age + ' years old')
}
}
//extends实现继承
class cPerson extends Person{
constructor(name, age, hobby){
super(name, age)
this.hobby = hobby
}
sayHobby = function(){
console.log('I like ' + this.hobby )
}
}
const p = new cPerson('zs', 12, 'drawing')
console.log(p.name) //zs
console.log(p.age) //12
console.log(p.hobby) //drawing
p.say() //my name is zs, I am 12
p.sayName() //my name is zs
p.sayHobby() //I like drawing
//实例对象上的属性可以被删除
delete p.sayHobby
p.sayHobby() //会通过原型链向上查找