萍萍的JavaScript教程 其二 三大结构

与其他的编程语言一样,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中循环的方式有很多种,可将其分为两种,一种为非递归循环,一种为递归循环。

其中非递归循环使用三种关键字forwhiledo 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的数组对象中也存在大量的迭代函数可以达到循环的目的,由此可见循环的大多数场景是遍历某个可迭代对象

其中最常见的有两种方法,mapreduce

这节课只介绍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']
*/

你可能感兴趣的:(萍萍的JavaScript教程 其二 三大结构)