我是小又又,住在武汉,做了两年新媒体,准备用 6 个月时间转行前端。
今日学习目标
昨天基于一些页面搜索,学习了《JavaScirpt 高级程序设计》(第三版) 第 3 章节中的 3.5 操作符。所以,今天主要是基于搜索来仔细学习 第 3 章节中的 3.6 语句,又是适合学习的一天,加油,小又又!!!!
今日学习概要
ECMA-262 规定了一组语句,从本质上看,语句定义了 ECMAScript 中的主要语法,语句通常使用一或多个关键字来完成给定任务。
语句可以很简单,例如通知函数退出
也可以比较复杂,例如指定重复执行某个命令的次数
- if 语句
- do-while 语句
- while 语句
- for 语句
- for-in 语句
- label 语句
- break 和 continue 语句
- with 语句
- switch 语句
- debugger 语句
if 语句
基础说明
当指定条件为真,if 语句会执行一段语句。如果条件为假,则执行另一段语句。
function testNum(a) {
let result;
if (a > 0) {
result = 'positive';
} else {
result = 'NOT positive';
}
return result;
}
console.log(testNum(-5));
// expected output: "NOT positive"
语法说明
if (condition)
statement1
[else
statement2]
语句名 | 具体说明 |
---|---|
condition | 值为真或假的表达式 |
statement1 | 当condition 为真时执行的语句。可为任意语句,包括更深层的内部if 语句。要执行多条语句,使用块语句({ ... })将这些语句分组;若不想执行语句,则使用空语句。 |
statement2 | 如果condition 为假且 else 从句存在时执行的语句。可为任意语句,包括块语句和嵌套的if 语句。 |
详细说明
多层 if...else
语句可使用 else if
从句。
注意:在 Javascript 中没有 elseif
(一个单词)关键字。
if (condition1)
statement1
else if (condition2)
statement2
else if (condition3)
statement3
...
else
statementN
要看看它如何工作,可以调整下嵌套的缩进
if (condition1)
statement1
else
if (condition2)
statement2
else
if (condition3)
...
要在一个从句中执行多条语句,可使用语句块({ ... }
)。通常情况下,一直使用语句块是个好习惯,特别是在涉及嵌套if
语句的代码中:
if (condition) {
statements1
} else {
statements2
}
不要将原始布尔值的true
和false
与Boolean对象的真或假混淆。任何一个值,只要它不是 undefined
、null
、 0
、NaN
或空字符串(""
),那么无论是任何对象,即使是值为假的Boolean对象,在条件语句中都为真。
例如:
var b = new Boolean(false);
if (b) //表达式的值为true
使用案例
使用
if...else
if (cipher_char === from_char) {
result = result + to_char;
x++;
} else {
result = result + clear_char;
}
使用
else if
注意,Javascript中没有`elseif`语句。但可以使用`else`和`if`中间有空格的语句:
if (x > 5) {
/* do the right thing */
} else if (x > 50) {
/* do the right thing */
} else {
/* do the right thing */
}
条件表达式中的赋值运算
建议不要在条件表达式中单纯的使用赋值运算,因为粗看下赋值运算的代码很容易让人误认为是等性比较。
比如,不要使用下面示例的代码:
if (x = y) {
/* do the right thing */
}
如果你需要在条件表达式中使用赋值运算,用圆括号包裹赋值运算。例如:
if ((x = y)) {
/* do the right thing */
}
do-while 语句
基础说明
do...while
语句创建一个执行指定语句的循环,直到condition
值为 false。在执行statement
后检测condition
,所以指定的statement
至少执行一次。
语法说明
do
statement
while (condition);
语句名 | 具体说明 |
---|---|
statement | 执行至少一次的语句,并在每次 condition 值为真时重新执行。想执行多行语句,可使用block 语句({ ... } )包裹这些语句。 |
condition | 循环中每次都会计算的表达式。如果 condition 值为真, statement 会再次执行。当 condition 值为假,则跳到do...while 之后的语句。 |
使用案例
下面的例子中,do...while
循环至少迭代一次,并且继续迭代直到 i
不再小于 5 时结束。
HTML 内容
<div id="example"></div>
JavaScript 内容
var result = '';
var i = 0;
do {
i += 1;
result += i + ' ';
} while (i < 5);
document.getElementById('example').innerHTML = result;
结果
while 语句
基础说明
while 语句可以在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时结束循环。
let n = 0;
while (n < 3) {
n++;
}
console.log(n);
// expected output: 3
语法说明
while (condition)
statement
语句名 | 具体说明 |
---|---|
condition | 条件表达式,在每次循环前被求值。如果求值为真,statement 就会被执行。如果求值为假,则跳出while 循环执行后面的语句。 |
statement | 只要条件表达式求值为真,该语句就会一直被执行。要在循环中执行多条语句,可以使用块语句({ ... } )包住多条语句。注意:使用break 语句在condition 计算结果为真之前停止循环。 |
使用案例
下面的 while
循环会一直循环若干次,直到 n
等于 3
。
var n = 0;
var x = 0;
while (n < 3) {
n++;
x += n;
}
在每次循环中,n
都会自增 1
,然后再把 n
加到 x
上。因此,在每轮循环结束后,x
和 n
的值分别是:
- 第一轮后:
n
= 1,x
= 1 - 第二轮后:
n
= 2,x
= 3 - 第三轮后:
n
= 3,x
= 6
当完成第三轮循环后,条件表达式n
< 3 不再为真,因此循环终止。
for 语句
基础说明
for
语句用于创建一个循环,它包含了三个可选的表达式,这三个表达式被包围在圆括号之中,使用分号分隔,后跟一个用于在循环中执行的语句(通常是一个块语句)。
let str = '';
for (let i = 0; i < 9; i++) {
str = str + i;
}
console.log(str);
// expected output: "012345678"
语法说明
for ([initialization]; [condition]; [final-expression])
statement
语句名 | 具体说明 |
---|---|
initialization | 一个表达式 (包含赋值语句) 或者变量声明。典型地被用于初始化一个计数器。该表达式可以使用 var 或 let 关键字声明新的变量,使用 var 声明的变量不是该循环的局部变量,而是与 for 循环处在同样的作用域中。用 let 声明的变量是语句的局部变量。该表达式的结果无意义。 |
condition | 一个条件表达式被用于确定每一次循环是否能被执行。如果该表达式的结果为 true,statement 将被执行。这个表达式是可选的。如果被忽略,那么就被认为永远为真。如果计算结果为假,那么执行流程将被跳到 for 语句结构后面的第一条语句。 |
final-expression | 每次循环的最后都要执行的表达式。执行时机是在下一次 condition 的计算之前。通常被用于更新或者递增计数器变量。 |
statement | 只要condition 的结果为true就会被执行的语句。要在循环体内执行多条语句,使用一个块语句({ ... } )来包含要执行的语句。没有任何语句要执行,使用一个空语句(; )。 |
使用案例
使用
for
以下例子声明了变量 i
并被初始赋值为 0
,for
语句检查 i
的值是否小于 9,如果小于 9,则执行语句块内的语句,并且最后将 i
的值增加 1。
for (var i = 0; i < 9; i++) {
console.log(i);
// more statements
}
可选的
for
表达式
for
语句头部圆括号中的所有三个表达式都是可选的。
例如,初始化块中的表达式没有被指定:
var i = 0;
for (; i < 9; i++) {
console.log(i);
// more statements
}
像初始化块一样,条件块也是可选的。如果省略此表达式,则必须确保在循环体内跳出,以防创建死循环。
for (var i = 0;; i++) {
console.log(i);
if (i > 3) break;
// more statements
}
你当然可以忽略所有的表达式。同样的,确保使用了 break
>语句来跳出循环并且还要修改(增加)一个变量,使得 break 语句的条件在某个时候是真的。
var i = 0;
for (;;) {
if (i > 3) break;
console.log(i);
i++;
}
使用无语句的
for
以下 for
循环计算 final-expression 部分中节点的偏移位置,它不需要执行一个 statement
或者一组 block statement
,因此使用了空语句。
function showOffsetPos(sId) {
var nLeft = 0, nTop = 0;
for (
var oItNode = document.getElementById(sId); /* initialization */
oItNode; /* condition */
nLeft += oItNode.offsetLeft, nTop += oItNode.offsetTop, oItNode = oItNode.offsetParent /* final-expression */
); /* 分号 semicolon */
console.log('Offset position of \'' + sId + '\' element:\n left: ' + nLeft + 'px;\n top: ' + nTop + 'px;');
}
/* Example call: */
showOffsetPos('content');
// Output:
// "Offset position of "content" element:
// left: 0px;
// top: 153px;"
提示:这里的分号是强制性的,是 JavaScript 中的少数几种强制分号的情况。如果没有分号,循环声明之后的行将被视为循环语句。
for-in 语句
基础说明
for...in
语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。
语法说明
for (variable in object)
statement
语句名 | 具体说明 |
---|---|
variable | 在每次迭代时,variable会被赋值为不同的属性名。 |
object | 非Symbol类型的可枚举属性被迭代的对象。 |
详细说明
for...in
循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。像 Array
和 Object
使用内置构造函数所创建的对象都会继承自Object.prototype
和String.prototype
的不可枚举属性。
例如 String
的 indexOf()
方法或 Object
的toString()
方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。
删除,添加或者修改属性
for...in
循环以任意序迭代一个对象的属性(请参阅delete
运算符,了解为什么不能依赖于迭代的表面有序性,至少在跨浏览器设置中)。
如果一个属性在一次迭代中被修改,在稍后被访问,其在循环中的值是其在稍后时间的值。一个在被访问之前已经被删除的属性将不会在之后被访问。在迭代进行时被添加到对象的属性,可能在之后的迭代被访问,也可能被忽略。
通常,在迭代过程中最好不要在对象上进行添加、修改或者删除属性的操作,除非是对当前正在被访问的属性。
这里并不保证是否一个被添加的属性在迭代过程中会被访问到,不保证一个修改后的属性(除非是正在被访问的)会在修改前或者修改后被访问,不保证一个被删除的属性将会在它被删除之前被访问。
数组迭代和
for...in
**
提示:for...in
不应该用于迭代一个 Array
,其中索引顺序很重要。
数组索引只是具有整数名称的枚举属性,并且与通用对象属性相同。不能保证for ... in
将以任何特定的顺序返回索引。
for ... in
循环语句将返回所有可枚举属性,包括非整数类型的名称和继承的那些。
因为迭代的顺序是依赖于执行环境的,所以数组遍历不一定按次序访问元素。因此当迭代访问顺序很重要的数组时,最好用整数索引去进行for
循环(或者使用 Array.prototype.forEach()
或 for...of
循环)。
仅迭代自身的属性
如果你只要考虑对象本身的属性,而不是它的原型,那么使用 getOwnPropertyNames()
或执行 hasOwnProperty()
来确定某属性是否是对象本身的属性(也能使用propertyIsEnumerable
)。或者,如果你知道不会有任何外部代码干扰,可以使用检查方法扩展内置原型。
使用案例
下面的函数接受一个对象作为参数。被调用时迭代传入对象的所有可枚举属性然后返回一个所有属性名和其对应值的字符串。
var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
下面的函数说明了
hasOwnProperty()
的用法:继承的属性不显示。
var triangle = {a: 1, b: 2, c: 3};
function ColoredTriangle() {
this.color = 'red';
}
ColoredTriangle.prototype = triangle;
var obj = new ColoredTriangle();
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
console.log(`obj.${prop} = ${obj[prop]}`);
}
}
// Output:
// "obj.color = red"
label 语句
基础说明
标记语句可以和 break
或 continue
语句一起使用。标记就是在一条语句前面加个可以引用的标识符(identifier)。
let str = '';
loop1:
for (let i = 0; i < 5; i++) {
if (i === 1) {
continue loop1;
}
str = str + i;
}
console.log(str);
// expected output: "0234"
备注: 使用标记的循环或语句块非常罕见。通常情况下,可以使用函数调用而不是(基于标记的)循环跳转。
语法说明
label :
statement
语句名 | 具体说明 |
---|---|
label | 任何不属于保留关键字的 JavaScript 标识符。 |
statement | JavaScript 语句。break 可用于任何标记语句,而 continue 可用于循环标记语句。 |
详细说明
可使用一个标签来唯一标记一个循环,然后使用 break
或 continue
语句来指示程序是否中断循环或继续执行。
需要注意的是,JavaScript 没有 goto
语句,标记只能和 break
或 continue
一起使用。
在严格模式中,你不能使用 “let
” 作为标签名称。它会抛出一个 SyntaxError
(因为 let 是一个保留的标识符)。
使用案例
在标记块中使用
break
你可以在代码块中使用标记,但只有 break
语句可以使用非循环标记。
foo: {
console.log('face');
break foo;
console.log('this will not be executed');
}
console.log('swap');
// this will log:
// "face"
// "swap
标记函数声明
从ECMAScript 2015开始,标准的函数声明现在对规范的 Web 兼容性附件中的非严格代码进行了标准化。
L: function F() {}
在严格模式中,这会抛出 SyntaxError
:
'use strict';
L: function F() {}
// SyntaxError: functions cannot be labelled
无论是否处于严格模式下,生成器函数都不能被标记:
L: function* F() {}
// SyntaxError: generator functions cannot be labelled
break 语句
基础说明
break 语句中止当前循环,switch
语句或label
语句,并把程序控制流转到紧接着被中止语句后面的语句。
break
语句包含一个可选的标签,可允许程序摆脱一个被标记的语句。break
语句需要内嵌在引用的标签中。被标记的语句可以是任何 块
语句;不一定是循环语句。
语法说明
break [label];
语句名 | 具体说明 |
---|---|
label | 可选。与语句标签相关联的标识符。如果 break 语句不在一个循环或 switch 语句中,则该项是必须的。 |
使用案例
下面的函数里有个
break
语句,当i
为 3 时,会中止while
循环,然后返回 3 *x
的值。
function testBreak(x) {
var i = 0;
while (i < 6) {
if (i == 3) {
break;
}
i += 1;
}
return i * x;
}
continue 语句
基础说明
continue 声明终止当前循环或标记循环的当前迭代中的语句执行,并在下一次迭代时继续执行循环。
let text = '';
for (let i = 0; i < 10; i++) {
if (i === 3) {
continue;
}
text = text + i;
}
console.log(text);
// expected output: "012456789"
语法说明
continue [ label ];
语句名 | 具体说明 |
---|---|
label | 标识标号关联的语句 |
详细说明
与 break
语句的区别在于, continue 并不会终止循环的迭代,而是:
continue
语句可以包含一个可选的标号以控制程序跳转到指定循环的下一次迭代,而非当前循环。此时要求 continue
语句在对应的循环内部。
使用案例
下述例子展示了一个在i
为 3时执行continue
语句的 while
循环。因此,n
的值在几次迭代后分别为 1, 3, 7 和 12 .
i = 0;
n = 0;
while (i < 5) {
i++;
if (i === 3) {
continue;
}
n += i;
}
with 语句
基础说明
with语句 扩展一个语句的作用域链。
语法说明
with (expression) {
statement
}
语句名 | 具体说明 |
---|---|
expression | 将给定的表达式添加到在评估语句时使用的作用域链上。表达式周围的括号是必需的。 |
statement | 任何语句。要执行多个语句,请使用一个块语句 ({ ... })对这些语句进行分组。 |
推荐写法
因为大量使用 with 语句会导致 性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用 with 语句~~~
严格模式下不允许使用 with 语句,否则将会视为语法错误~~
详细说明
JavaScript查找某个未使用命名空间的变量时,会通过作用域链来查找,作用域链是跟执行代码的context或者包含这个变量的函数有关。
'with'语句將某个对象添加到作用域链的顶部,如果在statement中有某个未使用命名空间的变量,跟作用域链中的某个属性同名,则这个变量将指向这个属性值。如果沒有同名的属性,则将拋出ReferenceError
异常。
不推荐使用with
,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。
性能方面的利与弊
- 利:
with
语句可以在不造成性能损失的情況下,减少变量的长度。其造成的附加计算量很少。使用'with'可以减少不必要的指针路径解析运算。需要注意的是,很多情況下,也可以不使用with语句,而是使用一个临时变量来保存指针,来达到同样的效果。 - 弊:
with
语句使得程序在查找变量值时,都是先在指定的对象中查找。所以那些本来不是这个对象的属性的变量,查找起来将会很慢。如果是在对性能要求较高的场合,'with'下面的statement语句中的变量,只应该包含这个指定对象的属性。
语义不明的弊端
- 弊端:
with
语句使得代码不易阅读,同时使得JavaScript编译器难以在作用域链上查找某个变量,难以决定应该在哪个对象上来取值。请看下面的例子:
function f(x, o) {
with (o)
print(x);
}
f
被调用时,x
有可能能取到值,也可能是undefined
,如果能取到, 有可能是在o上取的值,也可能是函数的第一个参数x
的值(如果o中没有这个属性的话)。如果你忘记在作为第二个参数的对象o中定义x
这个属性,程序并不会报错,只是取到另一个值而已。
- **弊端:**使用
with
语句的代码,无法向前兼容,特別是在使用一些原生数据类型的时候。看下面的例子:
function f(foo, values) {
with (foo) {
console.log(values)
}
}
如果是在ECMAScript 5环境调用f([1,2,3], obj)
,则with
语句中变量values
将指向函数的第二个参数values
。但是,ECMAScript 6标准给Array.prototype
添加了一个新属性values
,所有数组实例将继承这个属性。所以在ECMAScript 6环境中,with
语句中变量values
将指向[1,2,3].values
。
使用案例
下面的with
语句指定Math
对象作为默认对象。with
语句里面的变量,分別指向Math
对象的PI
、 cos
和sin
函数,不用在前面添加命名空间。
var a, x, y;
var r = 10;
with (Math) {
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}
switch 语句
基础说明
switch
语句评估一个表达式,将表达式的值与case
子句匹配,并执行与该情况相关联的语句。
const expr = 'Papayas';
switch (expr) {
case 'Oranges':
console.log('Oranges are $0.59 a pound.');
break;
case 'Mangoes':
case 'Papayas':
console.log('Mangoes and papayas are $2.79 a pound.');
// expected output: "Mangoes and papayas are $2.79 a pound."
break;
default:
console.log(`Sorry, we are out of ${expr}.`);
}
语法说明
switch (expression) {
case value1:
// 当 expression 的结果与 value1 匹配时,执行此处语句
[break;]
case value2:
// 当 expression 的结果与 value2 匹配时,执行此处语句
[break;]
...
case valueN:
// 当 expression 的结果与 valueN 匹配时,执行此处语句
[break;]
[default:
// 如果 expression 与上面的 value 值都不匹配,执行此处语句
[break;]]
}
语句名 | 具体说明 |
---|---|
expression | 一个用来与 case 子语句匹配的表达式。 |
case valueN 可选 | 用于匹配 expression 的 case 子句。如果 expression 与给定的 valueN 相匹配,则执行该 case 子句中的语句直到该 switch 语句结束或遇到一个 break 。 |
default 可选 |
一个 default 子句;如果给定,这条子句会在 expression 的值与任一 case 语句均不匹配时执行。 |
详细说明
一个 switch 语句首先会计算其 expression 。然后,它将从第一个 case 子句开始直到寻找到一个其表达式值与所输入的 expression 的值所相等的子句(使用 严格运算符,===
)并将控制权转给该子句,执行相关语句。(如果多个 case 与提供的值匹配,则选择匹配的第一个 case,即使这些 case 彼此间并不相等。)
如果没有 case
子句相匹配,程序则会寻找那个可选的 default
子句,如果找到了,将控制权交给它,执行相关语句。若没有 default
子句,程序将继续执行直到 switch
结束。按照惯例,default
子句是最后一个子句,不过也不需要这样做。
可选的 break
语句确保程序立即从相关的 case 子句中跳出 switch 并接着执行 switch 之后的语句。若 break
被省略,程序会继续执行 switch
语句中的下一条语句。
使用案例
下面的例子中,如果 expr
计算为 "Bananas",程序就会匹配值为 "Bananas" 的 case 然后执行相关语句。当遇到 break
时,程序就跳出 switch
然后执行 switch
后的语句。若 break
被省略,值为 "Cherries" 的 case 中的语句就也将被执行。
switch (expr) {
case 'Oranges':
console.log('Oranges are $0.59 a pound.');
break;
case 'Apples':
console.log('Apples are $0.32 a pound.');
break;
case 'Bananas':
console.log('Bananas are $0.48 a pound.');
break;
case 'Cherries':
console.log('Cherries are $3.00 a pound.');
break;
case 'Mangoes':
case 'Papayas':
console.log('Mangoes and papayas are $2.79 a pound.');
break;
default:
console.log('Sorry, we are out of ' + expr + '.');
}
console.log("Is there anything else you'd like?");
debugger 语句
基础说明
debugger 语句调用任何可用的调试功能,例如设置断点。 如果没有调试功能可用,则此语句不起作用。
语法说明
debugger;
使用案例
下面的例子演示了一个包含 debugger 语句的函数,当函数被调用时,会尝试调用一个可用的调试器进行调试。
function potentiallyBuggyCode() {
debugger;
// do potentially buggy stuff to examine, step through, etc.
}
今日学习总结
今日心情
今日主要是基于搜索来仔细学习 第 3 章节中的 3.5 语句,感受到操作符与语句组合的厉害之处~~~,感觉很不错,希望明天学习到更多东西~~~~
本文使用 mdnice 排版