首页
语句1
语句1
版权声明:本文为原创内容,转载请声明出处。
原文地址:http://www.excelib.com/article/203/show

简介

语句是用来执行具体功能的,可以分为单条语句和语句块,单条语句以分号结束,语句块用花括号包含,语句块可以包含多条语句。

语句主要由变量(或属性)、操作符和关键字组成,有的语句使用操作符完成,还有的语句需要使用相应的关键字,使用操作符的语句只要按照上一节学生给大家介绍的各种操作符的使用方法来完成就可以了,下面学生来给大家介绍使用关键字完成的语句。

var和let语句

var关键字用来定义变量,如果在函数内部定义则所定义的变量只能在函数内部使用,如果不是在函数内部定义的则会成为全局变量。在函数中使用变量时会优先使用内部变量,只有找不到内部变量时才会使用全局变量(关于变量的更多细节问题学生下一节会给大家详细讲解),我们来看个例子

1
2
3
4
5
6
7
8
9
10
var color = "red";
 function localColor(){
     var color = "blue";
     console.log(color);
 }
 function globalColor(){
     console.log(color);
 }
 localColor();                     //blue
 globalColor();                  //red

localColor方法中由于定义了内部变量color所以会输出blue,globalColor方法中由于没有定义内部变量color所以会输出全局变量red。


多知道点

ES中函数的参数

ES中函数的参数可以看做是一种特殊的内部变量,他的作用域和函数的内部变量一样,不同点只是他不需要使用var关键字来定义而且是在调用时才赋值的。我们来看个例子

1
2
3
4
5
6
var color = "red";
 function paramColor(color){
     console.log(color);
 }
 paramColor();                  // undefined
 paramColor("green");      // green

由于paramColor函数定义了color参数,所以就不会再使用全局变量color了,如果不传入参数则会打印出undefined。

为了让大家看的更加清楚我们对下面的代码设置断点后使用FireBug来调试一下

1
2
3
4
5
6
7
8
function paramF(p1){
     var msg="hello";
     console.log(p1);        //此行设置断点
     for(var i in arguments){
         console.log(arguments[i]);
     }
 }
 paramF("a","b","c");    //a a b c

执行代码后在FireBug中可以看到下面的结构

图1 FireBug调试图

从这里我们可以看出使用参数定义的p1和内部定义的变量msg是一样的。

在ES中函数的参数会自动保存到一个叫arguments的内部变量中,arguments类似数组对象,可以通过他来获取函数调用时的参数,比如下面的例子

1
2
3
4
5
6
7
8
function paramF(p1){
     console.log(p1);
     for(var i in arguments){
         console.log(arguments[i]);
     }
 }
 paramF("a");               //a a
 paramF("a","b","c");       //a a b c

paramF方法中参数p1的值和arguments[0]的值是一样的,函数的参数按顺序依次保存在arguments变量中,而且在调用时传入参数的个数也可以和定义时不一样,所以ES中不存在同名函数重载的用法

ES中的参数的本质其实是通过arguments对象来传递的,如果在方法定义时定义了参数名,那么在调用时解析器会自动创建以定义的参数名为名字的内部变量,并将他们按顺序指向arguments对象的属性值,比如上面例子中paramF方法的参数结构如图2所示

图2 函数参数结构图

在函数被调用时会首先将三个参数a、b、c保存到arguments对象中,然后会依次将函数定义时的参数指向arguments对象的元素,这里因为定义时只定义了一个p1参数,所以就会将p1指向arguments对象的第一个属性元素。

使用var定义的变量是函数级作用域而不是块级作用域,也就是说一个语句块内部定义的变量在语句块外部也可以使用,比如下面的例子

1
2
3
4
5
6
7
function greaterThan36(num){
     if(num>36){
         var result=true;
     }
     console.log(result);
 }
 greaterThan36(81);  //true

greaterThan36方法中的result是在if语句块中定义的,但是在if语句块外部依然可以调用。其实ES的方法在执行时会将其中的所有var定义的变量都统一看做方法的内部变量,所以var定义的变量是function级作用域而不是块级作用域。

在ES2015中可以使用let来定义块级变量,这样定义的变量在块外部就不可以使用了,比如我们将这个例子中的result改用let来定义的话,在if语句块外面就无法使用result来输出结果了。

if-else语句

if-else语句的作用是用来做条件判断的。当需要进行判断时就要使用if语句来完成,使用结构为:

if(条件){
           
语句块;
        }

当条件为真(true)时就会执行语句块里的相应内容,否则不执行,比如下面的例子

1
2
3
4
5
6
7
8
9
function sayHello(lang){
     var hello = "你好";
     if(lang=="en-us"){
         hello = "hello";
     }
     return hello;
 }
 sayHello();         //你好
 sayHello("en-us");  //hello

在sayHello方法中如果传入了值为"en-us"的lang参数则会返回“hello”,否则会返回“你好”。

有些时候需要对多种情况进行判断,这时就需要组合使用if-else语句了,在else后边可以接着写if语句,表示对另外一种情况的判断,也可以不跟if语句,用来表示如果所有条件都不符合时执行的默认操作,比如我们将前面的例子做如下修改

1
2
3
4
5
6
7
8
9
10
11
12
13
function sayHello(lang){
     var hello;
     if(lang=="en-us"){
         hello = "hello";
     }else if(lang=="zh-tw"){
         hello = "妳好";
     }else if(lang=="zh-hk"){
         hello = "妳好";
     }else{
         hello = "你好";
     }
     return hello;
 }

这时sayHello方法就对en-us、zh-tw和zh-hk三种参数都做了判断,如果都不是就会执行最后的默认语句块,也就是将hello设置为“你好”。

if语句的条件还可以使用我们前面介绍过的逻辑操作符来对多个条件进行组合判断,比如用||表示或,用&&表示与,用!表示非,我们上面的sayHello方法可以写成下面的形式

1
2
3
4
5
6
7
8
9
10
11
function sayHello(lang){
     var hello;
     if(lang=="en-us"){
         hello = "hello";
     }else if(lang=="zh-tw" || lang=="zh-hk"){
         hello = "妳好";
     }else{
         hello = "你好";
     }
     return hello;
 }

这里就把lang=="zh-tw"和 lang=="zh-hk"两个条件合并到一起组成一个条件了,当lang为zh-tw或者zh-hk的时候都会给hello赋值为“妳好”。

while语句

while语句和if语句的结构相同,都是一个条件和一个语句块,while语句结构为:

while(条件){
  
            语句块
        }

while语句和if语句不同之处在于:if语句如果条件成立的话会且只会执行一次语句块里的内容,而while语句会反复执行语句块里的内容,直到条件不成立为止。我们看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var step = 5;
 function widthTo(obj, width){
     var owidth = obj.width;
     var isAdd = width - owidth>0;
     while(owidth!=width){
         if(isAdd){
             owidth+=step;
         }else{
             owidth-=step;
         }
         if(width-owidth<step || owidth-width<step){
             owidth = width;
         }
         sleep(50);            //休眠50ms,sleep为自定义函数
         obj.width = owidth;
     }
 }

这个例子中的widthTo方法的作用是将相应对象的width属性修改为指定大小,而且不是一次修改到位而是按指定步长逐次修改,具体修改时需要先判断是变大还是变小然后再修改,每次实际修改前会等待50ms,这么做就可以给人一种简单的动画感觉。这里用的就是while循环,当对象的width属性没有达到目标大小时就会一直向目标方向变化,只有达到目标大小时才会停止并继续向下执行。while语句也可以理解为执行多次if语句,比如上面代码中的while语句相当于

1
2
3
4
if(owidth!=width){     具体操作; }
if(owidth!=width){     具体操作; }
if(owidth!=width){     具体操作; }
。。。

当if语句块足够多的时候也可以完成while语句相同的功能。当然,实际上没有这么用的,这里只是为了让大家更加清晰地理解while语句的原理。

do-while语句

do-while语句和while语句很相似,只是while语句的条件判断在语句执行之前而do-while语句的条件判断在语句执行之后,do-while语句的结构如下

do{
  
            语句块
        } while(
条件)

在do-while语句中,每执行完一次语句之后进行一次条件判断,如果条件成立就会循环执行直到条件不成立为止。由于do-while语句是在执行语句之后判断,所以语句块至少会执行一次。我们看下面的例子

1
2
3
4
5
6
7
8
function getTopLeader(person){
     var leader;
     do{
         leader = person;
         person = leader.getLeader();
     }while(person!=null);
     return leader;
 }

这里的getTopLeader方法是获取TopLeader(最高领导),要找最高领导很简单,随便找个人问他的领导是谁,如果有则继续问他的领导的领导是谁,直到有人说我没有领导了,好,他就是最高领导,我们将他返回去就可以了。我们这里就使用了do-while语句,do-while语句与while语句的区别是do-while语句至少会执行一次语句块的内容,在这上面的例子中是通过查询上级领导,然后判断是否为空,查询上级领导的操作至少会执行一次,所以我们使用了do-while语句。其实do-while语句也可以换成while语句来执行,只需要在执行前先执行一次语句块中的内容就可以了,比如上面的getTopLeader方法也可以写成下面的形式

1
2
3
4
5
6
7
8
9
10
function getTopLeader(person){
     var leader = person;
     person = leader.getLeader();
      
     while(person!=null){
         leader = person
         person = leader.getLeader();
     }
     return leader;
 }

这两种写法的效果是完全一样的。

for语句

for语句也是一种循环语句,而且他比while语句和do-while语句要更加灵活,for语句结构如下

for(表达式1; 表达式2; 表达式3){
  
            语句块
        }

for语句执行步骤为(非常重要

1、  执行表达式1,一般用来定义循环变量;

2、  判断表达式2是否为真,如果不为真则结束for语句块;

3、  执行语句块;

4、  执行表达式3,一般用于每次执行后修改循环变量的值;

5、  重复执行第2步。

大家要特别注意表达式2和表达式3执行的顺序。我们可以通过下面的例子来清晰地看到上述过程

1
2
3
4
5
6
7
8
var k;
 for(var i=0, j=""; i<=1; i++, j=1, k=1){
     console.log(i);
     console.log(typeof i);
     console.log(typeof j);
     console.log(typeof k);
     console.log("----------------");
 }

这里的表达式1和表达式3都使用了逗号来并列使用多条语句。表达式1为var i=0, j="",定义了两个变量i和j,i是number类型,值为0,j为string类型,值为空字符串;表达式2为i<=1,判断i是否小于等于1;表达式3为i++, j=1, k=1,共三条语句,i加1并将j和k设置为1,这里的j由原来的string类型转换为了number类型,并且初始化了k变量。执行后输出结果如下

1
2
3
4
5
6
7
8
9
10
0
number
string
undefined
----------------
1
number
number
number
----------------

从这里可以看出在第一次执行语句块的时候(i为0)表达式1已经执行了,所以这时i为number类型,j为string类型,k还没有初始化。语句块第一次执行完之后会执行表达式3,这时就将j变为了number类型并将k进行了初始化,所以第二次输出的j和k都是number类型了,第二次执行完语句块之后会再次执行表达式3(每次语句块执行完之后都会执行表达式3),这时会将i变为2,然后再判断表达式2的时候就不符合条件了,也就不循环了。

我们再来看一个计算10的阶乘的例子

1
2
3
4
var n=10, result=1;
 for(var i=1; i<=n; i++){
     result*=i;
 }

这里首先定义了两个变量n和result,n用来指定要计算谁的阶乘,result用于保存计算的结果,然后使用for语句执行具体阶乘计算并将结果保存到result中。

另外,for语句中的表达式1、2、3都可以为空,但是他们之间的分号不可以省略,如果不需要相应的表达式可以不写内容直接写分号,比如

1
2
3
4
5
var n=10, result= 1, i=1;
 for(;i<=n;){
     result*=i;
     i++;
 }

这里执行的效果和前面例子中的效果是完全相同的,只是将循环变量i的定义放到了for语句前面并将i++放到了语句块中。需要注意的是虽然这时语句1和语句3都不需要了,但是表达式中的分号是不可以省略的。只有表达式2的这种情况可以简单地使用while循环来完成,比如上面的例子还可以这样来写

1
2
3
4
5
var n=10, result= 1, i=1;
 while(i<=n){
     result*=i;
     i++;
 }

从这里就可以看出for循环的功能是最强大的,而while和do-while循环在特定条件下的使用更加简单

for-in语句

for-in语句可以遍历对象的属性,准确来说是遍历对象中可以遍历的属性(对象的属性是否可遍历会在后面详细讲解),for-in语句的结构如下

for(属性名 in 对象){
  
            语句块
        }

for-in语句遍历过程中直接获取到的是属性名,可以使用方括号来获取属性的值,比如下面的例子

1
2
3
4
var obj = {n:1, b:true, s:"hi"};
 for(var propName in obj){
     console.log(propName + ":" + obj[propName]);
 }

执行后输出结果如下

1
2
3
n:1
b:true
s:hi

在ES2015中新增了for-of语句,他可以直接获取到属性的值。

continue语句

continue用于循环语句块中,作用是跳过本次语句块,进行下一次语句块的执行,在进入下一次执行之前也会判断条件是否成立,如果条件不成立了就会结束循环。另外,如果是for语句的话,在执行判断前还会先执行表达式3。我们看下面的例子

1
2
3
4
5
6
7
8
9
var array = ["a", "b"];
 array[3] = "c";
 for(var i=0; i<array.length; i++){
     console.log("enter block")
     if(!array[i]){
         continue;
     }
     console.log(i+"->"+array[i]);
 }

这里定义了一个数组array,并对其进行了初始化,需要注意的是数组的第一个元素的下标是0,所以array数组的a元素和b元素分别对应下标0和1,然后又给下标3赋值为了c,这时array数组的下标2是没有内容的。array数组初始化完之后使用for循环遍历其中的元素并输出,在输出之前判断是否存在,如果不存在则使用continue语句跳过本次执行(输出)然后进入下一次循环,最后执行结果如下

1
2
3
4
5
6
7
enter block
0->a
enter block
1->b
enter block
enter block
3->c

当i为2时进入了循环语句块,这时会输出“enter into block”,但是当判断到array[2]不存在时就会跳过而不执行输出语句,接着执行i++,然后判断条件并进入i=3时语句块的执行,这时又会输出“enter block”,所以输出的结果中有两次连续的“enter block”。

break语句

break语句可以使用在循环中也可以使用到switch语句中,switch语句中break的用法我们放到switch语句中讲解,在循环语句中break的作用是跳出循环,他跟continue的区别是break会直接结束循环而continue是跳过本次语句块的执行而不会结束循环。我们将前面continue的例子改为break

1
2
3
4
5
6
7
8
9
var array = ["a", "b"];
 array[3] = "c";
 for(var i=0; i<array.length; i++){
     console.log("enter into block")
     if(!array[i]){
         break;
     }
     console.log(i+"->"+array[i]);
 }

这时控制台输出的结果如下

1
2
3
4
5
enter into block
0->a
enter into block
1->b
enter into block

也就是当i=2时会结束循环,所以下标为3的元素就不会被打印了。

return语句

return语句用于函数中,作用是结束函数并返回结果,返回的结果跟在return语句后面,使用空格分开,比如下面的add函数

1
2
3
4
function add(a,b){
     var c = a+b;
     return c;
 }

add函数将两个参数a、b的值相加后赋值给内部变量c并返回。在return语句中除了返回变量之外,也可以直接返回表达式,也就是上面的add函数可以不定义c变量而直接返回a+b,也就是还可以这么写

1
2
3
function add(a,b){
     return a+b;
 }

return除了返回结果外还经常用于结束函数的执行,比如下面的例子

1
2
3
4
5
6
7
8
9
function setColor(obj, color){
     if(typeof obj != "object"){
         return;
     }
     if(color!="red" && color!="green" && color!="blue"){
         return;
     }
     obj.color = color;
 }

这里的setColor函数的作用是将obj的color属性设置为指定的值,首先会判断obj是不是object类型,如果不是则不进行操作直接返回,然后判断color是不是red、green、blue中的一种,如果不是也不进行操作而直接返回,最后将obj的color属性设置为传入的color。这里的return语句主要就起了结束函数执行的作用。

with语句

ES是一种面向对象的语言,对象主要是通过其属性来使用,如果需要对同一个对象的多个属性多次进行操作就需要多次写对象的名称,比如下面的操作

1
2
$("#cur").css("color", "yellow");
 $("#cur").css("backgroundColor", "red");

这里重复使用了$("#cur"),这时就可以使用with语句

1
2
3
4
with ($("#cur")){
     css("color", "yellow");
     css("backgroundColor", "red");
 }

这种写法和前面的写法的作用是一样的,只是将所要操作的对象$("#cur")统一放到with语句的小括号中了。with语句的作用就是指定所操作的对象,不过由于他会影响运行速度而且不利于优化所以不建议大家使用,而且在strict model(严格模式)下已经禁用了with语句。


本节我们就暂时讲到这里,不过语句的内容还没有完,下一节学生接着给大家讲。