zoukankan      html  css  js  c++  java
  • JavaScript中的面向对象的讨论(转)

    前言

    今天,WEB2.0时代的到来,给了JavaScript又一次大展身手的机会。Web2.0借助JavaScript技术,使得客户端的Web体验更加丰富多彩,同时JavaScript面对的问题域也变得错综复杂起来,JavaScript代码也随着Web页面的多样化和功能的丰富而快速膨胀。以前的过程式的JavaScript开发方法已经不能适应Web2.0的开发需求,需要一种更先进的设计方法来指导JavaScript的开发,这就是这里我们要讨论的面向对象。

     

    面向对象概念的提出,是软件开发工程发展的一次革命,有了面向对象,很多复杂的大型应用程序的开发可以简化。可以说,有了面向对象,我们手里才得到了一把真正的利刃,可以得心应手的处理复杂而又规模庞大的问题域。

     

    面向对象的三个基本特征是:

    - 封装-把自己的数据和方法封装在对象内部,并让私有的数据和方法在对象外部不可见,而共有的数据和方法在对象外部可见。

    - 继承-在无需重新修改原来对象的前提下,让另一个对象获得原对象的属性和方法的能力

    - 多态-子类可以定义与父类具有相同signature的方法。

     

    因此我们就这三个基本特征展开JavaScript面向对象的讨论。

     

    基本概念

    JavaScript语言对对象提供了天然支持。数组(Array)是对象,函数(function)是对象。但是JavaScript不是一种真正意义上的面向对象语言。这是因为JavaScript并不具备完整的面向对象三个基本特征。

     

    在正式开始讨论之前,首先要对JavaScript的类,成员变量,成员函数,类变量,类方法这几个概念进行说明。

    Ÿ 类

    JavaScript中并没有类的概念,也就是说,JavaScript中并没有语法支持“类”。因此,JavaScript中的类其实都是使用function来模拟的。

    类的定义:

    1 function Circle(r){
    2   this.r = r;
    3 }

    类的实例化:var circle = new Circle(3);

     

    Ÿ 成员变量

    成员变量可以通过多种方式定义:

    构造器中: this.r = r;

    对象:circle.name="my circle";

     

    Ÿ 成员函数

    成员函数也可以通过多种方式定义:

    构造器中:

    1 function Circle(r){
    2   this.r = r;
    3   function sqr(){
    4     return r*r;
    5   }
    6 }

    prototype:

    1 Circle.prototype.getName=function(){
    2     return this.name;
    3 }

     

    Ÿ 类变量

    类变量是属于类的变量。就像java里用static声明的变量,可以直接用类就可以访问。由于类变量是属于类的,因此所有这个类的实例也可以访问这个变量。因此,任何实例都不应该修改类变量(JavaScript中没有类似java的final关键字使类变量不可变)。类变量与通过prototype定义的变量的功能类似,但是他们的访问方式不同。

    访问prototype变量:Circle.prototype.PI=3.14;

    访问类变量:Circle.PI=3.14;

     

    //使用prototype里的变量

    1 Circle.prototype.area1 = function(){
    2     return this.PI*this.r*this.r;
    3 }

    //使用类变量

    1 Circle.prototype.area2 = function(){
    2     return Circle.PI*this.r*this.r;
    3 }

    Ÿ 类方法

    类方法是直接在类上定义的方法。注意,在类方法中不能使用this关键字,就像是在java的static方法中,不能使用this一样。

    Circle.max = function(a,b){
        return a.r>b.r?a:b;
    }
    var maxCircle = Circle.max(new Circle(1),new Circle(2));

     

    面向对象的三个基本特性

    在有了上面的知识以后,下面就开始依据面向对象三个基本特征,对JavaScript的面向对象特性进行讨论。

     

    1. 封装

    JavaScript中,所有元素都可以认为是对象。这就是JavaScript对对象的天然支持。在JavaScript的对象里,还可以定义方法(function),数据变量(var)。这样,JavaScript对象可以把数据和方法封装在对象内部。

    JavaScript是如何实现对象数据的访问控制的呢?JavaScript跟别的面向对象语言一样,也是通过function和变量的不同的声明方式而实现访问控制的。

     

    Ÿ 公有成员

    对象的成员都是公有成员,任何函数都可以访问,修改或删除这些成员。有两种主要途径给对象添加公有成员:

    Ø 构造器:

    构造器中,使用this变量来向对象添加成员。注意,这里只是用this变量添加了属性成员。用this变量添加的function成员,而特权成员(见下文解释)而不是公有成员。

    1 function Container(param){
    2     this.member = param;
    3 }

    Ø 原型:

    使用prototype添加成员是很常用的一种给对象添加公共成员的方式:

    1 Container.prototype.stamp = function(string){
    2     return this.member+string;
    3 }

     

    Ÿ 私有成员

    私有成员要由构造器生成。构造器的参数,以及其中通过var声明成员都是私有成员。私有成员是无法被公有成员访问的。但是公有成员可以通过一些技巧来访问私有成员。例如,

     1 function Container(param){
     2     function dec(){
     3         if(secret>0){
     4             secret-=1;
     5             return true;
     6         }else{
     7             return false;
     8         }
     9     }
        this.member = param;
          var secret = 3;
          var self = this;
    10 }

    在上面的代码例子中,有三个私有成员:param,secret,self。它们在对象内部,并且在对象外部不能访问这三个成员,同时也不能被对象的公有方法访问。他们只对私有成员可见。

    这里有一个技巧,就是定义了一个私有的self变量。通过这个self变量,可以在让私有成员中访问公有成员。

     

    Ÿ 特权成员

    特权成员实际上是特指function成员。特权成员可以访问私有成员(变量和方法),同时它对公共域也是可见的。可以删除或替换一个特权成员,但是不能对他进行修改。

    特权方法是用this在构造器中定义的。

     1 function Container(param){
     2     function dec(){
     3         if(secret>0){
     4             secret-=1;
     5             return true;
     6         }else{
     7             return false;
     8         }
     9     } 
    10     this.member = param;
    11     var secret = 3;
    12     var self = this;
    13  
    14 //特权成员
    15 
    16     this.service = function(){
    17         if(dec()){
    18             return self.member;
    19         }else{
    20             return null;
    21         }
    22     };
    23 }

    上面的代码片段中,service方法就是一个特权成员。可以看到,在service方法中,调用了私有方法dec(),而dec又访问了私有变量secret.

    2. 继承

    JavaScript继承问题一直是网上被讨论最热烈的一个JavaScript问题。在详细讨论JavaScript的继承之前,我们先看一下“继承”的概念。

    继承,让子类具备父类的特性。继承,描述的是类型层面上而不是个体层面上的特性。因此,继承,只应该是描述类型的,也就是说,只能是类之间存在继承关系,而对象实体之间是不存在继承关系的。

    由于JavaScript并不是很清晰(类跟对象没有明显的区分),因此导致JavaScript中的继承实现要大费周折。很多人为JavaScript想出了各种各样的实现继承的方法,包括:构造器继承法,原型继承法,实例继承法,附加继承法。

    这里不去详细讨论每一种继承的实现思路。

    在《JavaScript权威指南1.5》中列出的是prototype继承。

    1 function SubCircle(x, y, r) { 
    2   this.x = x;
    3   this.y = y;
    4   this.r =r;
    5 } 
    6 SubCircle.prototype = new Circle(0);

    这种继承方式,会有一点问题,就是原来在SubCircle的prototype中定义的方法和属性丢失。

    在prototype1.5 framework中,通过属性复制定义另一中继承方式。核心概念就是把Circle的prototype中的所有成员复制到SubCircle中,这样可以确保SubCircle的prototype中的成员不会丢失,但是这样也有个问题,就是Circle中定义的公有成员,特权成员并没有被继承到SubCircle中。

    为了解决这个问题,可以综合上面两种继承的有点,进行如下的实现:

    3. 多态

    首先看一下例子:

    ///////////define: Cricle//////////////////
    
    function Circle(r) {
        this.r = r;
    }
    Circle.PI = 3.14;
    Circle.prototype.PI = 3.14;
    Circle.prototype.area = function() { return Circle.PI*this.r*this.r; }
    Circle.prototype.area2 = function() { return this.PI*this.r*this.r; } 
     
    //// test
    c = new Circle(3);
    //alert("area1 :"+c.area());
    //alert("area2 :"+c.area2());
    
     
    
    Circle.max = function(a, b) { return a.r>b.r ? a.r : b.r; }
    //alert("max is "+Circle.max(new Circle(1), new Circle(3)));
    
    c1 = new Circle(1);
    c2 = new Circle(1);
    c2.PI = 100;//Circle.prototype.PI=100;
    
    //alert("c1.area1 "+c1.area());
    
    //alert("c1.area2 "+c1.area2());
    
    //alert("c2.area1 "+c2.area());
    
    //alert("c2.area2 "+c2.area2());
    
     
    
    ////////////////////////define: SubCircle //////////////////
    
    function SubCircle(x, y, r) {
        this.x = x;
        this.y = y;
        this.r = r;
    }
    
    SubCircle.prototype = new Circle(0);
    SubCircle.prototype.PI = 100;
    SubCircle.prototype.move2 = function(x, y) { this.x = x; this.y = y;}
    SubCircle.prototype.area = function() { return this.PI*this.r*this.r*this.r; } 
    
    //// test
    
    sc = new SubCircle(0,0,2);
    alert(sc.area());
    

     

    调用sc.area()的执行顺序是:

    sc.PI->sc.prototype.PI->100;

    sc.area()->sc.prototype.area()->SubCircle(0,0,2).area()

    从上面的调用顺序可以看到,SubCircle的调用过程中,只要属性和方法在子类中存在,就完全用子类的属性和方法。

    如果要使用父类的属性和方法怎么办呢?这就要用到继承部分的支持。在继承的时候,子类的prototype中增加了一个属性superClass,这个superClass就是父对象的引用。因此就可以通过superClass调用父对象的属性和方法了。

     

    命名空间

    随着功能的增加,JavaScript代码也会变的越来越复杂,那么给JavaScript增加命名空间就显得尤为重要了。

    JavaScript语言中没有对命名空间提供直接的支持,因此只有通过模拟实现命名空间。具体实现是使用闭包特性,使JavaScript代码位于某些特定的Function内。下面是命名空间的代码片段:

     1 //最外层的包
     2 
     3 var laputa = {};
     4  
     5 //在laputa包内部定义了两个包:lang,util
     6 
     7 laputa.lang={};
     8 laputa.util = {};
     9  
    10 
    11 //在lang包里定义了String类,
    12 
    13 laputa.lang.String = {}; 
    14 
    15 //String类的trim方法
    16 
    17 laputa.lang.String.prototype.trim = function(){
    18     return this.replace(/(^s*)|(s*$)/g, ""); 
    19 };
    20 
    21 //String类的toUpperCase方法
    22 
    23 laputa.lang.String.prototype.toUpperCase = function(){
    24     return this.toUpperCase();
    25 }
    26 
    27 //在util包定义了DocumentUtil类
    28 
    29 laputa.util.DocumentUtil = {}; 
    30 
    31 //DocumentUtil类的$方法
    32 
    33 laputa.util.DocumentUtil.$ = function(id){
    34     return document.getElementById(id);
    35 }
    36 
    37 //DocumentUtil类的$v方法
    38 
    39 laputa.util.DocumentUtil.$v = function(id){
    40     var el = laputa.util.DocumentUtil.$(id);
    41     if(el){
    42         return el.value;
    43     }
    44     return null;
    45 }

     

  • 相关阅读:
    DVWA 黑客攻防演练(十)反射型 XSS 攻击 Reflected Cross Site Scripting
    DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)
    DVWA 黑客攻防演练(八)SQL 注入 SQL Injection
    DVWA 黑客攻防演练(七)Weak Session IDs
    DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA
    DVWA 黑客攻防演练(五)文件上传漏洞 File Upload
    工作流表结构设计
    Visual Studio 2019尝鲜----新建空项目体验
    《使用CSLA 2019:CSLA .NET概述》原版和机译文档下载
    .NET快速开发平台的在线预览
  • 原文地址:https://www.cnblogs.com/wolm/p/3307649.html
Copyright © 2011-2022 走看看