JavaScript继承
六种继承:
- 原型链继承
- 构造继承
- 实例继承
- 拷贝继承
- 组合继承
- 寄生组合继承
继承则必须有父类,子类继承父类的属性和方法。
一、原型链继承
1、什么是原型链?
由外到内通过__proto__属性连接所形成的链式即为原型链。
原型链继承是通过prototype属性实现继承。
2、原型链继承的特点
实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。
3、原型链继承的缺点
(1)不能继承子类的原型属性和方法;
(2)只能进行单继承,不能多继承;
(3)继承之后,原型对象上的属性全是共享;
(4)子类不能直接向父类传递参数。
4、实现
//父类
function Person(a) {
this.name = a;
this.age = null;
this.sex = "男";
this.sleep = function () {
return "睡觉";
}
}
Person.prototype.height = 100;
//子类
function Child() {
this.job = null;
}
Child.prototype.eat = function () {
return "吃饭";
}
var child = new Child();
var child1 = new Child();
console.log(child, child1);
console.log(child instanceof Child); //true
console.log(child instanceof Person); //true
二、构造继承
构造继承通过使用call和apply来实现继承。
1、构造继承的优点
(1)可以实现多继承;
(2)可以向父类传递参数。
2、构造继承的缺点
(1)构造继承无法继承父类的原型属性和方法;
(2)子类的实例是本身不是父类。
3、实现
//父类
function Animal() {
this.name = arguments[0];
this.sleep = function () {
return "睡觉";
}
}
Animal.prototype.color = null;
//父类
function Type() {
this.type = arguments[0];
}
//子类
function Dog(n, s, t) {
this.sex = s;
this.eat = function () {
return "吃饭";
}
//写构造继承
Animal.call(this, n);
Type.apply(this, [t]);
}
Dog.prototype = {
constructor: Dog,
sleep: function () {
}
}
var dog = new Dog("小花", "公", "犬科");
console.log(dog);
console.log(dog instanceof Dog);//true
call(this,arg1,arg2) ;当后面参数个数确定时用call,参数之间用逗号连接。
apply(this,[arg1,arg2]);当后面参数个数不确定时用apply,参数通过数组形式输入。
三、实例继承
1、实例继承:
在子类内部直接构造父类的实例,即直接new父类。
2、实例继承的优点
(1)不限制调用方式;
(2)可以向父类传递参数。
3、实例继承的缺点
(1)不能实现多继承;
(2)不能拿到子类构造属性和方法;
(3)子类的实例不是本身而是父类。
4、实现
//父类
function Person(n,s){
this.name=n;
this.sex=s;
this.sleep=function (){
return "睡觉";
}
}
//子类
function Child(n,s){
this.eat=function (){
}
return new Person(n,s);
}
//子类实例有两种写法
var child=Child("小米","男");
console.log(child);
var child1=new Child("小米","男");
console.log(child1);
//子类对象的实例
console.log(child instanceof Child);//false
console.log(child instanceof Person);//true
四、拷贝继承
1、拷贝继承:
将父类里的方法和属性拷贝给子类。
2、拷贝继承的优点
(1)支持多继承;
(2)子类对象实例是本身不是父类;
(3)可以向父类传递参数。
3、拷贝继承的缺点
在继承时,不断的new,容易占内存。
4、实现
//父类
function Animale(){
this.name=arguments[0];
this.sleep=function (){
return "睡觉";
}
}
//父类
function Type(){
this.type=arguments[0];
}
//子类
function Cat(n,s,t){
this.sex=s;
this.eat=function (){
return "吃饭";
}
//实例化父类对象
var animale=new Animale(n);
for(var key in animale)
{
Cat.prototype[key]=animale[key];
}
var type=new Type(t);
for(var key in type)
{
Cat.prototype[key]=type[key];
}
}
var cat=new Cat("小花","公","猫科");
console.log(cat);
//子类对象的实例是本身,不是父类
console.log(cat instanceof Cat);//true
console.log(cat instanceof Animale);//false
console.log(cat instanceof Type);//false
五、组合继承
1、组合继承
将原型链和构造函数的技术组合在一块,相互弥补双方的缺点。
2、组合继承的优点
(1)子类的实例既是本身也是父类;
(2)可以实现多继承;
(3)可以向父类传递参数;
(4)每个新实例引入的构造函数属性是私有的,没有实现原型对象属性的共享。
3、组合继承的缺点
调用了两次父类构造函数,子类的构造函数会代替原型上的那个父类构造函数。
4、实现
//父类
function Person(n){
this.name=n;
this.eat=function (){
return this.name+"吃饭";
}
}
Person.prototype={
constructor:Person,
color:null
}
//子类
function Child(a,s,n){
this.age=a;
this.sex=s;
this.sleep=function (){
return "睡觉";
}
Person.call(this,n); //只能获取到父类的属性和方法,拿不到原型属性和方法
}
Child.prototype=new Person();//注意这 这里没传值,"花花");
console.log(child.eat());
var child1=new Child(12,"女","小红");
console.log(child1);
console.log(child instanceof Child);//true
console.log(child instanceof Person);//true
六、寄生组合继承
1、寄生组合继承
寄生:在函数内返回对象然后调用。处理组合继承的缺点。
2、寄生组合继承的特点
避免调用两次父类的构造函数。
3、寄生组合继承的原理
原理:将父类的原型对象给一个空对象的prototype,再把空对象和子类的原型对象关联。
4、实现
//父类
function Person(){
this.name=null;
this.sleep=function (){
return this.name+"睡觉";
}
}
Person.prototype={
constructor:Person,
color:null
}
//子类
function Child(){
this.age=null;
this.eat=function (){
return this.name+"吃饭";
}
Person.call(this);
}
//开始寄生
(function (){
var fn=function (){};
fn.prototype=Person.prototype;
Child.prototype=new fn();
})();
var child=new Child();
console.log(child);
console.log(child instanceof Child);//true
console.log(child instanceof Person);//true