标签:javascript 面向对象 原型 prototype
原型prototype
JS中的方法分为三类:类方法,对象方法,原型方法
比如:一个类(Function,为对比java,以下统称为类)
function Parent(name){
this.name=name;
this.sayHello=function(){
alert(‘Hello,’+name);
}
}
Parent类中sayHello方法就是对象方法,类比java中的实例方法
那么我这样定义一个方法呢?
Parent.run=function(){
alert(‘run……’);
}
这样定义的方法是合法的,这样的方法(run)是类方法,类比java中的静态方法。
最后还可以这样定义方法:
Parent.prototype.eat = function(){
alert(‘eat too more!’);
}
这样也是合法的,这样的方法叫做原型方法。
接下来谈一谈如何调用这些方法,为方便记忆,这里也跟java作类比。
对象方法的调用:
与java相同,先有对象,然后再调用,比如:
var p1 = new Parent(‘张三’);
p1.sayHello();//打印 Hello,张三
类方法的调用:
依然与java相同,不需要创建对象,也可以直接调用,比如:
Parent.run();//打印 run……
注:java中一般类直接调用静态方法,但也可以使用实例来调用,只是不鼓励使用。js中使用实例是无法调用类方法的,这个需要牢记。
原型方法的调用:
最难理解的就是原型方法了,在java中似乎没有与之对应的元素在,其调用方法可以直接使用对象调用,比如:
p1.eat();//打印 eat too more!
也可以这样调用:
Parent.prototype.eat();//打印 eat too more!
那么原型究竟是个什么东西呢,如何进行类比呢?
既可以用类来调用,又可以用对象来调用,这个跟java中静态方法很像,java中虽然允许实例直接调用类方法,但不鼓励使用。而在JS中,是专门针对对象引入的原型,
而使用类直接调用原型方法就显得比较繁琐。这样看来,用类方法来类比原型方法也是说得通的。但要明白其间差别。
最后,用一个通俗的方式来描述原型,原型相当于在类中添加了一个容器,我们可以任意把方法和引用放置进去,使用对象调用的时候,会优先去实例中查找同名方法,如果
找不到则会去prototype方法中查找。也就是说,prototype是公用的(只有一个),只有类可以对其改变,改变之后所有的对象都可以进行引用。
出几个题,过把瘾先,对于上面的代码,添加几个功能。
Parent.sayHello= function(){
alert(‘Hello,Static Function’);
}
Parent.prototype.sayHello=function(){
alert(‘Hello,prototype,Function’);
}
这时候我的问题来了,使用如下方式调用分别打印什么?
p1.sayHello();
Parent.sayHello();
Parent.prototype.sayHello();
答案依次是:
Hello,prototype,Function //解释器会先去对象方法中查找方法,如果存在则直接使用,如果不存在,则去原型中查找
Hello,Static Function //不用多说,直接用类访问方法,只能访问到类方法
Hello,prototype,Function //这个似乎也不用多说,定义的时候就是这么定义的
下面一个简陋的表格:
方法类型| 调用方式 | 不可以如此调用 | 备注
——–|———————–|—————————|——————————————————————————
对象方法| obj.method(); | Class.method(); | 对象方法使用this定义,也可以obj.method2 = function(){}定义,但后者只能本对象可见
——–|———————–|—————————|——————————————————————————
类方法 | Class.Method(); | obj.method(); | 决不能只用对象调用类方法,这个与java区分开
——–|———————–|—————————|——————————————————————————
原型方法|obj.method(); | obj.prototype.method(); | 与对象方法重名时,对象方法会优先被调用
|Class.prototype.method;| |
——–|———————–|—————————|——————————————————————————
以下说一说继承那些事:
JS也是面向对象的,所有的数据都可以看做对象,很多东西不需要定义,直接拿来使用。而当需求高度抽象的时候,就会出现“面向过程编程”,代码冗长而不易懂。为了实现
面向对象的那些特性,我们就自定义一些类型,如上面定义的Parent,就是一个自定义类型。那么既然是面向对象了,就应该有面向对象的特性吧(封装,继承,多态)。封装就不用多说了,定义一个类型以后,所有的方法和属性都使用this来封装到类型中了(与java不同的是,js有一个原型,可以随时添加属性和方法,也可以使用类型直接添加静态的属性和方法),下面着重说一下继承和多态。
关于继承,网上有不少关于继承的方式,比如构造函数继承,原型继承,call和apply继承。
两个类:
function Parent(name){
this.name=name;
this.sayHello2Parent(){
alert(‘Hello,’+name);
}
}
function Child(name){
}
构造函数继承:
Child 类可以这样改造
function Child(name){
var p1 = new Parent();
p1.name=name;
p1.sayHello2Child=function(){
}
return p1;
}
var c1 = child(‘李四’);
这样c1具有了p1的属性和方法,且可以在Child方法中实现覆盖和隐藏。但这样的继承很明显入侵比较严重,Child方法需要进行改造,不可取。
原型继承:
Child.prototype = new Parent(‘张三’);//意思是把Parent的所有的属性和方法,拷贝给Child的原型(理解为放入其原型容器中)
Child.prototype.sayHello2Parent = function(){
alert(‘Hello,Child’);
}
这样就能够实现多态了,也就是父类型的同名方法被覆盖了。
那么如果想像java一样,调用父类的方法,如何操作呢?(java中使用super)
var p1 = new Parent(‘张三’);
var c1 = new Child(‘李四’);
p1.sayHello2Parent.call(c1);//这样可以调用到父类的方法了
最后说一说call和apply继承:
function Child(name){
Parent.call(this,name);
}
function Child(name){
Parent.apply(this,arguments);
}
以上说明了,对象方法和原型方法都可以实现继承和覆盖,现在有个问题,类方法可以实现继承和覆盖吗?
答案是:不能 这点跟java中的特性一样的,所有的static变量和方法是无法实现继承的,因此也不存在多态。
版权声明:本文为博主原创文章,未经博主允许不得转载。
戏说javascript原型(prototype)实现面向对象
标签:javascript 面向对象 原型 prototype
原文地址:http://blog.csdn.net/salerzhang/article/details/47043541