版权声明:本文为博主原创文章,未经博主允许不得转载。
/*(JavaScript高级程序设计读书笔记)
javascript继承
author:shine
*/
谁都知道封装,继承,多态是JAVA语言的三大性质,javascript虽然不是纯的JAVA语言,但它也有继承机制。
那么我们就来看看它是如何实现的吧。
一、继承的方式。
1、对象冒充:
1)单继承的对象冒充:
如:
function Class1(name) {
this.name = name;
this.sayHello = function() {
alert("hello!"+this.name);
}
}
function Class2(name,sal) {
// 以下a.b.c三步就是对象冒充方式的核心代码
this.newMethod = Class1; //a
this.newMethod(name); //b
delete this.newMethod; //c
this.sal = sal;
this.showSal = function() {
alert(name+ "的工资是"+this.sal);
};
}
var test = new Class2("yaoyao",10000);
test.sayHello(); //output:hello!yaoyao
test.showSal(); //output:yaoyao的工资为10000
小结:
冒充对象方式:三步完成。
a.用指针指向父类函数Class1。
b.调用函数此指针的方法(有参数就传,没有就不传,但是一定要调用此方法),这就能使父类的方法
和属性成为子类的方法和属性。
c.删除指针的引用。
2)多继承的对象冒充
function Class1() {
this.showClass1 = function() {
alert("showClass1");
}
}
function Class2() {
this.showClass2 = function() {
alert("showClass2");
}
}
function Class3() {
this.newMethod = Class1; //继承Class1
this.newMethod();
delete this.newMethod;
this.newMethod = Class2; //继承Class2
this.newMethod();
delete this.newMethod;
}
var test = new Class3();
test.showClass1();
test.showClass2();
小结:
对象冒充实现多继承时有个问题,就是当Class1和Class2中的方法或属性有同名时,按照javascript的执
行顺序是后面的优先,也就是Class2优先。
总结:
传统的对象冒充是以构造函数方式来声明类的。
2.call()方法。
1)call的普通用法:
如:
function favoriteColor(name){
alert(this.color + "是" + name + "的最爱");
}
var obj = new Object();
obj.color = "棕黄色";
sayColor.call(obj,"yaoyao"); //output:深棕色是yaoyao的最爱。
小结:
a.方法名.call() 有两个参数,第一个参数是指在哪个对象里用该方法(即:用哪个对象的资源),第二个
参数就是该方法的参数列表。(有几个写几个)。
b.call()方法并不是把方法放入某个指定的对象中,而是借用某个对象中的资源(如上例中的this.color)
来调用这个方法。
2)call的经典用法
如:
function Class1(name) {
this.name = name;
this.sayHello = function() {
alert("hello!" + this.name);
}
};
function Class2(name,sal) {
//this.newMethod = Class1;
//this.newMethod(name);
//delete this.newMethod;
Class1.call(this,name); //把三步简化为一步。
this.sal = sal;
this.showSal = function() {
alert(this.name + "的工资:"+this.sal);
}
}
var test = new Class2("yaoyao",10000);
test.sayHello(); //output:hello!yaoyao
test.showSal(); //output:yaoyao的工资是10000
3.apply()方法。
1)apply的普通用法:
function favoriteColor(num,name) {
alert("编号为"+num+"的同学"+name + "最喜欢的颜色是"+this.color);
}
var obj = new Object();
obj.color = "棕黄色";
favoriteColor.apply(obj,new Array("1","yaoyao")); //output:编号为1的同学yaoyao最喜欢的颜色是棕黄色
小结:
apply方法唯一的不同就是以一种数组对象的形式来传参数,有人会问那不是还麻烦些么,有了call还要
apply干嘛,呵呵继续看下去,你就会知道啦。
2)apply的经典用法:
function Class1(name) {
this.name = name;
this.sayHello = function() {
alert("hello!" + this.name);
};
};
function Class2(name,sal) {
//this.newMethod = Class1;
//this.newMethod(name);
//delete this.newMethod;
Class1.apply(this,arguments); //没错就是用到arguments对象
this.sal = sal;
this.showSal = function() {
alert(this.name + "的工资:"+this.sal);
};
};
小结:
看上去似乎apply加上arguments后,又比call强些,其实这里有“猫腻”,arguments是函数的参数列表对象
,如上例中的arguments指的是name,sal,那么Class1不是只要一个参数name么,没错,确实是传过
去了两个参数,但javascirpt并不做参数的检查,所以Class1会顺着取传过来的第一个参数,即name。
由此看来,使用apply加arguments时,必须使两个函数的参数顺序相同。
4.原型链
如果说上面的对象冒充,call,apply是以构造函数方式声明类,那么从名字上就应该猜到原型链自然是
以原型方式声明类。
如:
function Class1() {};
Class1.prototype.color="red";
Class1.prototype.showColor = function (){
alert(this.color);
};
function Class2() {};
Class2.prototype = new Class1(); //关键在这里
var test = new Class2();
test.showColor();
小结:既然是原型方式,那么一样也存在着同样的问题,构造函数不能带参数。
5* 继承中同名问题。
1)
function Class1() {};
Class1.prototype.color="red";
Class1.prototype.showColor = function (){
alert(this.color);
};
function Class2() {};
Class2.prototype = new Class1(); //a
Class2.prototype.color = "green"; //b 观察1) 2) 中a.b两句的顺序,和输出的结果
var test = new Class2();
test.showColor(); //output:green
2)
function Class1() {};
Class1.prototype.color="red";
Class1.prototype.showColor = function (){
alert(this.color);
};
function Class2() {};
Class2.prototype.color = "green"; //b
Class2.prototype = new Class1(); //a
var test = new Class2();
test.showColor(); //output:red
小结:
你现在一定在思考为什么吧?
a.在例1中的现象是因为javascirpt中是先查找该类中所有属性和方法,如果没找到,就找该类prototype中
的类(例1中的Class1)的属性和方法,如果还找不到,就找Class1中prototype中的类的属性和方法,如
此循环下去。
b.在例2中的现象是因为所有函数的prototype都只有一个,既然a句在b句之后,所以a就把b中的同名方
法覆盖掉了。(例1从这个角度也可以解释)
6.混合方式
可能有人猜得到这就是"构造函数/原型方式" 加上了“继承” ,使用“对象冒充”来继承属性,使用“原型链”来
继承方法。这样即能排除使用“对象冒充”带来的函数的多余定义,又能避免“原型链”带来的无法带入参数
的弊端。
如:
function Class1(color){
this.color = color;
}
Class1.prototype.showColor = function (){
alert(this.color);
}
function Class2(color,name){
Class1.call(this,color); .//用“对象冒充”继承属性
this.name = name;
}
Class2.prototype = new Class1(); //用“原型链”继承方法
Class2.prototype.showName = function() {
alert(this.name);
}
var test = new Class2("red","yaoyao");
test.showColor();
test.showName();