• JavaScript面向对象的支持(1)


    ================================================================================
    Qomolangma OpenProject v0.9


    类别    :Rich Web Client
    关键词  :JS OOP,JS Framwork, Rich Web Client,RIA,Web Component,
              DOM,DTHML,CSS,JavaScript,JScript

    项目发起:aimingoo (aim@263.net)
    项目团队:aimingoo, leon(pfzhou@gmail.com)
    有贡献者:JingYu(zjy@cnpack.org)
    ================================================================================


    八、JavaScript面向对象的支持
    ~~~~~~~~~~~~~~~~~~
    很少有人对JavaScript的面向对象特性进行系统的分析。我希望接下来的文字让你了解到这
    个语言最少为人知的一面。


    1. JavaScript中的类型
    --------
    虽然JavaScript是一个基于对象的语言,但对象(Object)在JavaScript中不是第一型的。JS
    是以函数(Function)为第一型的语言。这样说,不但是因为JS中的函数具有高级语言中的函
    数的各种特性,而且也因为在JS中,Object也是由函数来实现的。——关于这一点,可以在
    后文中“构造与析构”部分看到更进一步的说明。

    JS中是弱类型的,他的内置类型简单而且清晰:
    ---------------------------------------------------------
    undefined : 未定义
    number    : 数字
    boolean   : 布尔值
    string    : 字符串
    function  : 函数
    object    : 对象

     1). undefined类型
    ========================
    在IE5及以下版本中,除了直接赋值和typeof()之外,其它任何对undefined的操作都将导致
    异常。如果需要知道一个变量是否是undefined,只能采用typeof()的方法:
    <script>
    var v;
    if (typeof(v) == 'undefined') {
      // ...
    }
    </script>

    但是在IE5.5及以上版本中,undefined是一个已实现的系统保留字。因此可以用undefined来
    比较和运算。检测一个值是否是undefined的更简单方法可以是:
    <script>
    var v;
    if (v === undefined) {
      // ...
    }
    </script>

    因此为了使得核心代码能(部分地)兼容IE5及早期版本,Romo核心单元中有一行代码用来
    “声明”一个undefined值:
    //---------------------------------------------------------
    // code from Qomolangma, in JSEnhance.js
    //---------------------------------------------------------
    var undefined = void null;

    这一行代码还有一点是需要说明的,就是void语句的应用。void表明“执行其后的语句,且
    忽略返回值”。因此在void之后可以出现能被执行的任何“单个”语句。而执行的结果就是
    undefined。当然,如果你愿意,你也可以用下面的代码之一“定义undefined”。
    //---------------------------------------------------------
    // 1. 较复杂的方法,利用一个匿名的空函数执行的返回
    //---------------------------------------------------------
    var undefined = function(){}();

    //---------------------------------------------------------
    // 2. 代码更简洁,但不易懂的方法
    //---------------------------------------------------------
    var undefined = void 0;

    void也能像函数一样使用,因此void(0)也是合法的。有些时候,一些复杂的语句可能不能
    使用void的关键字形式,而必须要使用void的函数形式。例如:
    //---------------------------------------------------------
    // 必须使用void()形式的复杂表达式
    //---------------------------------------------------------
    void(i=1);       // 或如下语句:
    void(i=1, i++);


     2). number类型
    ========================
    JavaScript中总是处理浮点数,因此它没有象Delphi中的MaxInt这样的常量,反而是有这
    样两个常值定义:
      Number.MAX_VALUE  : 返回 JScript 能表达的最大的数。约等于 1.79E+308。
      Number.MIN_VALUE  : 返回 JScript 最接近0的数。约等于 2.22E-308。

    因为没有整型的缘故,因此在一些关于CSS和DOM属性的运算中,如果你期望取值为整数2,
    你可能会得到字符串“2.0”——或者类似于此的一些情况。这种情况下,你可能需要用
    到全局对象(Gobal)的parseInt()方法。

    全局对象(Gobal)中还有两个属性与number类型的运算有关:
      NaN      : 算术表达式的运算结果不是数字,则返回NaN值。
      Infinity : 比MAX_VALUE更大的数。

    如果一个值是NaN,那么他可以通过全局对象(Gobal)的isNaN()方法来检测。然而两个NaN
    值之间不是互等的。如下例:
    //---------------------------------------------------------
    // NaN的运算与检测
    //---------------------------------------------------------
    var
      v1 = 10 * 'a';
      v2 = 10 * 'a';
    document.writeln(isNaN(v1));
    document.writeln(isNaN(v2));
    document.writeln(v1 == v2);

    全局对象(Gobal)的Infinity表示比最大的数 (Number.MAX_VALUE) 更大的值。在JS中,
    它在数学运算时的价值与正无穷是一样的。——在一些实用技巧中,它也可以用来做一
    个数组序列的边界检测。

    Infinity在Number对象中被定义为POSITIVE_INFINITY。此外,负无穷也在Number中被定
    义:
      Number.POSITIVE_INFINITY  : 比最大正数(Number.MAX_VALUE)更大的值。正无穷。
      Number.NEGATIVE_INFINITY  : 比最小负数(-Number.MAX_VALUE)更小的值。负无穷。

    与NaN不同的是,两个Infinity(或-Infinity)之间是互等的。如下例:
    //---------------------------------------------------------
    // Infinity的运算与检测
    //---------------------------------------------------------
    var
      v1 = Number.MAX_VALUE * 2;
      v2 = Number.MAX_VALUE * 3;
    document.writeln(v1);
    document.writeln(v2);
    document.writeln(v1 == v2);

    在Global中其它与number类型相关的方法有:
     isFinite()   : 如果值是NaN/正无穷/负无穷,返回false,否则返回true。
     parseFloat() : 从字符串(的前缀部分)取一个浮点数。不成功则返回NaN。


     3). boolean类型
    ========================
     (略)

     4). string类型
    ========================
    JavaScript中的String类型原本没有什么特殊的,但是JavaScript为了适应
    “浏览器实现的超文本环境”,因此它具有一些奇怪的方法。例如:
      link() : 把一个有HREF属性的超链接标签<A>放在String对象中的文本两端。
      big()  : 把一对<big>标签放在String对象中的文本两端。
    以下方法与此类同:
      anchor()
      blink()
      bold()
      fixed()
      fontcolor()
      fontsize()
      italics()
      small()
      strike()
      sub()
      sup()

    除此之外,string的主要复杂性来自于在JavaScript中无所不在的toString()
    方法。这也是JavaScript为浏览器环境而提供的一个很重要的方法。例如我们
    声明一个对象,但是要用document.writeln()来输出它,在IE中会显示什么呢?

    下例说明这个问题:
    //---------------------------------------------------------
    // toString()的应用
    //---------------------------------------------------------
    var
      s = new Object();

    s.v1 = 'hi,';
    s.v2 = 'test!';
    document.writeln(s);
    document.writeln(s.toString());

    s.toString = function() {
      return s.v1 + s.v2;
    }
    document.writeln(s);

    在这个例子中,我们看到,当一个对象没有重新声明(覆盖)自己toString()方
    法的时候,那么它作为字符串型态使用时(例如被writeln),就会调用Java Script
    环境缺省的toString()。反过来,你也可以重新定义JavaScript理解这个对象
    的方法。

    很多JavaScript框架,在实现“模板”机制的时候,就利用了这个特性。例如
    他们用这样定义一个FontElement对象:
    //---------------------------------------------------------
    // 利用toString()实现模板机制的简单原理
    //---------------------------------------------------------
    function FontElement(innerHTML) {
      this.face = '宋体';
      this.color = 'red';
      // more...

      var ctx = innerHTML;
      this.toString = function() {
        return '<Font FACE="' + this.face + '" COLOR="' + this.color + '">'
          + ctx
          + '</FONT>';
      }
    }

    var obj = new FontElement('这是一个测试。');

    // 留意下面这行代码的写法
    document.writeln(obj);


     5). function类型
    ========================
    javascript函数具有很多特性,除了面向对象的部分之外(这在后面讲述),它自
    已的一些独特特性应用也很广泛。

    首先javascript中的每个函数,在调用过程中可以执有一个arguments对象。这个
    对象是由脚本解释环境创建的,你没有别的方法来自己创建一个arguments对象。

    arguments可以看成一个数组:它有length属性,并可以通过arguments[n]的方式
    来访问每一个参数。然而它最重要的,却是可以通过 callee 属性来得到正在执行
    的函数对象的引用。

    接下的问题变得很有趣:Function对象有一个 caller 属性,指向正在调用当前
    函数的父函数对象的引用。

    ——我们已经看到,我们可以在JavaScript里面,通过callee/caller来遍历执行
    期的调用栈。由于arguments事实上也是Function的一个属性,因此我们事实上也
    能遍历执行期调用栈上的每一个函数的参数。下面的代码是一个简单的示例:

    //---------------------------------------------------------
    // 调用栈的遍历
    //---------------------------------------------------------
    function foo1(v1, v2) {
      foo2(v1 * 100);
    }

    function foo2(v1) {
      foo3(v1 * 200);
    }

    function foo3(v1) {
      var foo = arguments.callee;
      while (foo && (foo != window)) {
        document.writeln('调用参数:<br>', '---------------<br>');

        var args = foo.arguments, argn = args.length;
        for (var i=0; i<argn; i++) {
          document.writeln('args[', i, ']: ', args[i], '<br>');
        }
        document.writeln('<br>');

        // 上一级
        foo = foo.caller;
      }
    }

    // 运行测试
    foo1(1, 2);


    2. JavaScript面向对象的支持
    --------
    在前面的例子中其实已经讲到了object类型的“类型声明”与“实例创建”。
    在JavaScript中,我们需要通过一个函数来声明自己的object类型:
    //---------------------------------------------------------
    // JavaScript中对象的类型声明的形式代码
    // (以后的文档中,“对象名”通常用MyObject来替代)
    //---------------------------------------------------------
    function 对象名(参数表) {
      this.属性 = 初始值;

      this.方法 = function(方法参数表) {
        // 方法实现代码
      }
    }


    然后,我们可以通过这样的代码来创建这个对象类型的一个实例:
    //---------------------------------------------------------
    // 创建实例的形式代码
    // (以后的文档中,“实例变量名”通常用obj来替代)
    //---------------------------------------------------------
    var 实例变量名 = new 对象名(参数表);


    接下来我们来看“对象”在JavaScript中的一些具体实现和奇怪特性。

     1). 函数在JavaScript的面向对象机制中的五重身份
     ------
    “对象名”——如MyObject()——这个函数充当了以下语言角色:
      (1) 普通函数
      (2) 类型声明
      (3) 类型的实现
      (4) 类引用
      (5) 对象的构造函数

    一些程序员(例如Delphi程序员)习惯于类型声明与实现分开。例如在delphi
    中,Interface节用于声明类型或者变量,而implementation节用于书写类型
    的实现代码,或者一些用于执行的函数、代码流程。

    但在JavaScript中,类型的声明与实现是混在一起的。一个对象的类型(类)
    通过函数来声明,this.xxxx表明了该对象可具有的属性或者方法。


    这个函数的同时也是“类引用”。在JavaScript,如果你需要识别一个对象
    的具体型别,你需要执有一个“类引用”。——当然,也就是这个函数的名
    字。instanceof 运算符就用于识别实例的类型,我们来看一下它的应用:
    //---------------------------------------------------------
    // JavaScript中对象的类型识别
    //   语法:  对象实例 instanceof 类引用
    //---------------------------------------------------------
    function MyObject() {
      this.data = 'test data';
    }

    // 这里MyObject()作为构造函数使用
    var obj = new MyObject();
    var arr = new Array();

    // 这里MyObject作为类引用使用
    document.writeln(obj instanceof MyObject);
    document.writeln(arr instanceof MyObject);

    ================
    (未完待续)
    ================
    接下来的内容:

    2. JavaScript面向对象的支持
    --------

     2). 反射机制在JavaScript中的实现
     3). this与with关键字的使用
     4). 使用in关键字的运算
     5). 使用instanceof关键字的运算
     6). 其它与面向对象相关的关键字

    3. 构造与析构

    4. 实例和实例引用

    5. 原型问题

    6. 函数的上下文环境

    7. 对象的类型检查问题

  • 相关阅读:
    二叉树遍历
    nginx反向代理signalr
    SignalR入坑笔记
    CSS一些特殊图形
    Powershell下git中文乱码
    使用VisualStudio直接运行简单的C#语句
    wpf实现一个windows定时关机的工具
    Asp.NetCoreWebApi
    MySql权限丢失问题解决
    Systemd 入门教程:命令篇
  • 原文地址:https://www.cnblogs.com/encounter/p/2188727.html
Copyright © 2020-2023  润新知