javascript面向对象技术基础(四)

看了很多介绍javascript面向对象技术的文章,很晕.为什么 不是因为写得不好,而是因为太深奥.javascript中的对象还没解释清楚怎么回事,一上来就直奔主题,类/继承/原型/私有变量。结果呢,看了大半天,有了一个大概的了解,细细一回味,好像什么都没懂。

这篇文章是参考<<javascript-the definitive guide,5th edition>>第7,8,9章而写成的,我也会尽量按照原书的结构来说明javascript的面向对象技术(对象/数组->函数-->类/构造函数/原型).对一些我自己也拿捏不准的地方,我会附上原文的英文语句,供大家参考.

类、构造函数、原型

先来说明一点:在上面的内容中提到,每一个函数都包含了一个prototype属性,这个属性指向了一个prototype对象,注意不要搞混了.

构造函数:

new操作符用来生成一个新的对象.new后面必须要跟上一个函数,也就是我们常说的构造函数.构造函数的工作原理又是怎样的呢?
先看一个例子:

Js代码

 
  1. functionPerson(name,sex){
  2. this.name=name;
  3. this.sex=sex;
  4. }
  5. varper=newPerson("sdcyst","male");
  6. alert("name:"+per.name+"_sex:"+per.sex);//name:sdcyst_sex:male

下面说明一下这个工作的步骤:

开始创建了一个函数(不是方法,只是一个普通的函数),注意用到了this关键字.以前我们提到过this关键字表示调用该方法的对象,也就是说通过对象调用"方法"的时候,this关键字会指向该对象(不使用对象直接调用该函数则this指向整个的script域,或者函数所的域,在此我们不做详细的讨论).

当我们使用new操作符时,javascript会先创建一个空的对象,然后这个对象被new后面的方法(函数)的this关键字引用!然后在方法中通过操作this,就给这个新创建的对象相应的赋予了属性.最后返回这个经过处理的对象.这样上面的例子就很清楚:先创建一个空对象,然后调用Person方法对其进行赋值,最后返回该对象,我们就得到了一个per对象.

prototype(原型)--在这里会反复提到"原型对象"和"原型属性",注意区分这两个概念.

在javascript中,每个对象都有一个prototype属性,这个属性指向了一个prototype对象.上面我们提到了用new来创建一个对象的过程,事实上在这个过程中,当创建了空对象后,new会接着操作刚生成的这个对象的prototype属性.

每个方法都有一个prototype属性(因为方法本身也是对象),new操作符生成的新对象的prototype属性值和构造方法的prototype属性值是一致的.构造方法的prototype属性指向了一个prototype对象,这个prototype对象初始只有一个属性constructor,而这个constructor属性又指向了prototype属性所在的方法,有点晕,看下面的图:

这样,当用构造函数创建一个新的对象时,它会获取构造函数的prototype属性所指向的prototype对象的所有属性.对构造函数对应的prototype对象所做的任何操作都会反应到它所生成的对象身上,所有的这些对象共享构造函数对应的prototype对象的属性(包括方法).

看个具体的例子吧:

Js代码

 
  1. functionPerson(name,sex){//构造函数
  2. this.name=name;
  3. this.sex=sex;
  4. }
  5. Person.prototype.age=12;//为prototype属性对应的prototype对象的属性赋值
  6. Person.prototype.print=function(){//添加方法
  7. alert(this.name+"_"+this.sex+"_"+this.age);
  8. };
  9. varp1=newPerson("name1","male");
  10. varp2=newPerson("name2","male");
  11. p1.print();//name1_male_12
  12. p2.print();//name2_male_12
  13. Person.prototype.age=18;//改变prototype对象的属性值,注意是操作构造函数的prototype属性
  14. p1.print();//name1_male_18
  15. p2.print();//name2_male_18

到目前为止,我们已经模拟出了简单的类的实现,我们有了构造函数,有了类属性,有了类方法,可以创建"实例".在下面的文章中,我们就用"类"这个名字来代替构造方法,但是,这仅仅是模拟,并不是真正的面向对象的"类".

在下一步的介绍之前,我们先来看看改变对象的prototype属性和设置prototype属性的注意事项:给出一种不是很恰当的解释,或许有助于我们理解:当我们new了一个对象之后,这个对象就会获得构造函数的prototype属性(包括函数和变量),可以认为是构造函数(类)继承了它的prototype属性对应的prototype对象的函数和变量,也就是说,prototype对象模拟了一个超类的效果.听着比较拗口,我们直接看个实例吧:

Js代码

 
  1. functionPerson(name,sex){//Person类的构造函数
  2. this.name=name;
  3. this.sex=sex;
  4. }
  5. Person.prototype.age=12;//为Person类的prototype属性对应的prototype对象的足球平台出租属性赋值,
  6. //相当于为Person类的父类添加属性
  7. Person.prototype.print=function(){//为Person类的父类添加方法
  8. alert(this.name+"_"+this.sex+"_"+this.age);
  9. };
  10. varp1=newPerson("name1","male");//p1的age属性继承子Person类的父类(即prototype对象)
  11. varp2=newPerson("name2","male");
  12. p1.print();//name1_male_12
  13. p2.print();//name2_male_12
  14. p1.age=34;//改变p1实例的age属性
  15. p1.print();//name1_male_34
  16. p2.print();//name2_male_12
  17. Person.prototype.age=22;//改变Person类的超类的age属性
  18. p1.print();//name1_male_34(p1的age属性并没有随着prototype属性的改变而改变)
  19. p2.print();//name2_male_22(p2的age属性发生了改变)
  20. p1.print=function(){//改变p1对象的print方法
  21. alert("iamp1");
  22. }
  23. p1.print();//iamp1(p1的方法发生了改变)
  24. p2.print();//name2_male_22(p2的方法并没有改变)
  25. Person.prototype.print=function(){//改变Person超类的print方法
  26. alert("newprintmethod!");
  27. }
  28. p1.print();//iamp1(p1的print方法仍旧是自己的方法)
  29. p2.print();//newprintmethod!(p2的print方法随着超类方法的改变而改变)

看过一篇文章介绍说javascript中对象的prototype属性相当于java中的static变量,可以被这个类下的所有对象共用.而上面的例子似乎表明实际情况并不是这样:

在JS中,当我们用new操作符创建了一个类的实例对象后,它的方法和属性确实继承了类的prototype属性,类的prototype属性中定义的方法和属性,确实可以被这些实例对象直接引用.但是,当我们对这些实例对象的属性和方法重新赋值或定义后,那么实例对象的属性或方法就不再指向类的prototype属性中定义的属性和方法,此时,即使再对类的prototype属性中相应的方法或属性做修改,也不会反应在实例对象身上.这就解释了上面的例子:

一开始,用new操作符生成了两个对象p1,p2,他们的age属性和print方法都来自(继承于)Person类的prototype属性.然后,我们修改了p1的age属性,后面对Person类的prototype属性中的age重新赋值(Person.prototype.age = 22),p1的age属性并不会随之改变,但是p2的age属性却随之发生了变化,因为p2的age属性还是引自Person类的prototype属性.同样的情况在后面的print方法中也体现了出来.

通过上面的介绍,我们知道prototype属性在javascript中模拟了父类(超类)的角色,在js中体现面向对象的思想,prototype属性
是非常关键的.

您可能感兴趣的文章:
J2ME Snake脚本引擎使用手册
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值