与其他的编程语言一样,javascript 也存在三种基础的程序执行结构.分别是顺序结构,选择结构,循环结构.我们依次来了解一下
顺序结构
执行一个 js 文件,解析器默认会从第一行依次往下执行,分别执行行为,与定义.如下
let a = 10;
let sqrt = x => x*x;
console.log(sqer(a)); //输出100;
以上代码的执行顺序为 1 2 3 2 3,其中第一次执行的二三行分别是定义函数与调用函数,第二次的二三行分别是执行函数,获取返回值.程序执行固然是顺序的,即使由函数这种代码组织方式改变了执行次序,我们也说它们是顺序的.另外一点需要注意的是,javascript 中没用所谓的主函数它的程序入口点,取决于执行环境对他的解释.
在浏览器环境中,程序的执行顺序取决于 script 标签出现在 html 文件中的顺序,浏览器会一边构造 dom,一边执行 javascript.
而在服务器环境中 (nodejs),程序的入口点在于在于使用 node 命令后紧跟的那个 js 文件名,那个文件我们称其为启动文件,解释器会从这个文件的第一行开始解释执行.再由模块系统引入其他文件交由解释器去执行,这样就形成了一个完整的服务器项目.
选择结构
// js中的选择结构
let a = true;
if(a)
console.log('a is true');
else
console.log('a is false');
console.log( a?'a is true':'a is false' );
let str = a?'a is true':'a is false';
console.log(str);
let code = 200;
switch(code){
case 200: console.log('服务器响应成功'); break;
case 500: console.log('服务器错误');break;
default: console.log('服务器发生未知错误');
}
最常见的选择结构是 if,else, 表示的含义及 "如果... 否则...".其判断的条件是括号内的表达式.顺带一提,表达式可以理解称任何一段合法的 javascript 代码,如一个已经声明的变量名,一个函数调用,一个常量,一个对象的某个成员变量或某个成员方法的调用.
if 语句会将括号中的条件最终转成逻辑值后进行真假判断,即调用 Boolean(表达式).笔者使用谷歌浏览器做了以下代码的测试.
let testlist = [
Boolean(null), //false
Boolean(undefined), //false
Boolean(""), //false
Boolean(0), //false
Boolean({}), //true
Boolean(-1), //true
Boolean(1), //true
Boolean("true"), //true
Boolean("false"), //true
];
testlist.map( item => console.log(item) );
我们暂时将 Boolean(表达式) 所返回的值称为该表达式的逻辑含义,则在 javascript 中 null,undefined,空字符串,0 的逻辑含义均为 false.因此 javascript 中常常使用一种模式去确保接线来的操作可执行.即判断变量或对象成员的存在性.
let obj = {
x : 1,
};
let sqrt = x => x*x;
if( obj.x )
console.log(sqrt(obj.x));
// 当然,由于x的值为0也是合法的,因此上面的代码改为以下的形式更为合适
if( obj.x || obj.x == 0 )
console.log(sqrt(obj.x));
if,elese 也存在如下方式的嵌套使用.
let a = true;
let b = false;
if(b)
console.log('b is true');
else if( a )
console.log('a is true');
else
console.log('all false');
if,else 中,若需要执行的代码不只一行,则需使用代码块的方式书写.
let a = true;
let b = false;
if(b){
console.log('b is true');
console.log('其他代码');
}
else if( a )
console.log('a is true');
else{
console.log('all false');
console.log('其他代码');
}
选择结构中存在简写的三元表达式,其使用方法为 [条件表达式]?[条件为真时执行的表达式或代码块]:[条件为假时执行的表达式或代码块].如下代码示例.
let a = 1+1 == 2 ? true:false;
console.log('1+1 == 2 这个表达式的返回值为:'+a); // true
同样也可以使用代码块.
let a = true;
a?console.log('a == true'):{
console.log('a != true');
console.log('其他代码');
};
三元表达式也是可以嵌套书写的,其结合顺序为从右至左.
let a = 1+1 == 2 ? true : 1+2 == 3? true:false; // a = true
//以上表达式等价于
let a = 1+1 == 2 ? true : ( 1+2 == 3 ? true:false );
console.log(a); //输出true
三元表达式通常用于书写单行逻辑,在赋值语句中尤为常见,经常用于处理 "若条件成立则变量赋一个值,不成立赋另一个值" 的需求.
另外一种常见的选择结构是 swatch 语句, 它是一种多重选择语句,存在的意义是替代多重 if else 嵌套.
其使用方式为 switch 后紧跟一对括号,括号中填写需要判断的表达式,而后紧跟一个花括号,其中书写一个一个的 case 后跟一个合法的原始类型常量, 后跟冒号, 之后书写一系列的语句,直到书写完成,使用 break 跳出选择.
let a = 'add';
switch(a){
case 'add':console.log('add');break;
case 'exit':console.log('exit');break;
default:console.log('命令非法'); //default关键字不是必须的,用于处理未知条件表达式返回
}
值得注意的是 break 的使用仅用于跳出当前选择,且 switch 的选择会逐一匹配合法的原始类型常量,匹配正确后会进入执行,直到遇见 break 语句,或整个花括号结束.如下代码.
let a = 'a';
switch(a){
case 'a':
case 'b':
case 'c':
// 字母省略
case 'x':console.log('这是一个小写字母');break;
case '+':
case '-':
case '*':
case '/': console.log('这是四则运算符');break;
default: console.log('不知道是什么');
}
循环结构
javascript 中循环的方式有很多种,可将其分为两种,一种为非递归循环,一种为递归循环.
其中非递归循环使用三种关键字 for,while,do while.
for 循环通常用来处理一些已知循环次数的需求,如下.
for( let i = 0;i<1000;i++ )
console.log('love pp');
// 以上代码输出1000次字符串 "love pp"
其较为常见的一种结构是 for([初始化语句][条件判断语句][步长语句]).
当首次执行时,解释器会执行循环的初始化语句,后判断条件判断语句的返回值是否为 true,若为 true 则进入循环执行代码,若不是则退出循环继续按顺序结构执行其他代码.当一次内部循环完成时,解释器会自动执行一次步长语句.
for 循环还存在以下两种针对可迭代对象的结构,最常见的可迭代对象便是数组了.
let arr = ['a','b','c'];
for( let item of arr )
console.log(item); //依次输出 a b c
for( let i in arr )
console.log( arr[i] ); //依次输出 a b c
可见 for 语句接受一个表达式作为参数,分别为 of 和 in.当使用 of 时,每次循环取出的迭代对象的具体元素,而使用 in 的时候取出的是元素下标 (或者叫当前循环的次数).
while 循环通常用于处理一些未知循环次数的需求,如下.
let a = 1;
while( a <= 100 ) a++;
console.log(a); //输出101
而 do while 则是提前执行循环体的手段.
let a = 1;
do{
console.log('一些代码');
console.log('一些代码');
console.log('一些代码');
a++;
}while(a<100);
可见 while 循环更加容易造成死循环, 即在循环体内部忘记改变条件判断中关联的量.
循环中的递归循环主要通过函数实现,即函数自身调用自身,如下一段代码.
let f = x => x == 1 ? 1 : x == 2 ? 2 : f(x-1) + f(x-2);
console.log(f(20)); //求前20个斐波那契数列的和 10946
除了非递归与递归循环,es6 的数组对象中也存在大量的迭代函数可以达到循环的目的,由此可见循环的大多数场景是遍历某个可迭代对象.
其中最常见的有两种方法,map,reduce.
这节课只介绍 map 方法,关于其他数组上的迭代方法请查询相关文档自行了解.
['a','b','c'].map( item => console.log(item) ); //依次输出
// map 方法接受一个函数作为参数,这个函数的完整接受参数有三个,如下
['a','b','c'].map( (item,index,arr) => console.log(item,index,arr) ); //输出结果如下
/*
a 0 ['a','b','c']
b 1 ['a','b','c']
c 2 ['a','b','c']
*/
来源: http://www.jianshu.com/p/85fe49e6725e