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


Posted in Javascript onAugust 21, 2006

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中留下最少痕迹的手段

Javascript 相关文章推荐
JS判断元素为数字的奇异写法分享
Aug 01 Javascript
javascript函数定义的几种区别小结
Jan 06 Javascript
JS实现队列与堆栈的方法
Apr 21 Javascript
易被忽视的js事件问题总结
May 14 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
May 26 Javascript
内容滑动切换效果jquery.hwSlide.js插件封装
Jul 07 Javascript
JavaScript实现多栏目切换效果
Dec 12 Javascript
手机端转换rem适应
Apr 01 Javascript
微信小程序实现日历功能
Nov 27 Javascript
vue watch关于对象内的属性监听
Apr 22 Javascript
JS原型prototype和__proto__用法实例分析
Mar 14 Javascript
处理canvas绘制图片模糊问题
May 11 Javascript
让iframe框架网页在任何浏览器下自动伸缩
Aug 18 #Javascript
去除链接虚线全面分析总结
Aug 15 #Javascript
静态的动态续篇之来点XML
Aug 15 #Javascript
实用javaScript技术-屏蔽类
Aug 15 #Javascript
巧妙破除网页右键禁用的十大绝招
Aug 12 #Javascript
总结一些js自定义的函数
Aug 05 #Javascript
document对象execCommand的command参数介绍
Aug 01 #Javascript
You might like
php 字符串函数收集
2010/03/29 PHP
php中随机显示图片的函数代码
2011/06/23 PHP
PHP7标量类型declare用法实例分析
2016/09/26 PHP
Yii框架中sphinx索引配置方法解析
2016/10/18 PHP
YII中Ueditor富文本编辑器文件和图片上传的配置图文教程
2017/03/15 PHP
jquery插件冲突(jquery.noconflict)解决方法分享
2014/03/20 Javascript
JS遍历数组及打印数组实例分析
2016/01/21 Javascript
JS跨域解决方案之使用CORS实现跨域
2016/04/14 Javascript
Ajax使用原生态JS验证用户名是否存在
2020/05/26 Javascript
input获取焦点时底部菜单被顶上来问题的解决办法
2017/01/24 Javascript
Bootstrap多级菜单的实现代码
2017/05/23 Javascript
angular.extend方法的具体使用
2017/09/14 Javascript
vue实现todolist基本功能以及数据存储功能实例详解
2019/04/11 Javascript
Vue对象赋值视图不更新问题及解决方法
2019/06/03 Javascript
layUI的验证码功能及校验实例
2019/10/25 Javascript
vue 微信扫码登录(自定义样式)
2020/01/06 Javascript
[02:08]2014DOTA2国际邀请赛 430专访:力争取得小组前二
2014/07/11 DOTA
详解Python的Django框架中的通用视图
2015/05/04 Python
python中日志logging模块的性能及多进程详解
2017/07/18 Python
利用python在excel里面直接使用sql函数的方法
2019/02/08 Python
Python制作微信好友背景墙教程(附完整代码)
2019/07/17 Python
英国网上电器商店:Electricshop
2020/03/15 全球购物
Puccini乌克兰:购买行李箱、女士手袋网上商店
2020/08/06 全球购物
一套比较完整的软件测试人员面试题
2012/05/13 面试题
J2EE中常用的名词进行解释
2015/11/09 面试题
三年大学生活自我鉴定
2014/01/21 职场文书
森林防火工作方案
2014/02/14 职场文书
求职个人评价范文
2014/04/09 职场文书
社团活动总结范文
2014/04/26 职场文书
核心价值观演讲稿
2014/05/13 职场文书
优秀员工评优方案
2014/06/13 职场文书
三年级学生评语大全
2014/12/26 职场文书
出纳试用期自我评价
2015/03/10 职场文书
社区法制宣传日活动总结
2015/05/05 职场文书
教师远程培训心得体会
2016/01/09 职场文书
go结构体嵌套的切片数组操作
2021/04/28 Golang