《JavaScript 权威指南(第六版)》三——语句

第五章:语句

2017.02.23

语句

语句(statement)是JavaScript整句或命令。

表达式计算值,语句用来执行以使某件事发生。

表达式语句

表达式语句(expression statement):具有副作用的表达式是JavaScript最简单的语句。

赋值语句

i*=3;

递增递减++ --

counter++;

delete运算符

delete o.x;

函数调用

alert(greeting);
window.close();

复合语句和空语句

用花括号将多条语句结合在一起,形成一条复合语句(compound statement)。希望多条语句被当做一条语句使用时,使用复合语句来替代。

{
    x=Math.PI;
    cs=Math.cos(x);
    console.log("cos(π)="+cx);
}

语句块的结尾不需要分号。

空语句(empty statement)允许包含0条语句。

;
for(i=0;i<a.length;a[i++]=0);

声明语句

var和function都是声明语句,声明或定义变量或函数。这些语句定义标识符(变量名和函数名)并给其赋值。

var

var name_1 [=value_1] [,...,name_n[=value_n]]

function

var f=function(x){return x+1;} //①
function f(x){return x+1;} //②

function语句的花括号是必须的,即使只包含一条语句(不同于while if等语句)。

函数声明语句通常出现在JavaScript代码的最顶层,也可以潜逃在其他函数体内。但在嵌套时,函数声明只能出现在所潜逃函数的顶部。函数定义不能出现在if语句,while循环或其他任何语句中。(有些JS的实现允许出现语句的地方都可以进行函数声明,但是不同的实现在细节处理方式上有很大差别,因此将函数声明放在其他的语句内的做法并不具备可移植性。)

①中使用var,只有变量声明提前,初始化代码还在原位。②函数名称和函数体均提前。

条件语句

条件语句是通过判断指定表达式的值来决定执行还是跳过某些语句。

if/else if

if(expression){
    //
}
else if{
    //
}...{
    //
}else{
    //
}

没有花括号时,else总是和最近的if语句相匹配。所以建议使用花括号,即使分支只有一条语句。

switch

此处的case匹配使用===恒等运算符比较。

switch(expression){
    case expression1:
        statements1;
        [break;]
    case expression2:
        statements2;
        [break;]
    case expression3:
        statements3;
        [break;]
    ...
    default:
        statements;
}

循环

while

while(expression){
    statements
}

do/while

do {
    statements
}while(expression)

for

for(initialize;test;increment){
    statements
}

相当于

initialize;
while(test){
    statements
    increment;
}

死循环

for(;;)

相当于

while(true)

for/in

for(varibale in object){
    statement
}

用for in循环遍历对象属性成员:

for(var p in o){
    console.log(p+":"+o[p]);//p是属性名,o[p]是属性值
}

注意:只要for/in 的variable值可以当做赋值表达式的左值,它可以是任意表达式。每次循环都会计算这个表达式。

将对象的所有属性名复制到一个数组中:

var o={x:1,y:2,z:3};
var a=[],i=0;
for(a[i++] in o);

枚举数组索引:

> var a=[1,2,,,,4]
undefined
> del
0
1
5

for/in循环并不会遍历对象的所有属性,只有"可枚举"(enumerable)的属性才会遍历到。JavaScript语言核心所定义的内置方法就不是"可枚举的"。对象可以继承其他对象的属性,集成的自定义属性也可以枚举出来。如果for/in循环体删除了还未枚举的属性,那么这个属性将不会再枚举到。如果循环体定义了新属性,这些属性通常不会被枚举到。

属性枚举的顺序

实际上,主流浏览器厂商的JavaScript实现是按照属性定义的先后顺序来枚举简单对象的属性,先定义的先枚举。如果使用对象直接量的形式创建对象,则将按照直接量中属性的出现顺序枚举。

More 关于枚举顺序

跳转

break:跳转到循环或者其他语句的结束。
continue:终止本次循环的执行并开始下一次循环的执行。
return:让解释器跳出函数体的执行,并提供本次调用的返回值。
throw:触发或者抛出一个异常,与try、catch、finally语句一同使用。

标签语句

identifier:statement

通过break,continue跳转。break和continue是JavaScript中唯一可以使用语句标签的语句。

示例

mainloop:while(token!=null){
    //...
    continue mainloop;
}

用作标签的identifier必须是合法的标识符,不能使保留字。标签的命名空间与变量函数的命名空间不同,因此可以使用同一个额标识符作为语句标签和作为变量名或函数名。语句标签只有在它所起作用的语句内是有定义的。一个语句标签不能喝它内部的语句标签重名,但在两个代码段不相互嵌套的情况下可以出现同名的语句标签。带有标签的语句还可以带有标签。

outerloop: 
for (var i = 0; i < 10; i++) { 
    innerloop:  
    for (var j = 0; j < 10; j++) { 
        if (j > 3){ 
          break; 
        } 
        if (i == 2) { 
          break innerloop; 
        } 
        if (i == 4) { 
          break outerloop; 
        } 
    document.write("i=" + i + " j=" + j + "<br>"); 
    } 
} 

break 语句

单独使用break语句的作用是立即退出最内层的循环或switch语句。

break;

break 关键字后面紧跟一个语句标签。

break labelname;

当break和标签一块使用时,程序将跳转到这个标签所标识的语句块的结束,或者直接终止这个闭合语句块的执行。当没有任何闭合语句块指定break所用的标签,这时会产生一个语法错误。当使用这种形式的break语句时,带标签的语句不应该是循环或者switch语句,因为break可以跳出任何闭合的语句块。这列的语句可以是花括号括起来的一组语句,使用同一个标签来标识这一组语句。

break和labelname之间不能换行。因为换行会在break后面补分号。

break无论带不带标签,都无法越过函数的便捷。在函数内部无法通过标签跳转到函数外部。

continue 语句

执行下一次循环。

continue;

continue后面紧跟一个语句标签。

continue labelname;

不管continue带不带标签,只能在循环体内使用,否则会报语法错误。

带标签的continue语句可以用在嵌套的循环中,用以跳出多层次嵌套的循环体逻辑。

continue和labelname之间不能换行。

return 语句

函数中的return语句是指定函数调用后的返回值。

return expression;

只能在函数体内出现,否则语法错误。

如果没有return语句。函数一次执行函数体内的每一条语句直到结束,表达式结果返回undefined。

return语句不必带有expression,这样函数也会返回undefined。

return和expression之间不能有换行。

throw 语句

异常(exception)是当发生了某种异常情况或错误时产生的一个信号。抛出异常,就是用信号通知发生了错误或异常装潢。捕获异常是指处理这个信号,即采取必要的手段从异常中恢复。在JavaScript中,当产生运行时错误或者程序使用throw语句就会显式地抛出异常。使用try/catch/finally语句可以捕获异常。

throw expression;

例如:

function f(x){
    if(x<0) throw new Error("x 不能是负数");
    return x;
}
f(-1);//Error: x 不能是负数

当抛出异常时,JavaScript解释器会当即停止当前正在执行的逻辑,并跳转至就近的异常处理程序(try/catch/finally语句段)。如果抛出异常的代码块没有相关联的catch一句,解释器会检查更高层的闭合代码块,以此类推,直到找到一个异常处理程序位置。
如果没有处理语句,异常将向上传播到调用该函数的代码。这样,异常就会沿着JavaScript方法的语法结构和调用栈向上传播。如果没有任何异常处理程序,JavaScript将把异常当做程序错误来处理,并报告给用户。

try/catch/finally 语句

各语句块都需要用花括号括起来。不能省略。

try{
    //通常来讲,此处代码从头到尾执行不会有问题,有事会抛出异常,或由throw语句直接抛出或由方法间接抛出
}
catch(e){
    //当try语句抛出异常时执行。通过局部变量e或得对Error对象或者抛出的其他值的引用。
    //这里的代码块可以基于某种原因处理这个异常,也可以忽略这个异常或者通过throw语句重新抛出异常
}
finally{
    //不管try语句块是否抛出异常,这里总会执行。终止try语句块的方式:
    // 1)正常终止,执行完最后一条语句
    // 2)通过break,continue,renturn终止
    // 3)抛出异常,被catch捕获
    // 4)抛出异常,异常未被捕获,继续向上传播
}

catch子句中的标识符具有块级作用域,只在catch内有定义。不管try代码执行了多少,只要try语句中有一部分代码执行了,finally从句就会执行。

More

其他语句

with 语句

域链(scope chain),一个可以按序检索的对象列表,通过它可以进行变量名解析。

with 可用于临时扩展作用域链。

with (object)
statement

这条语句将object添加到作用域头部,然后执行statement,最后把作用域链恢复到原始状态。

严格模式中禁止使用with。使用with语句的JavaScript代码难于优化,运行更慢。

例如:

document.forms[0].address.value

with(document.forms[0]){
    name.value="";
    address.value="";
    email.value="";
}

等价于

var f=document.forms[0];
f.name.value="";
f.address.value="";
f.email.value="";

只有在查找标识符的时候才用到作用域链,创建新的变量的时候不适用。

with(o) x=1;//如果对象o有属性x,那么代码给属性赋值。如果没有,则等价于不含有with语句的情景。给局部变量或全局变量赋值或初始化全局变量并赋值。

debugger 语句

debugger语句通常什么也不做。调试程序可用并且运行时,JavaScript将会以调试模式运行。实际上,此语句用于产生断电,JavaScript代码执行将会停止在短点的位置。

function f(o){
    if (o===undefined) debugger;
}

"use strict"

ES5引入的指令。指令不是语句(但非常接近于语句)。

  • 不包含任何语言的关键字。指令仅仅是一个包含一个特殊字符串直接量的表达式。(单引号或双引号)
  • 只能出现在脚本代码的开始或者函数体的开始、任何实体语句之前。

目的是说明(脚本或函数中)后续的代码将会解析为严格代码。如果顶层使用"use strict",那么它们就是严格代码。eval()内代码同样是严格代码。

  • 严格模式禁止使用with语句
  • 严格模式中,所有变量都要先声明。如果个未命名的变量,函数,函数参数,catch从句参数或全局对象的属性赋值,都会抛出引用错误异常。
  • 严格模式中,调用的函数中的一个this值是undefined。非严格模式下this总是全局对象。可以用这种特性判断JavaScript是否支持严格模式。var hasStrictMode=(function(){"use strict";return this===undefined}());
  • 严格模式中,传入eval()的代码不能调用程序所在的上下文中声明变量或定义函数。变量和函数的定义是在eval()创建的新作用域中,这个作用域在eval()返回时就弃用了。
  • 严格模式中,函数里的arguments对象拥有传入的函数值的静态副本。非严格模式中,arguments对象具有"魔术般"的行为,arguments里的数组元素和函数参数都是指向同一个值的引用。
  • 严格模式中,delete跟随非法的标识符(变量,函数,函数参数)时,会抛出一个语法错误异常。(非严格模式下,delete什么也没做并返回false);试图删除一个不可配置的属性将抛出一个类型错误异常(非严格模式中不会报错)。两种模式下删除非左值都返回true。
  • 严格模式中,函数声明中存在两个及以上同名的参数会产生语法错误(非严格模式中不会报错,后者覆盖前者):实际Chrome测试,严格模式下不会报错,后者覆盖前者。
  • 严格模式中,函数声明中存在两个或多个同名参数会报错(非严格模式下,会覆盖)
  • 严格模式中,不许晕使用八进制整数直接量。
  • 严格模式中,eval和arguments当做关键字,值不可以更改。不能给其赋值,不能声明为变量、用做函数名或用作catch块标识符。
  • 严格模式中限制了对调用栈的检测能力。 arguments.caller和arguments.callee都会抛出类型错误异常。严格模式函数同样具有calle和arguments属性,访问这两个属性时将抛出类型错误异常(有一些JavaScript的实现在费严格模式里定义了这些非标准的属性)

示例,chrome58 dev 下

【严格模式下】

<script>
    "use strict";
    function f(){
        return this;
    }
    console.log(f());//输出 undefined
    console.log(delete 1===true);// true
    var o={x:1,x:2};
    var o=123;
    console.log(o);//123
    function ff(x,x){
        return (x+x);
    } //Uncaught SyntaxError: Duplicate parameter name not allowed in this context
    console.log(ff(1,2));
    var m={x:2}
    function c(o){
        o.x=1;
    };
    c(m);
    console.log(m);//Object {x:1}
</script>

【非严格模式下】

<script>
    function f(){
        return this;
    }
    console.log(f());//输出 window对象
    console.log(delete 1===true);// true
    var o={x:1,x:2};
    var o=123;
    console.log(o);//123
    function ff(x,x){
        return (x+x);
    } //4
    console.log(ff(1,2));
    var m={x:2}
    function c(o){
        o.x=1;
    };
    c(m);
    console.log(m);//Object {x:1}
</script>

chrome 58 dev下

> (function(){"use strict";return this===undefined}());
true

node 6.9.5下

> (function(){"use strict";return this===undefined}());
true
语句语法小结
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容