JavaScript类的设计

【转载】

Javascript与其他的面向对象语言不同,如C++,Java或PHP等。它并不是基于类的,而是基于原型的一种语言。

1、对象创建

在Javascript中创建一个类是非常容易的:

var myObject = {
  aVar: 15,
  aMethod: function() {
    alert("I‘m a method of the object myObject." + "aVar: " + this.aVar);
  }
}

你不必通过定义一个类然后实例化该类来创建一个对象。我们在这里使用了一个对象构造器。它满足了使用单个对象的场合。如果我们需要使用同一个类型的多个对象,我们必须使用一个构造器函数和new关键字。

2、使用构造器函数

在Javascript中没有类的概念,但是构造器是存在的。你可以编写一个函数,然后通过new关键字来创建一个对象。

// 首先,我们为我们的类定义一个空的构造器
function myClass() {
  this.aVar = 15;
  this.aMethod = function() {
    alert("I‘m a method of the object myObject.");
  }
}

// 创建类的实例
var A = new myClass();

// 显示 15
alert(A.aVar);

// 第二个实例
var B = new myClass();

3、动态附加

怎么在Javascript实现OO编程?

恐怕最佳的方式就是充分利用prototype属性。

关于prototype比较基本的原理的理解是:当你用prototype编写一个类后,当你new一个新的object,浏览器会自动把prototype中的内容替你附加在object上。这样,通过利用prototype,你也就实现了类似OO的Javascript。

方法共享

你必须使用prototype对象:

// 我们定义了一个prototype对象的一个方法
myClass.prototype.sharedMethod = function() { alert("I‘m a shared method") }

// 显示我们的信息
A.sharedMethod();

// 相同的信息
B.sharedMethod();

在myClass定义中并没有一个名为sharedMethod的方法。Javascript会在myClass相关联的prototype对象中寻找与该方法名相同的方法,如果存在的话,Javascript则调用该方法。

在Javascript中,object就是个associative array。上面的例子讲到了一个function就是个类。当你编写如下function时,其实就是定义了一个类,该function就是他的构造函数。

function MyObject(name, size){
    this.name = name;
    this.size = size;
 }

之后,你能方便的通过MyObject类的prototype属性来方便的扩充他。

比如,你能给他添加其他的属性和方法:

//通过prototype属性添加tellSize 方法
MyObject.prototype.tellSize = function()
{
    return "size of "+this.name+" is "+this.size;
}
//通过prototype属性添加color 属性

MyObject.prototype.color = "red";

MyObject.prototype.tellColor = function()
{
    return "color of "+this.name+" is "+this.color;
}

var myobj1 = new MyObject("tiddles", "7.5 meters");

domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

你能想象,当你调用tellColor()方法后,结果是这样的:

color of tiddles is red

非常方便的是,prototype属性能动态添加。比如,你需要往MyObject中加入一个height属性,并希望其提供一个tellHeight()方法来获得height属性的值。你能在上面的代码后,继续添加如下的代码:

MyObject.prototype.height = "2.26 meters";

MyObject.prototype.tellHeight = function()
{
    return "height of "+this.name+" is "+this.height;
}

之后,你能访问一下myobj1的tellHeight()方法,你能得到如下的结果:

height of tiddles is 2.26 meters

prototype的这些动态的特性看起来有些迷人,不过我倒是反而觉得有些凉飕飕的。确实,这些特性给你非常大的灵活性,能给予你runtime改动类属性和方法的能力。不过,稍微发掘一下,会有些不良的习惯产生。

首先,如果能动态添加属性和方法,那么非常容易让人想到,当我调用时,我想要调用的属性或方法存在不?这是个非常严肃的问题,如果当我们调用时根本没有该属性或方法,将可能导致我们的脚本down掉。

不过也有解决办法。比如,在上面的代码中,当还没有tellHeight()方法时,我们能如下编写代码避免发生错误:

if (myobj1.tellHeight)
{
    domDiv.innerHTML += myobj1.tellHeight()+"<br /><br />";
}  

注意,一定要在if语句中,不要加方法后面的那对(),否则,直接就down掉了。有兴趣的读者能打印一下,看看分别访问myobj1.tellHeight和myobj1.tellHeight()时有什么差别。

也许,你觉得这个是小意思。加个判断嘛,不就好了?

对,不过下面一个问题更令人头痛。

属性和方法在不在的问题简单,可是属性和方法变不变化的问题可就严重了。在不在我们能检测,变不变呢?比如,请看下面的代码:

function MyObject(name, size)
{
    this.name = name;
    this.size = size;
}

MyObject.prototype.color = "red";

MyObject.prototype.tellColor = function()
{
    return "color of "+this.name+" is "+this.color;
}

var myobj1 = new MyObject("tiddles", "7.5 meters");

domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

MyObject.prototype.color = "green";

domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

该代码将产生如下结果:

color of tiddles is red
color of tiddles is green

请注意,你修改的是类MyObject的color属性。不过你惊奇的看到你之前实例化的对象myobj1的属性值竟然也变化了。天!如果你的项目代码是多人合作,那么,也许某个人会在编程时为了图一己之便,擅自修改你的类。于是,所有人的对象都变化了。于是,你们陷入了漫长的debug过程中。。。。。。

上面是属性,更有方法:

function MyObject(name, size)
{
    this.name = name;
    this.size = size;
}

MyObject.prototype.color = "red";

MyObject.prototype.tellColor = function()
{
    return "color of "+this.name+" is "+this.color;
}

var myobj1 = new MyObject("tiddles", "7.5 meters");

domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

MyObject.prototype.color = "green";

MyObject.prototype.tellColor = function()
{
    return "your color of "+this.name+" is "+this.color;
}

domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

这段代码的结果是:

color of tiddles is red
your color of tiddles is green

问题来了。Javascript太灵活的编程方式多少让人不适应。如果整个Team的水平都比较高还能,没人会犯这样的错误。不过,当有个毛头小伙子不知情,擅自修改类,将导致所有的人的对象都发生变化,无论是属性还是方法。在Javascript代码变得越来越多的Ajax时代,这是个严重的问题。

这说明,编写Javascript时,好的编程风格更加重要。记得某人原来说过这样的话,想Java和C#这些比较严格的语言,虽然降低了灵活性,但也减少了犯错误的可能。这样,即使一个新手,他写出的代码也不会和高手差太多。不过,像Javascript这样的脚本语言,由于太灵活,所以,高手写出的是天使,而新手写的,可能是魔鬼!

时间: 2024-08-04 20:19:27

JavaScript类的设计的相关文章

Pongo网页版JavaScript源代码及设计思路

1.游戏背景介绍(写在前面的废话): 五月初的某天,看到某网推荐了这款游戏,Pongo,看着还不错的样子就用ipad下下来试玩了下,玩了两局感觉还错挺过瘾的,因为是手欠类游戏嘛大家懂的. 但是没一会发现游戏在ipad似乎有些bug,玩一会就会卡住然后只能强退了,真是揪心,记录还等着破呢. 怎么办?玩游戏不如玩自己的游戏的念头又邪恶的出现了,然后就把pad丢给了朋友虐心去,我默默回到电脑前开始动手自己写个不会卡的. 大概两小时吧,写出了基本框架,然后扔sinaapp里试了下效果基本能玩就洗洗睡了.

JavaScript异步编程设计快速响应的网络应用

JavaScript已然成为了多媒体.多任务.多内核网络世界中的一种单线程语言.其利用事件模型处理异步触发任务的行为成就了JavaScript作为开发语言的利器.如何深入理解和掌握JavaScript异步编程变得尤为重要!!!<JavaScript异步编程设计快速响应的网络应用>提供了一些方法和灵感. 一.深入理解JavaScript事件 1. 事件的调度 JavaScript事件处理器在线程空闲之前不会运行(空闲时运行). var start = new Date(); setTimeout

javascript 继承机制设计思想

作者: 阮一峰 原文链接:http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html 我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(proto

JavaScript类和模块

类 在JavaScript中,类的实现是基于原型继承机制的.如果两个实例都从同一个原型对象上继承了属性,我们说它们是同一个类的实例. 构造函数 从某种意义上讲,定义构造函数即是定义类,所以构造函数名首字母要大写,而普通的函数都是首字母小写. // 构造函数,首字母大写 // 注意,这里并没有创建并返回一个对象,仅仅是初始化 function Range(from , to) { // 添加2个属性,这2个属性是不可继承的,每个对象都拥有唯一的属性 this.from = from; this.t

第11周项目1——点、圆、圆柱类的设计

<pre class="html" name="code"> /* *Copyright (c) 2016,烟台大学计算机学院 *All rights reserved. *文件名称 : *作 者 : 刘云 *完成日期 : 2016年5月8号 *版 本 号 : v6.0 * *问题描述 : 点.圆.圆柱类的设计 *输入描述 : 无 *程序输出 : */ /**************************************************

类的设计

1001: 类的设计(1) Time Limit: 1 Sec  Memory Limit: 65535 MB   64bit IO Format: %lldSubmitted: 9  Accepted: 7[Submit][Status][Web Board] Description 设计clock类,成员数据包含时(hour)分(minute)秒(second),都是int类型,根据给定的main函数设计必要的成员函数. main函数已给定,提交时只需要提交main函数外的代码部分. int

表达式计算器类的设计5(面向对象的表达式计算器8)

计算器的github下载地址:https://github.com/ljian1992/calculator 概述 表达式计算器的类基本已经设计完成了,由于在程序运行的时候总会有这样那样的异常,例如:a +2, a没有初始化,对于异常的管理一般而言是需要自定义异常类.这个自定义异常类也是在继承了系统已经定义好的exception类,然后再重新定义内容. 异常的种类 语法异常---->SyntaxError类 赋值时左操作数不是变量:1 = 2; 缺少括号:1 + (2*2 不认识的函数: 函数缺

表达式计算器类的设计4(面向对象的表达式计算器7)

概述 把符号表和变量表中的内容保存到一个文件中,通过IO文件流,来把符号表和变量表存储到文件中.在这之前需要弄明白什么是序列化和反序列化 对象的序列化 序列化:把对象转换为字节序列的过程 反序列化:把字节序列恢复为对象的过程 我们要把SymbolTable类的对象(符号表)和Storage类的对象(变量表)转换成字节序列保存到文件中,这时就可以设置Serializer类来完成这样的功能,同样的设置一个DeSerializer类来完成把保存到文件当中的字节序列恢复为对象的功能.这里要注意的是,所有

表达式计算器类的设计3(面向对象的表达式计算器6)

概述 有了构建语法的类,存储符号的类,现在就可以对表达式进行扫描,解析了.扫描可以抽象出一个Scanner类来完成这一个功能,而解析可以抽象出一个Parser类来完成这一个功能.这两个类存在一定的关系,扫描与解析的互动是这样子的:扫描到一个标识符,然后解析它是什么标识符.由于该表达式计算器是要支持一些命令的,命令的解析和表达式的解析过程完全不一样,所有呢,又要设置一个CommandParser类,来解析命令. Scanner类,Parser类,CommandParser类的设计 Scanner类