第二章 JS语法
- 语句
- 变量和数组
- 操作符
- 条件语句和循环语句
- 函数与对象
2.1 准备工作
用JS写的代码必须通过HTML/XHTML文档才能执行。两个方法:
- 将JS代码放到文档
<head>
标签中的<script>
标签之间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Example</title>
<script>
JavaScript goes here...
</script>
</head>
<body>
mark-up goes here...
</body>
</html>
- 把JS代码存为一个扩展名为.js的独立文件。典型的做法是在文档的
<head>
部分放一个<script>
标签,并把它的src属性指向该文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Example</title>
<script src="file.js"></script>
</head>
<body>
mark-up goes here...
</body>
</html>
- 但最好的做法是把
<script>
标签放到HTML文档的最后,</body>
标签之前。这样能使浏览器更快的加载页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Example</title>
</head>
<body>
mark-up goes here...
<script src="file.js"></script>
</body>
</html>
程序语言分为解释型和编译型两大类。JAVA/C++等需要一个编译器(complier)。编译器是一种程序,能够把用JAVA等高级语言写出来的源代码翻译为直接在计算机上执行的文件。
解释型语言不需要编译器,他们仅需要解释器。在互联网环境下,web浏览器负责完成有关的解释和执行工作。解释型的语言代码中的错误只能等到解释器执行到有关代码才能发现。
2.2 语法##
与其他脚本语言一样,都由一系列指令构成。这些指令叫做语句(statement)。
2.2.2 注释###
- //注释一行
-
/* abc */
注释一段 - ``HTML风格,如果使用,JS要求每行开头都由`
2.2.3 变量###
赋值(assignment)
mood="happy";
age=33;
一个变量被赋值以后,就说该变量包含这个值。
alert(mood);
alert(age);
JS中没要求必须提前声明变量,但这是一个好习惯。下面语句对变量做出了声明:
var mood;
var age;
或者:var mood, age;
甚至可以把声明和赋值一起完成:
var mood="happy";
var age=33;
甚至还可以这样:var mood="happy", age=33;
JS变量名区分大小写。
为了让比较长的变量易读,可在变量名中加下划线。(第一个字符不允许是数字)。
另一种是用驼峰格式(camel case),删除中间的空白(下划线),后面的每个新单词改用大写字母开头:
var myMood="happy";
通常驼峰格式是函数名,方法名和对象属性名命名的首选格式。
2.2.4 数据类型###
有些语言要求在声明变量的同时还必须声明变量的数据类型,此做法叫类型声明(typing)
JS是弱类型(weakly typed)语言,意味着可以再任何阶段改变变量的数据类型
var age= "thirty three";
age=33;
这在JS中是可以的。
-
字符串,字符串由零个或多个字符构成。
var mood ="don't ask";
-
数值,可以用整数,也可以是浮点数
var age=33.25;
-
布尔值(boolean)
var sleeping=true;
但是var married="true";
就是设成了字符串
2.2.5 数组###
用一个变量来存储一组值,就需要使用数组(array)
数组是指用一个变量表示一个值的集合,集合中的每个值都是这个数组的一个元素(element)。在JS中,数组可以用关键字Array声明。声明的同时还可以指定数组初始元素的个数、长度。
var beatles=Array(4);
如果无法预知数组长度,可以不声明。
var beatles=Array();
向数组中添加元素称为填充 (populating)
array[index]=element;
例如:
var beatles=Array(4);
beatles[0]="John";
beatles[1]="Paul";
beatles[2]="George";
beatles[3]="Ringo";
然后就可以通过标值来获取元素,例如用beatles[2]
来获取"George"。
注意数组下标是从0开始计数的
或者还有一种简单的方式:声明数组的同时进行填充
var beatles=Array("John","Paul","George","Ringo");
数组元素也可以是混合的数据类型:
var lennon=["John",1900,false];
数组元素还可以是变量:
var name="John";
beatles[0]=name;
或者可以指定变量赋值给数组:
var names=["Ringo","John","Geogre","Paul"];
beatles[1]=names[3];
数组还可以包含别的数组:
var lennon=["John",1900,false];
var beatles=[];
beatles[0]=lennon;
如此,beatles数组的第一个元素就是另外一个数组,要想获得二级数组的值要用更多的括号,beatles[0][0]就是"John",beatles[0][1]就是1900,beatles[0][2]就是false。
这种方法的缺点在于不得不记住每个下标的数字。首先看一种更可读的填充数组的方式,然后介绍存放数据的首选方式:将数据保存为对象
2.2.5.1 关联数组####
如果在填充数组的时候只给出了元素的值,这个数组就是一个传统数组,他的各个元素的下标将被自动创建和刷新。
可以通过在填充数组时为每个新元素明确的给出下标来改变这种默认的行为。在为新元素给出下标时,不必局限于整数数字,还可使用字符串。
var lennon=Array();
lennon["name"]="John";
lennon["year"]=1900;
lennon["living"]=false;
这样的数组就是关联数组
关联数组的理解:
由于使用了字符串来替代数字值,因而代码更具有可读性。但这不是一种好习惯,不推荐使用。本质上,在创建关联数组时,创建的都是Array对象的属性。在JS中所有的变量都是某种类型的对象。比如一个布尔值就是一个Boolean类型的对象。本例子中实际上是给lennon数组添加了name,year,living三个属性。理想情况下,不该修改Array对象的属性,二应该使用通用的对象(Object)。
2.2.6 对象###
上一节的lennon数组可以变成下面的对象:
var lennon=Object();
lennon.name="John";
lennon.year=1900;
lennon.living=false;
创建对象使用Object关键字,不使用方括号和下标来获取元素,而是点号来获取属性。
创建对象还有一种更简洁的语法,花括号语法:
{propertyName:value, propertyName:value}
比如Lennon对象可以写成这样:
var lennon={name:"John", year:1940, living:false};
如果现在还用lennon来填充beatles数组,就简单多了:
var beatles=Array();
beatles[0]=lennon;
此时只需beatles[0].name
就能得到"John"
再举个例子:
var beatles={};
beatles.vocalist=lennon;
现在beatles.vocalist.name
的值就是"John"
2.3 操作##
JS也要做一些计算和处理数据,也就需要完成一些操作(operation).
算术操作符###
+,-,=,/,*,+=
给一个数值变量加1,year++
给一个数值变量减1,year--
加号还可用于字符串,把两个字符串合二为一。这种操作叫拼接(concatenation)
var message="I am feeling "+"happy";
或者
var mood="happy";
var message="I am feeling "+mood;
注意,如果将字符串和数值拼接在一起,结果是更长的字符串
alert("10"+20);
alert(10+20);
第一条返回“1020”,第二条返回30
2.4 条件语句##
if 语句:
if(condition){
statements;
}
if语句的花括号并不是必不可少的。如果只有一条语句的话,就可以不用花括号。
if(1〉2) alert("the world has gone mad!");
if还可以有一个else子句,包含在else子句中的语句会在给定条件为假时执行。
if (1>2){
alert("1");
}else{
alert("2");
}
注意单个等号是赋值,双等号才是判定是否一致
var my_mood="happy";
if(my_mood=="happy")
全等===
相等操作符==并不表示严格相等,例如false与一个空字符比较:
var a=false;
var b="";
if(a==b){
alert("a equals b");
}
这条语句的求值结果为true,因为相等操作符==认为空字符串与false的含义相同。要进行严格比较就要用全等===。这个操作符会执行严格的比较,不仅比较值,而且会比较变量的类型。
对于不等操作符!=也是一样的,如果想比较严格的不相等,就要使用!==。
逻辑操作符
与: &&
或:||
非:!
2.5 循环语句##
工作原理:只要给定条件仍能得到满足,包含在循环语句里的代码就将重复的执行下去;一旦给定条件的求值结果不再是true,循环也就到此为止。
while循环
while(condtion){
statements;
}
do...while循环###
在某些场合,我们希望循环语句内部的代码至少执行一次,就要用到do...while循环:
do{
statements;
}while(condition);
即使循环控制条件的首次求值结果是false,包含在花括号里的语句也至少会被执行一次。
var count=1;
do{
alert(count);
count++;
}while(count<11);
for循环###
for循环只是while循环的一种遍体。
initialize;
while(condition){
statements;
increment;
}
而for循环不过是进一步改写为更紧凑的形式:
for(initial condition; test condition; alter condition){
}
用for循环的好处是循环控制结构更清晰,与循环有关的所有内容都包含在圆括号里。这样我们可以知道那些代码将被执行多少次。
注意:
for循环最常见的用途是对某个数组里的全体元素进行遍历。这往往要用到数组的array.length属性。一定要记住,数组的下标是从0开始而不是1开始。
2.6 函数##
如果需要多次使用同一段代码,可以把他们封装成一个函数。事实上,每个函数都是一个短小的脚本。
作为一种良好的习惯,应该先对函数作出定义再调用他们。
function shout(){
var beatles=Array("John","Paul","George","Ringo");
for(var count=0;count<beatles.length;count++){
alert(beatles[count]);
}
}
可以随时使用如下的语句来调用这个函数:
shout();
昧旦需要反复做一件事时,都可以利用函数来避免重复键入大量相同内容。不过函数的真正威力体现在,你可以把不同的数据传递给他们,而他们将使用这些数据去完成预订的操作
我们把传递给函数的数据称为参数(argument)。
定义一个函数的语法:
function name(arguments){
statements;
}
JS提供里许多内建函数,如alert()。在定义函数时,可以为声明任意多个参数,只要用逗号把他们分割开来就行,在函数内部,可以像使用普通变量那样使用他的任何一个参数。
函数的返回数据
return语句:
function multiply(num1, num2){
var total=num1 *num2;
return total;
}
函数的真正价值体现在,我们还可以把他们当作一种数据类型来使用,这以为着可以把一个函数的调用结果赋给一个变量
var temp_fahrenheit=95;
var temp_celsius=convertToCelsius(temp_fahrenheit);
alert(temp_celsius);
驼峰命名法
在命名变量时,用下划线来分隔各个单词。
在命名函数时,从第二个单词开始把每个单词的第一个字母写成大写形式。
与变量的情况一样,JS不允许函数的名字里包含空格。
变量的作用域###
变量既可以是全局的,也可以是局部的。他们之间的区别,其实是变量的作用域(scope)。
全局变量(global variable)
可以在脚本中的任何位置被引用。一旦在某个脚本里声明了全局变量,就可以从这个脚本的任何位置包括函数内部引用它。全局变量的作用域时整个脚本。
局部变量(local variable)
只存在于声明它的那个函数内部,在那个函数的外部是无法引用它的。作用域仅限于某个特定的函数。
如果在函数中使用来var
,那个变量就是一个局部变量
如果没有使用var
,那就是一个全局变量,如果脚本里已经存在一个与之同名的全局变量,这个函数就会改变那个全局变量的值
举个例子:
function square(num){
total = num * num;
return total;
}
var total = 50;
var number = square (20);
alert (total);
这些代码会导致全局变量total的值变为400;我的本意时让square()函数只把它计算出来的平方值返回给变量number,但因为未把这个函数内部的total变量明确的声明为局部变量,这个函数把名字同样时total的那个局部变量的值也改变了。
例子应这么写:
function square(num){
var total = num*num;
return total;
}
记住,函数在行为方面应该像一个自给自足的脚本。在定义一个函数时,我们一定要把它内部的变量全都明确的声明为局部变量。如果你总是在函数里使用var
关键字来定义变量,就能避免任何形式的二义性隐患。
2.7 对象##
对象时自包含的数据集合,包含在对象里的数据可以通过两种形式访问,属性(property)和方法(method):
属性是隶属于某个特定对象的变量
方法是只有某个特定对象才能调用的函数
对象就是由一些属性和方法组合在一起而构成的一个数据尸体实体
在JS中,属性和方法都是使用“点”来访问:
Object.property();
Object.method();
例如:
Person.mood;
Person.age;
Person.walk();
Person.sleep();
这些属性和方法全部集合在一起,就得到来一个Person对象。
为了使用Person对象来描述一个特定的人,需要创建一个Person对象的实例(instance)
为给定对象创建一个实例,需要使用new
关键字
var jeremy = new Person;
上面这条语句创建一个Person对象的新实例jeremy,我们就可以使用Person的属性来检索关于jeremy的信息:
jeremy.age;
jeremy.mood;
2.7.1 内建对象###
预先定义好的对象,就是内建对象(native object)。数组就是其中一种,当我们用new
去初始化一个数组时,其实就是在创建一个Array对象的新实例。
var beatles = new Array();
beatles.length();
其他的内建对象,比如 Math对象和 Date对象。
Math对象的round方法可以把十进制的数值舍入一个与之最接近的整数:
var num=7.561;
var num=Math.round(num);
alert(num);
Date对象可以用来存储和检索与特定日期和事件有关的信息。在创建Date对象 的新实例时,JS解释器会使用当前日期和时间对它进行初始化。
var current_date = new Date();
还有getDay(),getHours(),getMonth()等一系列方法:
var today = current_date.getDay();
2.7.2 宿主对象###
还有些预先定义好的其他对象,他们不是由JS而是由运行环境本身提供。具体到web应用,就是浏览器。由浏览器提供的与定义对象被称为宿主对象(host object)。
宿主对象包括Form,Image和Element等。我们可以通过他们获得关于网页上的表单、图像和各种表单元素等信息。
另一种宿主对象也能获得网页上的任何一个元素信息,它就是document对象。
2.7.3 用户定义对象###
user-defined object, 由程序员自行创建的对象,本书不讨论。