继承是指在原型对象的所有属性和方法,都能被实例对象共享。也就是说,我们只要在原有对象的基础上,略作修改,得到一个新的的对象。
实现对象 继承的5种方式
1.原型链继承
JavaScript使用原型链作为实现继承的主要方法,实现的本质是重写原型对象
function Fn(name){
this.name = name;
}
Fn.prototype.say = function(){
console.log('我是'+this.name)
}
Fn.prototype.car = function(){
console.log('我有一辆小汽车')
}
function Son(name){
this.name = name;
}
Son.prototype = Fn.prototype; //将Fn原型对象 赋值 给Son ****
// Son.prototype = new Fn('父亲') //将new出来的实例对象赋值给Son 不推荐
Son.prototype.constructor = Son; //改变Son原型对象中的指向 指向自己
var f = new Fn('父亲');
console.log(f)
// f.say();
// f.car();
var s = new Son('儿子')
s.__proto__.car = function(){ //儿子 修改方法 父亲也会发生改变
console.log("a8")
}
console.log(s)
// s.say();
// s.car();
s.car();
f.car();
2.借用构造函数继承
借用构造函数的技术(有时候也叫做伪类继承或经典继承)。这种技术的基本思想相当简单, 即在:子类构造函数的内部调用父类构造函数。 别忘了,函数只不过是在特定环境中执行代码的对象,因此通过使用apply()和call()方法也可以在新创建的对象上执行构造函数
function Fn(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.oa = function(){
console.log(111)
}
}
Fn.prototype.say = function(){
console.log(this.name,this.age,this.sex)
}
var f = new Fn('张三',18,"未知")
f.say();
function Son(name,age,sex){
// Fn.call(this,name,age,sex);
//调用Fn函数,在本次调用时改变Fn内的this指向(指向Son 将向Fn内添加的属性 添加至Son中),将参数
//传递过去
Fn.apply(this,[name,age,sex]);
//调用Fn函数 在本次调用时改变Fn内的this指向(指向Son 将向Fn内添加的属性 添加至Son中) 将参数传
//递过去
}
var s = new Son('贾师傅',18,'哦念经四川');
console.log(s)
3.组合继承
组合继承,指的是将原型链和借用构造函数技术组合到一起,从而发挥两者之长的一种继承模式。其背后的思想是使用原型链实现对原型上的公共属性和方法的继承,而通过借用构造函数继承来实现对父类私有属性的继承。这样,即通过在父类原型上定义方法实现了函数复用,又能够保证每个实例都有父类的私有属性。
组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,称为JavaScript中最常用的继承模式。
function Fn(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Fn.prototype.car = function(){
console.log('我是有一辆小汽车')
}
Fn.prototype.dog = function(){
console.log('家有恶犬')
}
var f = new Fn('沾伞',18,'难受')
console.log(f)
function Son(name,age,sex){
Fn.call(this,name,age,sex)
}
//对Fn函数的原型对象进行遍历 将Fn原型对象中的每个属性或方法 添加至 Son的原型对象中
// for(var i in Fn.prototype){
// Son.prototype[i] = Fn.prototype[i];
// }
// Son.prototype.constructor = Son;
// Son.prototype = new Fn();
var s = new Son('请问',21,'在撒的');
s.__proto__.car = 123;
console.log(s)
组合继承的问题: 无论在什么情况下,都会调用两次父类的构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部
4.寄生组合继承
组合继承方法我们已经说了,它的缺点是两次调用父级构造函数,为了解决这个问题只能砍掉一次调用。因此使用Object.create方法进行继承
function Fn(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Fn.prototype.say = function(){
console.log('我会说话')
}
function Son(name,age,sex){
Fn.call(this,name,age,sex);
}
Son.prototype = Object.create(Fn.prototype); // 这里只将父类的prototype拿过来并使用Object.create(是一种创建对象的方式,它会创建一个中间对象)
Son.prototype = new Fn();
Son.prototype.constructor = Son;
var f = new Fn('张三',18,'男');
var s = new Son('李四',20,'男');
s.__proto__.__proto__.say = 123;
console.log(f);
console.log(s)
5.多重继承
JavaScript中不存在多重继承,那也就意味着一个对象不能同时继承多个对象,但是我们可以通过变通方法来实现。
function Fn(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
function Fun(){
this.car = '宝马';
this.lou = '别野'
}
Fn.prototype.car = function(){
console.log('我是有一辆小汽车')
}
Fn.prototype.dog = function(){
console.log('家有恶犬')
}
var f = new Fn('沾伞',18,'难受')
console.log(f)
function Son(name,age,sex){
Fn.call(this,name,age,sex)
Fun.call(this);
}
//对Fn函数的原型对象进行遍历 将Fn原型对象中的每个属性或方法 添加至 Son的原型对象中
// for(var i in Fn.prototype){
// Son.prototype[i] = Fn.prototype[i];
// }
// Son.prototype.constructor = Son;
var s = new Son('请问',21,'在撒的');
s.__proto__.car = 123;
console.log(s)