逻辑结构
逻辑结构
由上一节我们知道,事实上,JavaScript的语句体系与C语言是相似的。而JavaScript的逻辑结构几乎与C语言完全相同,我们权且当作复习一下C语言地去学习JavaScript吧!
值得注意的是,逻辑框架所框出来的语句为块作用域,在ES5中,这样结构内的变量在块外依然能够被引用。在ES6中,推荐使用let
关键字来代替var
以达到块内变量封闭的效果。
判断语句
在C语言中,判断语句值类型为数值型,即采用逻辑运算符操作时,判断结果为0或1。
在JavaScript中则有:
- 布尔型语句,值为true/false
- 判断条件型语句(比较运算符、逻辑运算符、类型运算符等),值为true/false
三目运算符语句
三目运算符?:
var a = (condition) ? valueT:valueF;
条件满足时返回第一个值,反之返回第二个值。
与C语言不同的是,两个值的类型可以不同,有机会可以使用三目运算符来特别判断类型以统一类型。
var a=1;
var b=(typeof(a) == 'number')?a+1:a+"1";
document.write(b);
条件结构
即有两种结构模式
if-else if-else
if (condition1)
{
//当条件 1 为 true 时执行的代码
}
else if (condition2)
{
//当条件 2 为 true 时执行的代码
}
else
{
//当条件 1 和 条件 2 都不为 true 时执行的代码
}
这一体系可以只保留if-else,也可以只保留if-else if,当然可以只保留if。当语句为一句时,可以省略方括号{},但是依然还是属于块作用域的范围。
switch{case : }
n对应取值时执行。一般用于离散的数据。
switch(n)
{
case 1:
//执行代码块 1
break;
case 2:
//执行代码块 2
break;
default:
//与 case 1 和 case 2 不同时执行的代码
}
和C语言语句一样,可以不用有break;
,就把case
当作标签来看待。n对应到标签上的数值,就从哪里开始进行语句。而不符合情况的跳到default
标签上。
当然也有骚操作让switch用于范围:
function switch_s(x){
switch(true) {
case x > 1 :
break;
case x == 1 :
break;
case x < 1 :
break;
}
}
循环结构
与C语言几乎一样,拥有着相似的for循环、while循环。
for循环
for ( 初始化语句; 满足条件; 循环一次执行语句 )
{
/**/
}
值得一提的是,如果初始化变量用var
声明,例如for(var i=0;i<=10;i++){}
则当i=11时跳出循环后,i依然可以被引用,而且值为11。因此,在ES6以后,这类变量最好用let
声明
while循环
与C语言一样,JavaScript也有while循环和do-while循环。
while(满足条件)
{
/**/
}//先判断条件,满足条件后再执行
do
{
/**/
}//首先执行一次,再判断条件
while (满足条件);
由于JavaScript语句分号可以省略,在这里循环体的判断在于紧接程度。
var mynum =6;//mynum初值化数值为6
do
{
document.write("数字:"+mynum+"<br/>");
mynum=mynum-1;
}
while(mynum>0)
{
mynum=mynum+3;
document.write("数字:"+mynum+"<br/>");
}//这里的语句块不被当作循环,而是仅仅被当成语句块
/*
数字:6
数字:5
数字:4
数字:3
数字:2
数字:1
数字:3
*/
for-in循环
用于遍历对象内的元素或者列表内的元素,
for(x in person){}
这里x做为属性名,每一次遍历属性名都不同。
var person = {fname:"John", lname:"Doe", age:25};
var text = "";
var x;//也可省略
for (x in person) {//在这里x作为person内属性名的代替值
text += person[x] + " ";
}
/*输出结果:
John Doe 25
*/
for-in也可以对数组进行变量。
事实上。使用for-in对数组进行变量时,x作为属性名的代替值时,是一个对象,而不是一个数字,因此与使用for循环数字遍历数组有一定的区别——当你为Array增添非数字索引的属性值时,该属性也会被遍历到。例如:
Array.prototype.fatherName = "Father";
const arr = [1, 2, 3];
arr.name = "Hello world";
let index;
for(index in arr) {
document.write("arr[" + index + "] = " + arr[index]);
}
/*输出结果
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[name] = Hello world
arr[fatherName] = Father
*/
for-in 并不适合用来遍历 Array 中的元素,其更适合遍历对象中的属性,这也是其被创造出来的初衷。却有一种情况例外,就是稀疏数组。
const arr = [];
arr[0] = "a";
arr[100] = "b";
arr[10000] = "c";
总体上,数组的遍历应该基于以下原则:
- 不要用for in遍历数组,全部统一采用标准的for循环变量数组(我们无法保证我们引入的JavaScript是否会采用prototype扩展原生的Array)
- 如果要对JavaScript的原生类扩展的时候,不要采用prototype了
注意:JavaScript里还有一个in语句,用法相似
if-in语句
判断属性名是否属于某个对象或,数组某个序号下有无值
if(x in object1){}
forEach方法
数组的forEach方法用于遍历数组中的每一个元素。forEach(参数),这个参数为一个回调函数。
通常这个函数有三个参数,分别为:
- 数组当前项的值;
- 数组当前项的索引;
- 数组对象本身;
三个参数顺序是固定的,不可以调整。例如:
var txt = "";
var numbers = [45, 4, 9, 16, 25];
numbers.forEach(myFunction);
function myFunction(value, index, array) {
txt = txt + value + "<br>";
}
也就是说,把函数传入方法里后,我们不用管这个函数的3个参数。而这3个参数是解释过程中解释器提供的,因此可以把这些参数当成是本次循环产生的数据拿来用,如上。
forEach方法只会关注数字序号下的元素,数组的其他属性不会被遍历到。方法执行时,每次遍历到一个元素,这个元素就被执行该回调函数,那些已删除(使用 delete 方法等情况)或者从未赋值的项将被跳过。
如果传入forEach方法的函数只有一个参数的话,这个参数为 数组当前项的值,与for-in不同。
使用lambda表达式(箭头函数)可以简化forEach方法的书写:
const arr = [1, 2, 3];
arr.forEach((data) => {
document.write(data);
});
数组的其他迭代方法:参数为一个函数(这个函数同样传入3个参数)
every: 循环在第一次 return false 后返回
some: 循环在第一次 return true 后返回
filter: 返回一个新的数组,该数组内的元素满足回调函数,例如:
function myFunction(value) {return value > 18;}
map: 返回一个新的数组,将原数组中的元素处理后再返回
reduce: 对数组中的元素依次处理,将上次处理结果作为下次处理的输入,最后得到最终结果。
for-of循环(ES6)
for(x of list){}
与for-in不同的是,x这里作为属性的值。(for(x in person){}
这里x做为属性名)。
其特点为:
- forEach不能响应break、continue 和 return 语句,而它可以正确响应 。
- 而且只变量数值作为键值的属性,也就是数组项,而不会遍历到属性。
- 其不仅可以遍历数组,还可以遍历类数组对象(DOM nodelist)和其他可迭代对象(字符串(视作字符的数组)、Set、Map)。
- 但不支持普通对象
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
document.write(v);
}
/*输出结果
red green blue*/
调试结构
在C++里,调试结构为
try {
//语句组
}
catch(异常类型) {
//异常处理代码
}
...
catch(异常类型) {
//异常处理代码
}
catch(...){
//可以读取所有异常
}
catch{}
可以有多个,分别获取对应的异常情景。
在JavaScript里,也有类似的调试结构。
try
语句允许我们定义在执行时进行错误测试的代码块。catch
语句允许我们定义当try
代码块发生错误时,所执行的代码块。finally
语句在try
和catch
之后无论有无异常都会执行。
try {
//尝试执行代码块
}
catch(err) {
//捕获错误的代码块
//err为一个参数,这个参数记录了错误信息
}
finally {
//无论 try / catch 结果如何都会执行的代码块
}
在语句中,可以用throw "xxx"
来报错。
值得一提的是,如果单纯是想让代码通过就执行,不通过就算了,可以写为:
try{
//单纯想执行代码
}catch(e){}
逻辑控制关键字
break
跳出循环、跳出结束switch{}
continue
进入下一个循环的迭代,跳过continue
以下的语句
没有goto,但有标签
标签名和冒号置于语句之前,标记这个语句
label1:{//label1是一个标签,标定了一个语句块
//代码语句
break label1;
//代码语句,此时已经跳出语句块了,这里的语句不会执行
}
break labelname;
看到这一语句时,从标记为labelname
的语句块中跳出,不再执行
continue labelname;
这时标明从循环体内部中止,并继续到标签处开始执行,并且这个标签所指示的语句必须是包含此continue
的循环语句。
对于一层循环来说不起作用,作用在于从内层循环直接控制跳过一层外层循环。
return
与C语言相同,用于结束函数,此时函数返回类型为undefined
;或者返回值。
参考资料:
- w3school
- 菜鸟教程
- js中的四种for循环 - Lynn_z - 博客园 (cnblogs.com)