一、继承相关概念
确认继承关系后:
- 子类的实例可以共享父类的方法
- 子类可以覆盖或扩展父类的方法
- 子类和父类都是子类实例的类型
二、继承的实现(常用几种)
- 对象冒充(构造函数绑定) 原理:使用对象冒充(call或apply方法)继承基类,实质上是改变了this指针的指向
// 1.构造函数绑定方式
function Monkey(_type,_home) {
this.type = _type;
this.home = _home;
this.say = function(){
alert("我是快乐的小猴子,家住"+this.home);
}
}
function Hero(_HP) {
this.HP = _HP;
}
//一个子类实现两个父类(属性、方法均可)
function Magic_monkey(_type,_home,arr,_HP){
// Monkey.call(this,_type,_home)
Monkey.apply(this,[_type,_home]) //注意apply与call不同处参数为数组
Hero.call(this,_HP)
this.skill = arr;
}
var wukong = new Magic_monkey('猴子','花果山',['七十二变','筋斗云'],1000)
alert(wukong.home)
alert(wukong.type)
alert(wukong.skill)
alert(wukong.HP)
wukong.say()
- 原型链(使用prototype属性)
-
prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
-
原型链的弊端是不支持多重继承。记住,原型链会用另一类型的对象重写类的 prototype 属性。
-
子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。
-
//2.原型链继承方式
// ~不支持多重继承。因为原型链会用另一类型的对象重写类的prototype属性
// ~子类的所有属性和方法都必须出现在prototype属性被赋值后。因为在它赋值前的所有方法都会被删除。
// 因为prototype属性被替换成了新对象,添加了新方法的原始对象将会被销毁
function Monkey2() { }
Monkey2.prototype.type = "猴子";
Monkey2.prototype.say = function(){
alert("我是一只快乐的小猴子")
}
function Magic_monkey2(){}
// 将Magic_monkey2的prototype对象指向一个Monkey的实例。
// 相当于删除了prototype对象原先的值,然后赋予一个新值。
Magic_monkey2.prototype.skill = "法术";
Magic_monkey2.prototype = new Monkey2();
var suWukong = new Magic_monkey2();
// alert(suWukong.type)
// suWukong.say()
// alert(suWukong.skill) //undefine , 属性必须在重写后定义
- 混合模式 创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。
function Monkey3(_type,_home){
this.type = _type;
this.home = _home;
}
Monkey3.prototype.say = function(){
alert("我是快乐的小猴子,家住"+this.home);
}
function Magic_mokey3(_type,_home){
//用对象冒充继承父类Monkey3的属性
Monkey3.call(this,_type,_home)
}
//用原型链继承父类Monkey3的方法
Magic_mokey3.prototype = new Monkey3()
var suXingzhe = new Magic_mokey3('猴子','水帘洞')
alert(suXingzhe.type)
alert(suXingzhe.home)
suXingzhe.say()
//总结:继承最好的方式就是,用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法