Javascript客户端脚本的设计和应用


Javascript 根本概念

  JavaScript是一种基于对象(Object)和事件驱动(Event Driven)并 存在安全性能的脚本语言,最初由Netscape公司制造出来,起名Live Script,它和Java的关系惟独一个:名字 比较像 。 使用它的 目标是与HTML超文本标记语言、Java 脚本语言(Java小程序)一同实现在一个Web页面中链接多个对象,与Web客户交互作用 。从而 可以开发客户端的 利用程序等 。它是通过嵌入或调入在 标准的HTML语言中实现的 。它的浮现 补偿了HTML语言的缺陷,它是Java与HTML折衷的 取舍 。( 留神,如同VBScript一样,JavaScript一样有服务器端版本)

一、JavaScript的 根本语法

  0、引言

  Javascript的语法 根本上与Java 统一,然而由于Javascript是一个弱类型的脚本语言,在程序编写的过程中会有一些不同 。同时由于Javascript是基于对象的语言, 留神不是面向对象的语言,所以它在对对象的 支撑上有 定然缺陷,大家所 相熟的诸如对象继承,多态等面向对象语言所 存在的 根本 特点在Javascript中不得不通过一些变通 目的来实现(通常 比较复杂) 。然而,弱类型语言也有其 长处,那便是 容易性,Javascript中类型转化是十分容易的(弱类型语言在代码中 根本上 体现为无类型),一个String通过一个 容易的加减操作就 可以转化为Int(相当于调用了Integer.ParseInt(String)),并且不会抛 异样 。Javascript作为一种解释性语言,还能 使用在编译性语言C/C++、JAVA难以 支撑的eval语句 。由于运行在沙箱中,Javascript运行时有众多的安全性 制约 。它不同意 拜访当地的硬盘,并不能将数据存入到服务器上,不同意对网络文档进行 批改和删除,不得不通过阅读器实现信息阅读或动态交互,从而有效地 预防数据的 迷失 。 总体上来说,Javascript应该是优缺陷兼备(辨正的说=]) 。
  作为学过JAVA的软院本科生来说,学习Javascript并不 困苦 。Javascript不像HTML、CSS这种 教训性很强的的领域,一旦大家入门之后, 残余阶段的Javascript 有关的学习很可能便是查阅 材料而已 。在这里我 盼望我所写的内容 可以起到抛砖引玉的作用,为大家打下 根底 。以下内容重要是Javascript的入门 常识,我会从 要害字开始 形容,强调 要害字是为了让大家对Javascript的语法有 比较全面的 意识,可能大家在今后的开发中可能向来用不到其中的某些 要害字,但我认为大家有必要了解一下,同时请 留神其中标出的 留神事项 。随后将是在页面中加入脚本的四种 步骤 。在“Javascript客户端编程”中,我将提及阅读器文档(DOM)模型和事件(EVENT)模型,其中会有如何寻觅对象以及安装事件 解决器(事件 解决映射)的 详尽 讲解 。最终我将在“Javascript样例”中给出一段核心代码的注解和三个样例 。“Javascript学习 材料”中有一些有用的书籍名,电子参考 材料和 有关网址,请 留神其中的推举参考 材料和MLParser的 使用指南 。大家的对Javascript问题我将会在FAQ中给出解答 。
  第一次写, 舛误在所 不免,恳请大家 教正和 原谅 。

  1、VAR

  var i = 5;
  var j = "hello world";
  var k = document;
  for( var u = 0; ... ; ... ) { ... }
  function fun() { var v = document; ... }
  VAR的作用是申明变量,然而不通过VAR申明的变量也 可以 使用 。
  在BLOCK块(用 { 和 } 或 (和 )括起来的的代码段)中用VAR申明的变量是 部分变量,一旦出了BLOCK的 规模(SCOPE),变量就会失效 。例如在样例中的 u 和 v 变量,当程序流分别出了 FOR 和 FUNCTION 语句的 规模之后 u 和 v 就成了未定义变量 。
   其余状况下用VAR申明或者通过未申明直接 使用的变量(解释器会隐式申明这些变量)都是全局变量 。

  在同一个 规模(SCOPE)中对同一个变量名不能用一次以上的VAR,即不可 反复申明变量 。
  不同 规模(SCOPE)中申明的同名变量在Javascript中会 彼此 潜藏,例如,有一个全局变量 variable,同时在程序段中还有一个 部分变量 variable,那么你在程序中 引用的变量实际上会是 部分变量 variable  。

  一个变量在赋值之后,其类型就转化为所赋值的类型 。
  从未申明过(包括赋值操作激发的隐式申明)的变量值为 undefined 类型也为 undefined  。

  变量的有效性是它的定义 规模与定义语句浮现的顺序无关 。
  function test(){
    document.write(great) ;  // print "undefined"
    document.write(odd) ;   // print "javas" , not "undefined"
    var odd = "javas" ;
  }
  样例中 固然 odd 在 document.write 之后,但在程序被解释时 odd 就被初始化了,所以打印 后果不是 "undefined" 而是odd被给予的初始值 。

  2、IF-ELSE

  if( val > 2.3){
    rs = 5.56;
  }
  else if( val + rs > "1.2") {
    rs = document;
  }
  else{
    rs = "Hello world";
  }
  IF-ELSE的用法与JAVA中的 彻底 雷同 。
   留神 抒发式中的中的“val + rs > 1.2 "这在JAVA中是不同意浮现的 。
  另外 固然Javascript不要求在每句语句之后加分号,但外加分号是良好的编程习惯 。
  在样例中浮现的未申明就 使用的变量的状况在Javascript中是同意的,他们将自动转化为全局变量 。
  Javascript是大小写敏感的,所以请 留神 要害字的大小写 。

  3、SWITCH

  switch(key - 65){
    case 0:
      ch = "A" ;
      break;
    case 1:
      ch = "B" ;
      break;
    default:
      ch = "X" ;
      break;
    case 9:
      ch = "Y" ;
      break;
  }
  SWITCH的用法与JAVA中的 彻底 雷同 。
  CASE后跟的变量 提议 使用常量 抒发式(整数和字符串),不要用浮点 。
  每个CASE 完毕时的BREAK语句通常不可少,除非想利用SWITCH的FALL-THROUGH来实现特定的 性能 。
  DEFAULT语句 可以放在SWITCH 构造中的任意位置, 可以于CASE语句 穿插 搁置 。

  4、WHILE

  while( i < 0 && bool_var){
    if( i > -5)
      continue;
    i += 3 + i;
  }
  WHILE的用法与JAVA中的 彻底 雷同 。
  如果是BOOL变量 可以不写bool_var == true/false,直接 使用即可 。
  CONTINE语句会使程序流跳过循环中 残余的语句,进入循环的下一次迭代 。
  在Javascript中也有带LABEL的BREAK和CONTINUE,用法与JAVA 雷同 。
  在写循环时, 留神不要产生“死”循环 。样例程序片断中的便是一个“死”循环 。

  5、DO-WHILE

  do{
    i -= 8;
  } while( i > 0);
  DO-WHILE的用法与JAVA中的 彻底 雷同 。
  不要 脱漏结尾WHILE(Expression)之后的分号 。

  6、FOR

  for (var i = 0; i < 8; i++){
    document.writeln("Hello world !");
  }
  DO-WHILE的用法与JAVA中的 彻底 雷同 。
  不要在计数变量 i 之前加 int 类型标识符,Javascript是弱类型语言,加了 int 反倒会报语法错,然而 可以用 var 使之成为 部分变量 。
  FOR(... ; ... ; ...)中分号中间的内容都 可以空缺(for (;;)相当于while(true)),其中也 可以 使用多句语句用逗号分隔 。

  7、FOR-IN

  for ( var ite in document) {
    str_result += document [ ite ];
  }
  FOR-IN操纵语句在JAVA中不存在,它的作用有点 类似JAVA中的 Iterator 接口 形容的 性能 。在样例中,ite将遍历 docment 中全部的可遍历元素(不是全部元素),每次迭代时,ite中会包括被遍历数组或对象的索引字符串( 可以看作对象名),例如,textfield(如果你在页面中有一个元素的ID为textfield),或者像数字1、2、3(它们用来 引用对象中的未命名元素) 。
   引用对象中元素时 使用关联数组的 模式:数组名或对象名 [ 索引值 ],例子中用 document [ ite ] 示意 document 中索引为 ite 的元素 。
   使用FOR-IN的最大 好处便是你不需求晓得 指标对象或者数组 毕竟有多少元素,以及其内部 构造是怎么样的,就 可以遍历其全部可遍历元素 。

  8、CONTINUE-BREAK

  again:
  while ( test() ){
    whie (is_run) {
      if(work()) {
        break again;
        // continue again;
      }
      reap();
    }
    i++;
  }
  CONTINUE-BREAK的用法与JAVA中的 彻底 雷同 。
   使用带Label的break或者continue 可以在内外循环中进行跳转 。

  9、FUNCTION

  function fun_1(arg1, arg2) {
    rs = arg1 + arg2;
    return rs;
  }
  FUNCTION在Javascript中的写法与JAVA中的有很大的差异 。
  首先是参数类型的问题,参数前面不需求加任何类型 形容,VAR也不能加 。Javascript 步骤参数也有传值和传 引用之分, 规定与JAVA 根本 统一,具体请查阅 有关 材料 。
  其次是返回值,返回值的类型不需求 表明,RETURN会返回相应的对象,若无RETURN的数据,则返回值为undefined 。从这个 意思上讲,FUNCTION总是有返回值的 。
  最终是参数个数的问题,参数列表并不 制约实际传入函数的参数个数,它只不过提供了一个 拜访参数的快捷 模式,也便是说给了特定位置参数一个特定的名字 。

  sum = fun_1(1) ;
  以上函数调用时只传给 fun_1 一个参数( fun_1 定义时需求两个参数) 。那么此时 arg2 的值是什么呢?undefined,你猜对了 。
  我们 可以把 fun_1 改成以下 模式来 应答这种状况 。
  function fun_2(arg1, arg2) {
    if ( !arg1 ) arg1 = 0;
    if ( !arg2 ) arg2 = 0;
    rs = arg1 + arg2;
    return rs;
  }
  undefined在布尔 抒发式中相当于 false  。

  好了,问题 仿佛解决了 。可是如果我们要 解决更多参数怎么办呢?例如以下函数调用所代表的状况 。
  sum = fun_2(1, 2, 3) ;
  在函数内部有一个Arguments对象,它是一个参数数组,通过它 可以 拜访到传入函数的全部参数 。
  依据这一 特点我们把 fun_2 改成 fun_3 。
  function fun_3 () {
    rs = 0;
    for (var i = 0 ; i < Arguments.length; i++) {
      rs += parseInt( Arguments[i] );
    }
    return rs;
  }
   留神:这里 使用了parseInt而不是直接加法引起的隐式转化 。这是由于隐式转化的要求过高,并且有可能把 rs 转化为 其余内部类型 。
  0 + "23a" = NaN;0 + parseInt ( "23a" )= 23

  function Point ( x, y ) {
    this.x = x;
    this.y = y;
    this.func = m_func;
  }
  function m_func( num ) { ... }
  var newPoint = new Point( 1, 3 );
  newPoint.func( newPoint.x + new Point.y);
  任何一个函数都 可以成为 构造函数,在函数中的 this 要害字同JAVA中 意思 类似,但不 彻底 雷同 。
  通过 new 产生的对象最终会通过垃圾回收机制 革除 。
  函数也是Javascript的内部类型之一,所以 可以赋给某个变量, 留神不要加 () ,()实际上也是一个操作符 示意对函数的调用 。
  this.func = m_func; 示意把m_func函数赋给 this 的 func 成员变量 。
  this.func = m_func(); 示意把m_func函数调用的返回值赋给 this 的 func 成员变量 。

  对象成员 拜访与JAVA 类似:对象名.成员名
  为一个类增加新成员, 惟独给特定的成员名赋值即可(不赋值的话读出来都是 undefined),实际上全局变量或函数也便是顶级对象的成员属性和 步骤,从这个角度上来思量,大家就很容易 了解我在VAR一节中 形容的变量申明 规定了 。
  
  在Javascript中函数既然被视作一个类型,那么函数的申明就会有与一般变量 类似的 步骤:
  var my_func = new Function ("arg1", "arg2", ... , "argN", " var rs = arg1 + arg2 + ... + argN; return rs; ");
  var my_func = function (arg1, arg2, ... , argN)
    {
      var rs = arg1 + arg2 + ... + argN;
       return rs;
    };
  前者被称之为 构造器法,后者被称之为直接量法 。

  10、PROTOTYPE

  function Point ( x, y ) {
    this.x = x;
    this.y = y;
    // this.func = m_func;
  }
  Point.prototype.func = m_func;
  Point.prototype.s_name = "Point";
  function m_func( num ) { ... }
  new Point () ;
  var newPoint = new Point( 1, 3 );
  newPoint.func( newPoint.x + new Point.y);
  PROTOTYPE是原型的意思,我转变在第九节中 Point 的实现 。把 m_func 赋给了Point的原型 。
  这一转变唯一的 好处便是我们不用在每次调用 Point 函数都对 func 属性赋值了,func 属性被 保留在 Point 的原型对象中,从而 节俭了内存空间 。 Point 与 Point.prototype 的关系请查阅 有关的 材料,这里不再详述 。
  用PROTOTYPE 可以实现JAVA中的静态变量和静态 步骤(由于某些阅读器实现在对象 缔造之后才 缔造它的原型对象,所以 提议在 使用原型对象中静态成员之前先调用一次 构造器 步骤,如同样例中 new Point();语句,调用 完毕之后,无用对象将被回收,但其原型对象将 接续驻留在内存中),在Javascript 支撑的有限的对象继承也与PROTOTYPE有 定然 联络 。

  11、ARRAY

  var arr_8 = new Array(8);
  var arr = new Array();
  var arr_d = [ 1, 2, , 4 , .., "Hi", null, true, document ];
  var arr_m = [ [ 1, 2, 3, 4 ], [ 5, 6, 7], [ 8 ] ];

  arr_8[ 3 ] = "ABC";
  arr[ 100 ] = 8.8888;
  arr_d[ 0 ] = "CDE";
  arr_m[ 1 ][ 0 ] = "XYZ";
  数组的 缔造 可以通过 new Array 的 构造器 步骤(参数是数组初始长度,空参数 示意零长度) 。
  或者是把[ 数据 , 数据 , ... , 数据]的数组直接量赋给变量,数据中间用逗号分隔,arr_d中蓝色的 部分有两个延续的逗号 示意第三个元素空缺,其值为 undefined 。
   构造器 步骤的样例: arr_8和arr ;数组直接量的样例: arr_d和arr_m  。

  Javascript中的数组是动态数组,它将随着元素数量自动调节数组长度 。
  Javascript中的数组元素没有任何类型 制约,未初始化的元素值为 undefined 。
  Javascript中的多维数组的实现与JAVA中的 彻底 雷同 。arr_m中 [ 1, 2, 3, 4] 示意 arr_m[0]所指向的第二维数组的数据 。
  Javascript对数组的 拜访与JAVA中的 彻底 雷同 。

  var textfield = document.all[ "textfield" ];
  document.all 是一个数组吗?不 彻底是 。
  那为何我们 可以用 “textfield” 来 拜访我们的对象呢?
  这是由于以上我们所看到的是Javascript中十分特别的用法——关联数组,也 可以称之为索引器 。
  对象名[ "成员名" ] = 对象名.成员名

  关联数组的 使用, 可以使某些操作从硬编码中 开脱出来,使之更 存在灵便性 。请看下面一个例子 。
  如果我们在执行某个与对象 有关的操作时需求靠外界输出 威力确定调用的函数 。
   方案之一:SWITCH,每更改一个分支就需求更新该 步骤 。
   方案之二:对象 + . + 函数名();,语法 舛误 。
   方案之三:对象 [ 函数名字符串 ]();,好的 。
   方案之四:eval(对象名字符串 + "." + 函数名字符串 + "();");,也 可以的 。

  关联数组的 使用,使我们 可以用字符串,数字或者 其余的类型的变量作为索引来 拜访我们所需求 拜访的属性和 步骤 。
  在FOR-EACH中 一般会用这种 步骤来遍历对象或数组属性和 步骤 。

  12、UNDEFINDED-NULL

  undefined == null ? true
  undefined === null ? false
  undefined 示意所 引用的对象未经定义 。
  null 示意所 引用的对象的值是空值 。
  在布尔 抒发式中它的作用 根本与null 统一,都 示意 false 。

  13、TRY-CATCH-FINALLY-THROW

  try{
    throw new Error( "Test Exception" ) ;
  }
  catch( e ){
    document.writeln( e.name + ":" + e.message);
  }
  finally{
    document.writeln( "Final here");
  }
  TRY-CATCH-FINALLY-THROW的用法与JAVA中的 彻底 雷同 。
  这是Javascript 1.5才有的新 特点,在早期的阅读器中可能不 支撑 。当前常用的阅读器 IE6、NAV7、Opera、FireFox 1.0 都 支撑 。

  14、WITH

  function Point ( x, y ) {
    this.x = x;
    this.y = y;
  }
  var newPoint = new Point( 1, 3 );
  with (newPoint) {
    var sum = x + y;
  }
  WITH的用法与DELPH中的 彻底 雷同 。
  由于 使用了WITH,在其作用域中newPoint.x 和 newPoint.y 分别被简化为了 x 和 y  。

  15、TYPEOF

  swich (typeof obj) {
    case "String" :
      rs = "string" ;
      break;
    case "Object" :
      rs = "object" ;
      break;
    case "Number" :
      rs = "Number" ;
      break;
    defualt:
       rs = "Unknown Type" ;
  }
  TYPEOF的作用是返回变量中数据类型对应的字符串 。
  TYPEOF返回的字符串随着阅读器的不同会有 定然的差异 。

二、在网页中 使用JavaScript

  1、链接标记的URL中

  <a href = "Javascript: alert(Hi !);" >Click Me </a>
  Click Me
  这种做法通常只在教学演试中 使用 。
  HREF中的"Javascript : // "的 协定头 定然要加,其中 可以写多句脚本,但不能写 RETURN 语句 。

  2、HTML标签的事件 解决属性中

  <a href = "#" onclick = "Javascript: alert(Hello !);return false;">Click Me Too</a>
  Click Me Too
  这种做法 比较 容易, 比较常用 。return false 是为了禁止页面跳转 。
  通常 "Javascript : // "的 协定头 可以不加,简写为 onclick = "alert(Hello !);return false;" 。

  3、页面的SCRIPT标签中

  <script language="javascript" type="text/javascript">
  <!--//--><![CDATA[//><!--
  function testJs(){
    alert(Hello !);
    ...
  }
  //--><!]]>
  </script>
  ...
  <a href = "#" onclick = " testJs();return false;">Click Me Again</a>
  Click Me Again
  这种做法把脚本与HTML做了 定然的 拆散,代码的整体 构造 比较良好 。
  在代码的 四周外加<!--//--><![CDATA[//><!-- 和 //--><!]]>是为了幸免不 支撑脚本的阅读器把脚本当作一般文本输出 。
  与之作用 类似的还有<noscript>标签,<noscript>标签在阅读器不 支撑脚本时显示出其中的 揭示性文字 。
  <script>标签通常都放在<head>标签内 。

  4、外部脚本文件中

  [ testJs.js ]
  <!--//--><![CDATA[//><!--
  function testJsExt(){
    alert(Ohhh No!);
    ...
  }
  //--><!]]>
  [ *.htm ]
  <script language="javascript" type="text/javascript" src="mat/js/testJs.js"></script>
  ...
  <a href = "#" onclick ="testJsExt();return false;">Click Me Nowww! </a>
  Click Me Nowww !
  外部脚本便是把脚本 保留在一个 径自的 *.js 文件中,通过指定<script>标签的 src 属性,把脚本引入 。
   动机相当于在原先的<script> 标签中间插入外部文件中的脚本文本 。
   留神某些阅读器将 忽略有SRC属性的<script>标签中的脚本代码 。
  这种 步骤从 性质上来讲与第三种 步骤没有差异,然而由于把脚本和HTML做了 彻底的 拆散,所以是商业领域最常用的 步骤 。
  现在我们在标签<a>中 依旧有Javascript的痕迹,在Javascript客户端编程中我将会介绍如何将其去除,以及使Javascript脚本在HTML中留下 起码痕迹的 目的