1.5 初识JavaScript
JavaScript是面向Web的编程语言。绝大多数现代网站都是用了JavaScript,并且所有的现代Web浏览器——基于桌面系统、游戏机、平板电脑和智能手机的浏览器——均包含了JavaScript解释器。这使得JavaScript可称为史上使用广泛的编程语言。
“JavaScript”这个名字经常被误解。除了语法看起来和Java类似之外,JavaScript与Java是完全不同的两种编程语言。JavaScript早已超出了“脚本语言”本身的范畴,而成为一种集健壮性、高效性和通用性为一身的编程语言。
1.5.1 JavaScript的名字和版本
JavaScript是由Web发展初期的网景(Netscape)公司创建的,“JavaScript”是Sun Microsystem公司(Oracle)的注册商标,用来特指网景(Mozilla)对这门语言的实现。网景将这门语言作为标准提交给了ECMA(欧洲计算机制造协会),由于商标上的冲突,所以这门语言的标准版本改为“ECMAScript”。
当提到这门语言时,通常所指的语言版本是ECMAScript 3和ECMAScript 5,有时会看到JavaScript的版本号,这些是Mozilla的版本号:版本1.5基本上就是ECMAScript 3, JavaScript解释器也有版本号,现在为3.0。
1.5.2 准备使用JavaScript
本节中关注的是Web编程需要核心JavaScript特性。这里不会将全部的JavaScript内容讲述清楚,因为若是想完成这些工作本书的厚度是不够的。如果读者想要深入学习这方面的知识,则可以在网上选购几本这方面的书来提升自己的能力。
在HTML文档中定义脚本时有几种方法可供选择,既可以定义内嵌脚本(即脚本是HTML文档的一部分,用<script>标签可实现),也可以定义外部脚本(脚本包含在另一个文件中,通过一个URL引用)。这两种方法都用到了script元素。
1 <! DOCTYPE HTML> 2 <html><head><title>Example</title></head> 3 <body><script type="text/javascript"> 4 document.writeln("Hello"); </script> //输出语句 5 </body></html>
本段脚本的作用是在文档中加入单词Hello。script元素位于文档中其他内容之后,这样在脚本执行之前浏览器就已经对其他元素进行了解析,读者可以自行将本段代码输入到html文件中,并在网页中运行以查看效果。
上述代码为一个简单的JavaScript案例应用,并且定义HTML文档为内嵌脚本。在WebGL的开发中,除了在一些html文件中定义了stat方法外,剩下的脚本使用的都是通过URL来调用外部脚本。但是在本节介绍JavaScript基础时,我们会用内嵌脚本方式示例。
1.5.3 使用语句
JavaScript的基本元素是语句,一条语句代表一条命令,通常以分号结尾。实际上分号也可以不用,不过加上分号可让代码更易阅读,并且可以在一行书写几条语句。下面我们来看一下使用输出语句与定义一些函数的案例。
代码位置:随书源代码/第1章目录下的HTML5/Sample1_19.html。
1 <! DOCTYPE html> 2 <html><head><title>Sample1_19</title> 3 </head><body> 4 <style type="text/javascript"> 5 document.writeln("输出一句话。"); //输出语句 6 document.writeln("输出另一句话。"); 7 function myFun(){ //定义一个函数,用于输出一句话 8 document.writeln("调用方法输出一句话。); }; 9 myFun(); //调用定义的函数 10 function mayFun1(name, weather){ //定义一个带参数的函数 11 document.writeln("Hello"+name+"."); 12 document.writeln("It is"+weather+"today."); }; 13 myFun1("Tom", "Sunny"); //调用带参数的函数 14 function myFun2(name){ //定义一个带返回结果的函数 15 return("Hello"+name+"."); } 16 document.writeln(myFun2("Tom")); 17 </script></body></html>
说明
上面代码内嵌在脚本中演示了语句如何使用。JavaScript的基本元素是语句。有时候可以将几条语句包含在一个函数中,浏览器只有遇到调用该函数的语句时才会执行它。函数所含语句被包围在一对大括号之间,成为代码块。
前面讲述的HTML事件,一般情况下大家在日后的开发中会结合某些事件来调用JavaScript函数。另外需要注意的是,在调用有参函数时,参数个数可以比定义的少,此时缺少的参数值便会默认为undefined。如果多出参数,那么多出的会被忽略。
熟悉Java开发的读者知道,在Java开发中大家可以开发函数名相同但是参数个数不同的函数,这在JavaScript中是万万不可的。如果有两个相同名字的函数但参数个数不同,那么第二个定义将会取代第一个。
1.5.4 使用变量和类型
使用关键字var定义变量,在定义同时还可以像在一条单独语句中那样为其赋值。定义在函数中的变量为局部变量,只能在该函数范围内使用。直接在script元素中定义的变量称为全局变量,可以在任何地方使用(包括在其他脚本中)。
代码位置:随书源代码/第1章目录下的HTML5/Sample1_20.html。
1 <! DOCTYPE html> 2 <html><head><title>Sample1_20</title> 3 </head><body> 4 <script type="text/javascript"> 5 var myglobalvar="apple"; //定义全局变量 6 function myFun(){ //声明一个方法 7 var mylocalvar="sunny"; //定义局部变量 8 return("Hello"+name+".Today is"+mylocalvar+"."); }; 9 document.writeln(myFun("Tom")); 10 document.writeln("I like"+myglobalvar+"."); 11 var string1="This is a string."; //使用JavaScript的基本类型——字符串变量 12 var string2="This is a string."; 13 var bool1=true; //使用JavaScript的基本类型——布尔变量 14 var bool2=false; 15 var daysinweek=7; //使用JavaScript的基本类型——数值变量 16 var pi=3.14; //JavaScript中的整数、浮点数都用var来声明 17 var hexValue=0xFFFF; //十六进制数 18 var mydata=new Object(); //创建对象 19 mydata.name="Tom"; //为对象属性赋值 20 mydata.weather="sunny"; 21 document.writeln("Hello"+mydata.name+"."); 22 document.writeln("Today is "+ mydata.weather+"."); 23 var mydata1={ //使用对象字面变量 24 name:"Tom", //为对象属性赋值 25 weather:"Sunny"}; 26 document.writeln("Hello"+mydata1.name+"."); //使用对象属性 27 document.writeln("Today is"+mydata1.weather+"."); 28 var mydata2={ //为对象添加方法 29 name:"Tom", //为对象属性赋值 30 weather:"Sunny", 31 printMessages: function(){ //给对象属性声明一个方法 32 document.writeln("Hello"+mydata2.name+"."); 33 document.writeln("Today is "+ mydata2.weather+"."); }}; 34 mydata2.printMessages(); //读取和修改对象属性值 35 var mydata3={ 36 name:"Tom"; //为对象属性赋值 37 weather:"Sunny"; }; 38 mydata3.name="Jerry"; //修改对象属性值 39 mydata3["weather"]="raining"; 40 document.writeln("Hello"+mydata3.name+"."); //读取对象属性值 41 document.writeln("Today is "+ mydata3.weather+"."); 42 </script></body></html>
❑ 第5~10行为使用局部变量与全局变量。JavaScript是一种弱类型语言,但这不代表它没有类型,而是指它不用明确声明变量的类型即可随心所欲地用同一变量表示不同类型的值。
❑ 第11~17行为声明各种基本类型。字符串可以用夹在一对双括号或单引号之间的一串字符来表示。布尔类型有两个值:true和false。整数和浮点数都用number类型来表示,定义数值变量时不必声明所用的是哪种数值,只需写清楚值即可。
❑ 第18~41行创建对象的一些代码。JavaScript支持对象概念,有多种方法可以创建对象,可以用对象字面量的方式定义一个对象及其属性,也可以在声明完对象后添加属性。在创建好对象后,还可以修改对象的属性值。
使用对象的时候还可以枚举对象属性,可以用for…in语句枚举对象属性。for…in循环代码块中的语句会对对象的每一个属性执行一次。在每一次迭代过程中,所需要处理的属性名会被赋值给变量。大家看看下面这个简短的例子。
1 <! DOCTYPE HTML> 2 <html><head><title>Example</title></head> 3 <body><script type="text/javascript"> 4 var mydata={ //声明一个对象 5 name:"Tom", //为对象的属性赋值 6 weather:"Sunny", 7 printMessages:function(){ //为对象添加方法 8 document.writeln("Hello"+mydata.name+"."); //读取对象的属性值 9 document.writeln("Today is "+ mydata.weather+"."); }}; 10 for(var prop in mydata){ //枚举对象的属性值 11 document.writeln("Name" + prop + "Value:" + mydata[prop]); } 12 </script></body></html>
图1-21所示为这段代码的运行效果,从中可以看到,作为方法定义的函数也被枚举出来了。JavaScript在处理函数方面非常灵活,方法本身也被视为对象的属性,这就是其结果。除了枚举对象属性,还有增删属性等。
图1-21 案例运行效果
在日后的开发中会经常用到对象,不论是内嵌在JavaScript脚本中创建的对象,还是外部定义的要通过URL引用JavaScript的脚本,大家可以通过创建对象引用来实现相应功能,这些在后面的开发中要多留心观察。
1.5.5 JavaScript运算符
有编程经验的读者都明白,不论是什么语言都会经常用到运算符,JavaScript当然也不会例外。幸运的是,JavaScript的运算符与一般编程语言中的运算符没有多大的差别,所以这里简单介绍一下,表1-13所示为JavaScript运算符及其描述。
表1-13 JavaScript运算符
通过浏览表1-13大家不难发现这些运算符在入门学习任何一门编程语言时都会有详尽的介绍,所以这里便不再赘述了。表中描述的x、y假设均为已经声明好的变量旨在帮助读者理解运算符。
1.5.6 使用数组
JavaScript数组的工作方式与大多数编程语言中的数组类似,一般在枚举数组时都会使用{},但在JavaScript中声明数组使用[]而不是用花括号。下面来看一下如何用JavaScript创建数组,以及使用数组对象。
代码位置:随书源代码/第1章目录下的HTML5/Sample1_21.html。
1 <! DOCTYPE HTML> 2 <html><head><title>Sample1_21</title></head> 3 <body><script type="text/javascript"> 4 var myarray=new Array(); //创建与填充数组 5 myarray[0]=100; //为数组赋值 6 myarray[1]="Tom"; 7 myarray[2]=true; 8 var myarray1=[100, "Tom", true]; //使用数组字面量创建数组 9 var myarray2=[100, "Tom", true]; //读取指定索引位置的数组元素值 10 document.writeln("Index 0" + myarray2[0]); 11 var myarray3=[100, "Tom", true]; //修改数组内容 12 myarray3[0]="Tuesday"; 13 document.writeln("Index 0" + myarray3[0]); 14 var myarray4=[100, "Tom", true]; //枚举数组内容 15 for(var i=0; i<myarray4.length; i++){ //myarray4.length为数组的长度 16 document.writeln("Index 0" + myarray4[0]); } 17 </script></body></html>
❑ 第4~7行为调用new Array()创建一个新的数组。这是一个空数组,它被赋给变量myarray,后面的语句是给数组中的几个索引位置赋值。
❑ 第8~16行为数组的基本应用,包括通过数组字面量创建数组,读取指定索引位置的数组元素值,通过索引值来改变数组内容,遍历数组元素内容。我们在学习基础的编程语言时都已经学到这些基本的操作,这里的用法与之相差不大。
此例需要注意两点,第一点是在创建数组的时候不需要声明数组中的元素个数,JavaScript数组会自动调整大小以便容纳所有元素。第二点是不必声明数组所含数据的类型,JavaScript数组可以包含各种类型的数据。
有编程经验的读者知道除了上面所讲的数组基础用法外还应知道一些数组方法,下面我们便来看一下表1-14所列出的常用数组方法。由于篇幅有限所以这些方法的应用不再过多介绍了,读者可以对照着说明自行试验。
表1-14 常用数组方法
讲完数组后,JavaScript的基础内容基本结束了,JavaScript与Java类似也有处理错误。这里的处理错误也是用try…catch语句来实现,如果有错误发生,那么try子句中语句的执行将立即被停止,控制权转移到catch子句中。发生的错误由一个Error对象描述,它会传递给catch子句。
1.5.7 创建自己的JavaScript对象
在JavaScript中,不但可以使用系统提供的对象,还可以创建自己的对象,相当于把Java中类的声明和对象的创建合二为一了。由于创建对象时对象不止只有一个属性,所以属性与属性之间用逗号分隔,其余的声明规则与Java类似。其简略语法如下
<引用名>={<属性名>:<属性值>, {<属性名>:<属性值>……}}
在JavaScript中,对象实际上可以看作数组,因此对象的成员不仅可以用“<引用>.<属性>”的方式来访问,还可以用“<引用>[<属性>]”像数组一样来使用。如果希望对象可以重用,也可以像Java那样先声明类再new对象,其语法如下:
function<类名>([构造函数参数列表]) { this.<属性名1>=<构造函数参数>; …… this.<属性名n>=<构造函数参数>; }
实际上类的声明就是一个函数的声明,只是在函数中多了“this.<属性名>”,这既是属性的声明同时又进行了初始化。大家都知道一个类不但可以有属性,还可以有方法,给类添加方法的语法如下:
function<类名>([构造函数参数列表]){ this.<方法名1>=<函数名1>; //函数可以是在任意地方声明的函数 …… this.<方法名n>=<函数名n>; }
实际上方法的声明就是把已经写好的函数分配给一个属性。前面说过由于对象可以看作一个数组,所以可以对对象的属性进行遍历。在JavaScript中,可以方便地利用下面形式的for语句对指定对象的所有属性进行遍历:
for(var<变量>in<对象引用>){ //语句序列 }
对象操作的基本方法就这么多,用操作符“new”创建对象,释放(删除)对象时使用“delete”操作符。由于JavaScript是弱类型语言,所以在下一节中会看到无论声明什么类型的变量都会为var字符。有时判断变量的类型,这就要使用“typeof”操作符,如表1-15所示。
表1-15 typeof操作符的应用
“typeof”操作返回的是一个字符串。从表1-15可以看到typeof返回了一个undefined。在JavaScript中不但true/false布尔类变量可以参与逻辑计算,undefined和null都可以当作逻辑false来使用。JavaScript支持原型,使用原型可以向已有对象类型注射新的方法、属性。
代码位置:随书源代码/第1章目录下的HTML5/Sample1_22.html。
1 <! DOCTYPE html> 2 <html><head><title>Sample1_22</title> 3 </head><body> 4 <script type="text/javascript"> 5 tom={name:"Tom", age:21}; //创建自己的对象 6 document.write("Name:"+tom.name+"<br>"); //读取对象的属性值 7 document.write("Age:"+tom.age+"<br>"); 8 //对象可以看作数组,用数组形式访问对象,下面的例子便演示了如何用数组形式访问对象 9 tom={name:"Tom", age:21}; 10 document.write("Name:"+tom["name"]+"<br>"); //用数组形式访问对象 11 document.write("Age:"+tom["age"]+"<br>"); 12 //对象的重用,可以像Java那样先声明类再new对象 13 function Student(sno, sname, sage, sclass){ //声明student类 14 this.sno=sno; //为student类添加属性 15 this.sname=sname; //为属性添加属性值 16 this.sage=sage; 17 this.sclass=sclass; } 18 tom=new Student("10001", "Tom",21, "97002"); //创建Student对象 19 document.write(tom.sname+"<br>"); 20 //给类添加方法,即为类中的属性添加方法 21 function Student1(sno, sname, sage, sclass){ //声明student1 22 this.sno=sno; //将student类声明中传入的参数赋值给属性 23 this.sname=sname; //为sname属性赋值 24 this.sage=sage; //为sage属性赋值 25 this.sclass=sclass; //为sclass属性赋值 26 this.toString=toString; } //把toString方法挂接到Student 27 function toString(){ //声明toString方法 28 var result=""; //声明一个空白字符串 29 result+="学号: "+this.sno+"<br>"; //为字符串添加学号内容 30 result+="姓名: "+this.sname+"<br>"; //为字符串添加姓名内容 31 result+="年龄: "+this.sage+"<br>"; //为字符串添加年龄内容 32 result+="班级: "+this.sclass+"<br>"; //为字符串添加班级内容中 33 return result; } //将最终所得字符串返回 34 tom=new Student1("10001", "Tom",21, "97002"); //创建Student1对象 35 document.write(tom.toString()); 36 tom={name:"Tom", age:21, no:10001}; //对对象的属性进行遍历 37 for(var i in tom){ //对象属性用循环进行遍历 38 document.write(i+":"+tom[i]+"<br>"); } 39 function toWyfString(){ //用原型给已有对象注射新方法、新属性 40 var ss=this.wyfTime+this.toGMTString(); //得到系统时间 41 return ss; } //将字符串返回 42 function toGMTString(){ 43 return "HaHa! ! ! "; 44 } //使用原型可以向已有的对象类型注射新方法、属性 45 //对对象的功能进行扩展,同时也能覆盖原有的方法 46 Date.prototype.wyfTime="WYF: "; //拓展对象属性 47 Date.prototype.toWyfString = toWyfString; //覆盖原有的方法 48 d=new Date(); 49 document.write(d.toWyfString()+"<br>"); 50 document.write(d.toGMTString()+"<br>"); 51 Date.prototype.toGMTString = toGMTString; //覆盖原有的方法 52 document.write(d.toGMTString()+"<br>"); 53 </script></body></html>
❑ 第5~19行为创建自己的对象与对象的重用。这一部分的内容与Java没有太大的差异。在创建自己的对象时,相当于将类的声明和对象的创建合二为一了,对象的声明实际上就是函数的声明,只不过在函数体中多了this.<属性名>。
❑ 第20~38行为类添加方法与对对象属性进行遍历。实际上添加方法就是把已经写好的函数分配给一个属性。用var变量in对象引用的方式对对象属性进行遍历。本例是将每个属性输出了一遍。
❑ 第39~53行为使用原型给已有对象注射新方法、新属性。示例中对对象的属性进行了拓展,之后用自己写的方法通过原型覆盖了已有类中的原有方法,之后通过前后对比向读者展示了如何用原型拓展对象功能。
上面代码为本节中所讲述内容的应用。前面已经讲述了创建对象与数组,本节讲述的是如何开发自己的类,以及声明自己的对象和对象的一些用法。这些内容与Java有些类似,有Java开发经验的读者肯定不会陌生。
1.5.8 常用的JavaScript工具
有很多工具可简化JavaScript的编程工作,我们在调试程序时必不可少的一个环节便是调错。由于开发JavaScript不像开发其他语言有强大的编译环境,所以调错时不是很方便。幸运的是,现在的浏览器都会有内置的调试器,图1-22所示为Firefox浏览器的firebug插件。
图1-22 firebug插件调试
用其他浏览器中的调试器也是可以的,作者在开发时习惯使用Google浏览器的内置调试器,遇到的一般情况都可以解决。但是有时有一些特别错误解决不了,这时firebug的强大能力便体现出来了,它可以设置断点、探查错误和逐句执行脚本。
使用JavaScript最简便的方式是使用某种JavaScript工具包或库。这种工具包多如牛毛,其中非常流行的且开发非常活跃并具有许多有用特性的是jQuery,它与配套程序库jQueryUI非常流行。有了它,JavaScript开发工作要变得轻松许多。
到此为止便将JavaScript部分的基础内容介绍完毕了。还是用之前说过的一句话,本部分内容不可能是这么几页就能够解决的,WebGL的开发没有这些基础又不行,所以其目的就是简要介绍一下。