分享

javascript 面向对象编程 function也是类

 yiyiyicz 2012-11-09
        function在javascript中用来创建函数或方法,但要想实现面向对象方式的编程,类是不可或缺的角色之一,而且是主角。
        但javascript中并没有类概念,所谓的类也是模拟而来,通过函数加闭包模拟出类成员及私有成员。这里我们将用比较平实的方式来了解一下javascript中的”类”,避开一些生硬的原理。
        既然是用function来模拟类,所以编写代码创建类的关键字还是function。我们创建一个座标点类。
  1.     function Point() {
  2.       this.X = 0;
  3.       this.Y = 0;
  4.     };
  5.     var zeroPoint = new Point();
  6.     alert("当前座标值( X:" + zeroPoint.X + " , Y:" + zeroPoint.Y + " )");
复制代码

        大家都知道非静态类成员的访问需要通过对象来完成,所以先new出了一个Point类型对象,再通过该对象完成X和Y轴座标值的访问。从语法上来说,javascript类对象的创建过程和C#等差不多,但实现机制却不相同。这里的new创建出了一个Object,后续的Point()函数执行时将其this指向了这个新的Object对象。Point中的this.X和this.Y是Point类的两个公共成员,所以Point的对象可以直接对它们进行访问。
        说到类成员或对象的成员,免不了要提到可访问性的问题。在javascript的类中,也有public成员和private成员之分,但究其细节却不尽相同。javascript私有成员也是些在类外部不可以通过对象进行操作的成员,其实在类的内部成员之间私有成员也不定能被访问。在类的内部一般只有私有成员和私有成员之间可以互相的访问,你可以认为其它成员权限不够不能操作这些隐私的东西,但如果你有特权,那就不一样了,管它私有公开照用不误。私有成员变量和普通变量声明一样,用var关键字,私有方法可以用var声明变量来接收方法对象,也可以像普通方法那样去构建。
  1.     function Lady() {
  2.       var age = 30;
  3.       var name = "菜花";

  4.       var think = function() {
  5.         alert("其实我今年" + age + "岁。");
  6.       };

  7.      function fancy(){
  8.         alert("幻想变成20岁。");
  9.      };
  10.      this.Introduce = function() {
  11.         alert("我叫" + name + " , 今年20岁。");
  12.       };
  13.     };

  14.     var younglady = new Lady();
  15.     alert(younglady.age);//结果undefined
  16.     younglady.think(); //不支持
  17.     younglady.fancy(); //不支持
复制代码
       上面是一个Lady类,age、think、fancy都是私有成员,think和fancy方法可以访问age和name,think和fancy两个方法也可以互相进行调用。但它们是私有的,所以创建出来的youngLady对象并不能调用到age、think和fancy,当然也不能调用到name。如果私有成员只能互相之间调用,其实也就失去了私有成员存在的意义。javascript提供特权成员可以建立外界和私有成员互通的桥梁。特权成员是公共成员的一种,公共成员有普通公共成员、特权成员和对象公共成员。
        特权成员就是在类中用this.XX的方式建立的成员,它们可以通过对象来被调用,它们也可以访问私有成员,可以建立私有成员被访问的通道。
  1.     function Lady() {
  2.       var age = 30;
  3.       this.Name = "菜花";
  4.       
  5.      var think = function() {
  6.         alert("其实我今年" + age + "岁。");
  7.       };

  8.        function fancy() {
  9.         alert("幻想变成20岁。");
  10.       };

  11.        this.Introduce = function() {
  12.         alert("我叫" + this.Name + " , 今年" + age + "岁。");
  13.       };
  14.     };
  15.      var younglady = new Lady();
  16.     younglady.Introduce(); //Introduce
复制代码

        普通公共成员的创建,不在类的里面来编码,而是通过类的prototype来创建。添加普通公共成员都直接添加到类的prototype中,而prototype就是一个像JSON对象一样的成员集对象。当我们进行对象创建时,可以认为会将类prototype中的成员整体copy入新的Object对象中。
  1.     var younglady = new Lady();
  2.     younglady.Introduce(); //Introduce
  3.      Lady.prototype.Hobby = "上网";
  4.     Lady.prototype.GetName = function() {
  5.       return this.Name;
  6.     };
  7.     var lady2 = new Lady();
  8.     alert(lady2.GetName());
  9.     alert(lady2.Hobby);
复制代码
       上面代码通过prototype为Lady类添加了普通公共成员GetName方法和Hobby属性,因为是公共成员,所以它们可以和原先定意在类中的特权成员进行互相访问。因为公共成员可以互相访问。对上述代码做些修改。如下。
  1.     var younglady = new Lady();

  2.      Lady.prototype.Hobby = "上网";
  3.     Lady.prototype.GetName = function() {
  4.       return this.Name;
  5.     };

  6.     alert(younglady.GetName());
  7.     alert(younglady.Hobby);
复制代码
       先创建出Lady对象,再修改类成员,先前创建好的对象也具有了新的成员。这就是prototype做为类原型所带来的好处,这里简单理解,可以认为prototype是类对象的模版,模版的修改会影响到所有该类对象。
        在添加普通成员的时候也可以来个批量的添加,直接用一个新的JSON对象来赋给prototype就可以了。但是要注意,现在是将原先的prototype进行了替换,在替换之前创建的对象引用的是旧的prototype对象,所以对prototype替换之前创建的对象不会有Hobby和GetName成员。
  1.     Lady.prototype = {
  2.       Hobby: "上网",
  3.       GetName: function() {
  4.         return this.Name;
  5.       }
  6.     };
  7.     var younglady = new Lady();
  8.     alert(younglady.GetName());
  9.     alert(younglady.Hobby);
复制代码
     除了在构建类时可以添加公共成员,还可以对对象直接进行成员操作。做一下补充,对对象直接添加的成员,也是一种公共成员,这些成员也可以和类中原先具有的公共成员进行访问。
  1.     younglady.SetName = function(name) {
  2.       this.Name = name;
  3.     };
  4.     younglady.SetName("菜明");
  5.     alert(younglady.GetName());
复制代码

 

JavaScript为对象原型prototype添加属性的两种方式
为对象原型prototype添加属性的的方法,

  1. <script type="text/javascript">
  2. <!--
  3. /*
  4. 给原型 prototype 添加属性的两种方式
  5. */
  6. //方式一
  7. var myObj = function(){
  8. this.study = "JavaScript";
  9. }
  10. myObj.prototype.hobby = function()
  11. {
  12. this.hobby = "See girl";
  13. }
  14. var newObj = new myObj();
  15. for ( var attr in newObj )
  16. {
  17. document.write( attr +"<br/>" );
  18. }
  19. document.write( "==================== <br/>" );
  20. //方式二
  21. var superObj = { name:"xugang" };
  22. var subObj = { age:20 };
  23. function extend(superObj,subObj){
  24. //获得父对象的原型对象
  25. subObj.getSuper = superObj.prototype;
  26. //将父对象的属性给子对象
  27. for(var i in superObj){
  28. subObj[i] = superObj[i];
  29. }
  30. }
  31. extend(superObj,subObj);
  32. for ( var s in subObj )
  33. {
  34. document.write( s +"<br/>" ); //遍历子对象的属性
  35. }
  36. //-->
  37. </script>
复制代码

运行结果:
hobby
study
====================
age
getSuper
name

javascript 对象定义方法
工厂模式
初级开发者可能会这样定义对象

  1. var obj = new Object();
  2. obj.name = "hero";
  3. obj.showName=function (){alert(this.name);}
复制代码


这里存在一个问题就是如果我们要在多个地方用obj对象,可能在程序中类似的代码要写好多遍,于是产生了工厂方法

  1. function createObj()
  2. {
  3. var obj = new Object();
  4. obj.name="hero";
  5. obj.showName=function (){alert(this.name);}
  6. return obj;
  7. }
  8. var obj1 = createObj();
  9. var obj2 = createObj();
复制代码


和另外一种方法 构造函数法

  1. function obj (name)
  2. {
  3. this.name=name;
  4. this.showName= function (){alert(this.name);}
  5. }
复制代码


把生成对象的代码封装起来,避免出现重复new的代码,当然也可以进一步改进,就是createObj传递一些参数,而不是给obj赋默认固定值:

  1. function createObj(name)
  2. {
  3. var obj = new Object();
  4. obj.name=name;
  5. obj.showName=function (){alert(this.name);}
  6. return obj;
  7. }
  8. var obj1 = createObj("hero");
  9. var o'b'j2=createObj("dby");
复制代码


但是存在一个问题,就是我们每次调用createObj函数都会创建新的函数 showName.意味着每个对象都有自己版本的showName,所以要改进避开这个问题.

  1. function showName()
  2. {
  3. alert(this.name)
  4. }
  5. function createObj(name)
  6. {
  7. var obj = new Object();
  8. obj.name=name;
  9. obj.showName=showName;
  10. return obj;
  11. }
复制代码


这样就解决了 重复创建函数的问题, 哈哈哈,大功告成 .


原型方式:
主要是利用对象的prototype属性.

  1. function obj()
  2. {}
  3. obj.prototype.name="hero";
  4. obj.prototype.showName=function()
  5. {
  6. alert(this.name);
  7. }
复制代码


看起来似乎比刚才的工厂还完美,但是 有一个问题,该函数没有构造函数,属性是通过prototype指定的,这一点在实际应用中很让人头疼,所有的实例的属性都一样实在是不能让人接受.尤其还存在一个安全隐患,那就是当对象中有引用时,例如 加上这样一段
obj.prototype.nameArray = new Array("hero","dby");
然后
obj1 = new obj();
obj2 = new obj();
obj1.nameArray.push("lxw");
在obj2的nameArray中将也会看到这个属性,因为两个对象的nameArray指向的是同一个引用.
所以这种方式并不是理想方法.
需要 改进
结合构造函数,在构造函数定义属性,用原型定义方法
例如

  1. fuction obj(name)
  2. {
  3. this.name = name
  4. this.nameArray = new Array("hero","dby");
  5. }
  6. obj.prototype.showName = function(){alert(this.name)}
复制代码


所有的非函数属性都在构造函数里创建,函数属性用prototype方式创建,obj1 中改变nameArray的值,不会影响到obj2对象的nameArray的值, 而且只有一个showName函数,所以没有内存浪费.
基本上完美了,剩下的基本都是一下其他的修饰了.有兴趣的可以自己改着玩玩.
笔者在这里加上一个单例 玩了一下:

  1. function obj (name)
  2. {
  3. this.name = name;
  4. this.nameArray=new Array("hero","dby");
  5. if(typeof obj._initialized=='undefined')
  6. {
  7. obj.prototype.showName=function(){alert(this.name);}
  8. obj._initialized="true";
  9. }
  10. }
复制代码


其实不算是单例, 只不过是在构造对象的时候,先判断一个属性是否被定义,如果没有定义,那么用原型方法继续定义对象,如果已经定义了属性,那么就不在重复定义函数了. 该prototype方法只被创建一次,病赋值一次.
又差不多完美了,大功告成 .
这是个人的理解,,希望对大家有帮助,不完善的地方请qq联系,及时改正。
这是一个完整的实例:

  1. function Rectangle(name,color,width,heigth){
  2. this.name=name;
  3. this.color=color;
  4. this.width=width;
  5. this.heigth=heigth;
  6. }
  7. Rectangle.prototype.area=function(){
  8. return this.width*this.heigth
  9. }
  10. Rectangle.prototype.show=function(){
  11. document.write(this.name+" "+this.color+" "+this.width+" "+this.heigth+"<br/>");
  12. document.write(this.area());
  13. }
  14. var obj1= new Rectangle("Rectangle","red",15,20);
  15. obj1.show();
复制代码
 
下面看看实际应用:函数调用、继承、鼠标坐标显示(在VBA编辑器中编程)
读下面的代码需要基础,可参考:excel专业开发、VBA高级开发指南、API的资料等
函数调用的两个实例(lipton 和 ljw990485)
lipton兄采用的接口implements的方法
http://club./thread-938632-2-1.html

对于两个对象(函数),择其一处理


  1. Dim clsM As Class1 '//〖在类模块中定义方法,用于class1和class2〗//
  2. Dim cls1 As class2 '//〖在类模块中定义第一个函数〗//
  3. Dim cls2 As Class3 '//〖在类模块中定义第二个函数〗//
  4. Dim i As Long, j As Long
  5. Dim brr As Variant
  6. Set cls1 = New class2
  7. Set cls2 = New Class3
  8.     j = 1
  9.     brr = Sheet1.Range("a1:i1").Value
  10.     Do Until j = 3 '某种循环条件
  11.     
  12.         If j Mod 2 = 1 Then '某种判断式或子程序传回的标志
  13.             Set clsM = cls1
  14.             clsM.data = brr
  15.             Sheet1.Range("k1").Value = clsM.add '相同接口,计算方式累加
  16.             Set clsM = Nothing
  17.         Else
  18.             Set clsM = cls2
  19.             clsM.data = brr
  20.             Sheet1.Range("k2").Value = clsM.add '相同接口,计算方式结合成字符串
  21.             Set clsM = Nothing
  22.         End If
  23.         j = j + 1
  24.     Loop

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多