美文网首页《JavaScript 权威指南(第六版)》学习笔记
《JavaScript 权威指南(第六版)》三——语句

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

作者: 静候那一米阳光 | 来源:发表于2017-02-23 16:30 被阅读0次

第五章:语句

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
语句语法小结

相关文章

网友评论

    本文标题:《JavaScript 权威指南(第六版)》三——语句

    本文链接:https://www.haomeiwen.com/subject/cbybwttx.html