js面向对象编程------三大特征
- 封装
- 继承
- 多态
面向对象的三大特征对任意的面向对象语言都是具有的,只是表现形式不一样
面向对象的三大特征都是先从抽象这个概念出来的
- 封装:什么是封装
js提供有以下几种控制方法和属性的访问权限
- 公开级别:对外公开,在类的外部可以使用
- 私有级别:类本身可以访问,不对外公开,在类外部不可以使用
<html>
<head>
<script language="javascript">
function Person(name,agei,sal){
this.name=name; //公开的属性
var age=agei; //私有的属性
var salary=sal; //私有的属性
//在类中如何定义公开方法(特权方法),私有方法(内部方法)
//如果我们希望操作私有的属性,则可用公开方法实现
this.show=function(){
window.alert(age+" "+salary);
}
//私有方法,可以访问对象的属性,但不可以在类外部访问
function show2(){
window.alert(age+" "+salary);
}
}
var p1=new Person("顺平",20,50000);
window.alert(p1.name); //顺平
window.alert(p1.age); //undefined,age私有属性不能被访问
p1.show(); //这个是正确的
p2.show2(); //在类的外部不可以访问,因为他是私有的,这里会报错
</script>
</head>
<body></body>
</html>
特别强调:我们前面学习过,通过prototype给所有的对象添加方法,但是这种方式,不能去访问类的私有变量和方法
<html>
<head>
<script language="javascript">
function Person(){
this.name="abc"; //公开的属性
var age=90; //私有的属性
this.abc1=function(){
window.alert("可以调用公开方法abc1");
}
function abc2(){
window.alert("不可以调用私有方法abc2");
}
}
//通过prototype给所有的对象添加方法,但是这种方式,不能去访问类的私有变量和方法
Person.prototype.fun1=function(){
window.alert(this.name); //这是OK的
//window.alert(age); //这是错误的,undefined
this.abc1(); //这是OK的
abc2(); //这是错误的
}
var p1 = new Person();
p1.fun1();
</script>
</head>
<body></body>
</html>
- 继承:代码复用
继承是很重要的
<html>
<head>
<script language="javascript">
function MidStu(){ //中学生
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+" "+this.age);
}
//计算学费
this.payfee=function(money){
window.alert("应缴:"+money*0.8);
}
}
function PupilStu(){ //小学生
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+" "+this.age);
}
//计算学费
this.payfee=function(money){
window.alert("应缴:"+money*0.5);
}
}
</script>
</head>
<body></body>
</html>
上面的代码中出现冗余,怎么解决这个问题呢?
那就是继承(对象冒充),看下面的代码:
<html>
<head>
<script language="javascript">
//怎么解决代码冗余问题,这就要用到继承
//抽象出一个学生类,即把中学生和小学生的共性取出
function Stu(name,age){ //小学生
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+" "+this.age);
}
}
function MidStu(name,age){
window.alert(Stu);
this.stu=Stu; //这里的Stu是什么? 它实际上就是Stu的构造函数
//把Stu的构造函数交给了MidStu的stu属性(方法),也就可以在下面调用stu这个方法了
//其实可以像下面这样理解:
/* this.stu=function Stu(name,age){ //小学生
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+" "+this.age);
}
}
*/
this.stu(name,age); //js中实际上是通过对象冒充,来实现继承的,
//这句话绝对不能少,少了这句话就没有继承了
//这句话如果不写的话,相当于没有赋值
//主要原因就是因为 js 是动态语言
}
function Pupil(name,age){
this.stu=Stu;
this.stu(name,age); //js中实际上是通过对象冒充,来实现继承的,
//这句话绝对不能少,少了这句话就没有继承了
}
var midstu = new MidStu("顺平",20);
window.alert(midstu.name); //如果不写this.stu(name,age); 这句话会出现什么呢? undefined
midstu.show();
</script>
</head>
<body></body>
</html>
对于上面的代码,我们再来细说下 这句话 this.stu(name,age);
如果在 MidStu 类中只写了 this.stu=Stu; 而没有写 this.stu(name,age);会发什么呢?
这个时候当执行 midstu.show(); 时,会报错,因为js是动态语言, this.stu=Stu ; 这句话之后,Stu确实赋值给了 this.stu,但是 js 语言没有执行的话,是不会给 stu 这个属性开辟空间的,
相当于你只声明了,而没有初始化,类似于下面的代码:
var a;
window.alert(a); //只声明,没有初始化,undefined
不会给stu这个属性开辟空间,也就相当于并没有 this.show=function(){ window.alert(this.name+" "+this.age); } 这个东西
所以当执行 midstu.show(); 时,会报 midstu.show(); 不是一个函数 这个错误
继承小结
javascript虽然没有extends关键字,但是它可以通过对象冒充的方式实现继承,而且可以实现多重继承
- 重载及覆盖
重载:js 中不支持重载,即不可以通过参数的个数,来决定调用哪个函数,但是因为 js 本身支持可变参数,所以,可以看成是天然支持重载
覆盖:子类可以重新写函数,覆盖掉父类的某个方法
案例:
<html>
<head>
<script language="javascript">
function Stu(name,age){ //小学生
this.name=name;
this.age=age;
this.show=function(){
window.alert(this.name+" "+this.age);
}
}
function MidStu(name,age){
this.stu=Stu; //这里的Stu是什么? 它实际上就是Stu的构造函数
this.stu(name,age); //js中实际上是通过对象冒充,来实现继承的
//MidStu可以覆盖Stu父类的show方法
this.show=function(){
window.alert("MidStu:show()");
}
}
var midstu = new MidStu("顺平",20);
midstu.show(); //调用 MidStu 自身的show方法,覆盖掉了父类的show方法
</script>
</head>
<body></body>
</html>
- 多态
js 天然支持 多态