zoukankan      html  css  js  c++  java
  • Classes in JScript – Part III 类的继承与封装

    原文地址Classes in JScript – Part III: Class Hierarchy and Data Encapsulation

    原文发表日期】Published Wednesday, October 31, 2007 8:10

    在这篇博客中,我们将会来讨论如何在Jscript中实现类的继承与封装。

    我仍然会使用之前第一部分第二部分文章中所使用的示例代码,并按需要来修改它们。

    function Rectangle (ht, wt) {

                    this.height = ht;

                    this.width=wt;

    }

    Rectangle.prototype.area = function() {return this.height * this.width;}

    var rect1 = new Rectangle(5,10);

    var rect2 = new Rectangle(2,4);

    var rect1Area = rect1.area(); // rect1.area() will return 50.

    var rect2Area = rect2.area(); // rect2.area() will return 8.

    在支持而向对象的语言中都会有两个不同而有联系的概念:类和实例。在第一篇文章中,我们定义的类是对象的框架结构,在类中定义了对象所拥有的字段属性,类别和对对象进行操作的方法。类是一个抽象的概念,一个类可以拥有很多不同的实例,每个实例都有自己不同的状态。

    但是,基于prototype 的语言(比如:JScript),并没有对类和实例进行区分。这种语言中只有对象(objects)的概念。基于prototype的语言中,都提供了一个prototype对象,这个对象可以为新对象提供初始化属性的模板。任何对象都可以给prototype属性赋不同的值。

    在支持Class的语言中,类的继承关可以通过类的来定义。定义类的时候,我们可以指定它继承于一个已经存在的类。

    前面的文章中已经介绍过了,在Jscript中并不支持Class关键字(来定义类)。它是通过Constructor和Prototype对象来模拟类。因此,类的继承也可以通过Constructor和Prototype来实现。

    让我们扩展上类的例子,定义一个带有坐标的Rectangle。理论上,我们可能需要定义8个点(topLeftX, topLeftY, topRight(X & Y),bottomLeft(X & Y) and bottomRight(X & Y) )才能完全定位坐标,但是我们这里将它简化一下,只需要前面两个。

    定义PositionedRectangle:

    function PositionedRectangle (topLeftX,topLeftY,height,width) {

                    this.topLeftX = topLeftX;

                    this.topLeftY = topLeftY;

    }

    修改PositionedRectangle的prototype值为Rectangle的一个实例。

    PositionedRectangle.prototype = new Rectangle;

    类似的,我们可以创建一个PositionedRectangle对象。

    var prObj = new PositionedRectangle(2,3,4,5);

    prObj创建的时候,它会从Rectangle类中继承height和width,因为我们修改了PositionedRectangle的值为Rectangle的一个实例。

    通过下面的代码,我们可以看到topLeftX,topLeftY,height,width不同的值:

    alert(prObj.topLeftX+" "+ prObj.topLeftY+" "+ prObj.height+" "+ prObj.width);

    // 显示 2 3 undefined undefined

    因为Rectangle的height 和 width,未被赋值,所以我们看到它们的值是undefined。这就是以上做法的不完善的地方。如果我们像下面这样在构造器中给height和width属性设置默认值:

    function Rectangle () {

                    this.height = 1;

                    this.width=1;

    }

    这样的结果会是2 3 1 1。但是它不是我们希望的结果,因为参数值未被传递下来。

    为了解决这个问题,我们可以往构造器中添加一些代码:

    function PositionedRectangle (topLeftX,topLeftY,height,width) {

                    this.topLeftX = topLeftX;

                    this.topLeftY = topLeftY;

    //其中一种做法分别新建这两个属性

    this.height = height;

    this.width=width;

    //另一种做法是调用基类的构造器

    Rectangle(height,width);  (译注:2008/1/16更新 原代码的调用有误,应该是这样:Rectangle.call(this,height,width);   )

    }

    PositionedRectangle.prototype = new Rectangle;

    var prObj = new PositionedRectangle(2,3,4,5);

    alert(prObj.topLeftX+" "+ prObj.topLeftY+" "+ prObj.height+" "+ prObj.width);

    这样的输出结果会是2 3 4 5。这里我们做调用子类的一个普通法一样调用基类构造器,来设置正确的值。

    它是如何工作的?

    1. 首先,new操作符会创建一个普通的对象,将它的prototype属性的值赋给PositionedRectangle.prototype.。

    2. New操作符传入一个新创建的对象给PositionedRectangle构造器,用this关键字来表示它。

    3. 接下来初始化topLeftX和topLeftX。

    4. 在新创建的对象作用域里调用Rectangle方法,来初始化height和width的值。

    5. 在PositionedRectangle构造器返回时,将新创建的对象赋值给prObj。

    如果我们以后创建一个PositionedRectangle的子类,那么就需要为子类的prototype属性赋值为PositionedRectangle的实例,然后在子类的构造器里像调用普通方法一样调基类的构造器。

    数据封装

    所谓的数据封装,就是说对象的数据成员只能内部访问,而通过一些公用的方法来暴露给外界。简单的说,就是外界无法直接访问和修改对象的属性。

    在Jscript中,默认情况下所有的成员都是公有的,不需要通过方法来访问和修改这些成员。像上面的例子:

    ect1.height = 10; //会将height的值修改为10

    那么我们该如何来封装成员呢?

    答案就是能过使用内嵌函数,而不要在对象成员前加this关键字。让我们来为Rectangle增加一个colour属性。我们要将colour定义为私有的,而通过公有函数来向对界开放。

    function Rectangle (ht, wt) {

                    this.height = ht;

                    this.width=wt;

                    var colour = null;  // colour now is a private member of this class.

                    this.setColour = setColour;

                    this.getColour=getColour;

    //These methods will be used to access / modify colour.

                    function setColour (passedColour) {

                                    colour =passedColour;

                    }

                    function getColour() {

                                    return colour;

    }             

    }

    ar rect1 = new Rectangle(5,10);

    rect1.setColour (“blue”); // 设置颜色为blue.

    alert(rect1.getColour); // 这里会弹出blue

    alert(rect1.colour) // 这里会弹出undefined

    Rect1.colour =”red”; /*这里并不会弹出任何错误,也不会修改原先的color属性的值,而是会在Rect1对象上创建一个公有的colour属性。 */

    alert(rect1.getColour); //这里仍然会弹出blue

    alert(rect1.colour) // 而这里则会弹出red.

    这就是我们定义私有成员,和通过公有方法来访问私有成员的途径。这样我们就可以达到封装数据的目的了。

    到这里所介绍的并不是在Jscript中实现类的全部,但是做为一个开始已经是足够了。希望这个博客对你是有用的,并且你也喜欢阅读。

    这三篇就是我们计划在这个主题上的所有讨论了。这里还有一些有用的链接:

    http://www.webdevelopersjournal.com/articles/jsintro3/js_begin3.html

    http://dean.edwards.name/weblog/2006/03/base/

    http://www.crockford.com/javascript/inheritance.html

    http://devedge-temp.mozilla.org/viewsource/2001/oop-javascript/

    谢谢,

    Ritesh

    SDET, JScript Team.

    阿不 http://hjf1223.cnblogs.com
  • 相关阅读:
    用Vue创建一个新的项目
    事件循环学习2
    事件循环学习笔记
    关于访问器属性
    bootstrap-datetimepicker时间控件
    前端的指导方针---css篇
    web移动端小tip,box-flex
    数组常用的几种方法
    ajax对一些没有接口的数据进行分析和添加方法
    JAVA静态代理和动态代理理解
  • 原文地址:https://www.cnblogs.com/hjf1223/p/956765.html
Copyright © 2011-2022 走看看