笔记:《JavaScript学习指南》-第4章控制流

第4章 控制流
皇冠和锚的游戏演示:
水手托马斯在六个面的组合中放任意数量的硬币,这6个面是"皇冠", "锚", "红心","梅花", "黑桃", "方块"。然后掷三个骰子,每个骰子上面都有之前提到的6个面。如果掷出来的骰子跟他下注的一样,那托马斯就赢了。
4.1 控制流的底层
游戏将分成三部分:下注、掷骰子、收集赢到的钱。

4.1.1 while循环
let funds = 50;
while(funds > 1 && funds < 100){
    //下注

    //掷骰子

    //收集赢到的钱
}

4.1.2 块语句
块语句是被花括号包裹起来的一系列语句的集合。JavaScript会把它当成一个程序单元。
块语句可能单独存在,但没什么用。块语句和控制流语句结合起来就会变得有用起来。

4.1.3 空格
//代码块只有一行语句,则 不用另起一行,
while(funds > 1 && funds < 100)  funds = funds +2;


4.1.4 辅助方法
//返回[m,n]之间的随机整数(包含边界)
function rand(m,n){
    return m + Math.floor((n-m+1)*Math.random());
}

//随机返回代表皇冠和锚游戏中六个面其中之一的字符串
function randFace(){
    return ["皇冠", "锚", "红心","梅花", "黑桃", "方块"];
}

4.1.5 if else 语句
托马斯下注的一个惯例:随机从口袋取出一把硬币(少则一枚,多则全部)。另外,如果硬币个数为7,就将硬币放回口袋,然后把口袋中的所有钱压倒“红桃”上,否则,他会把拿到的硬币随机下注。
const bets = {"皇冠": 0, "锚": 0, "红心": 0, "梅花": 0, "黑桃": 0, "方块": 0};
let totalBet = rand(1,funds);
if(totalBet === 7){
    totalBet = funds;
    bet.heart = totalBet;
}else{
    //分配下注总数
}

funds = funds - totalBet;
 
4.1.6 do...while 循环
当托马斯拿出的硬币不是7个时,他会随机将手上的钱拿出一些(少则一枚,多则全部),然后随机下注到其中一个里面(有时会把钱重复下注给同一个面)。
let remaining = totalBet;
do{
    let bet = rand(1,remaining);
    let face = randFace();
    bets[face] = bets[face] + bet;
    remaining = remaining - bet;
}while(remaining > 0);
 
4.1.7 for 循环
开始掷骰子。
const hand = [];
for(let roll = 0; roll < 3; roll++){
    hand.push(randFace());
}

4.1.8 if 语句
收集赢钱信息。
let winings = 0;
for(let die=0; die<hand.length; die++){
    let face = hand[die];
    if(bets[face] > 0) winings = winings + bets[face];
}
funds = funds + winings;

4.1.9 最后的整合
//返回[m,n]之间的随机整数(包含边界)
function rand(m,n){
    return m + Math.floor((n-m+1)*Math.random());
}

//随机返回代表皇冠和锚游戏中六个面其中之一的字符串
function randFace(){
    return ["皇冠", "锚", "红心","梅花", "黑桃","方块"][rand(0,5)];
}

let funds = 50;

//开始条件
let round = 0;

while(funds > 1 && funds < 100){
    round++;
    console.log(`round ${round}:`);
    console.log(`\t starting funds:${funds}p`);

    //掷骰子
    let bets = {"皇冠": 0, "锚": 0, "红心": 0, "梅花": 0, "黑桃": 0, "方块": 0};
    let totalBet = rand(1,funds);

    if(totalBet === 7){
         totalBet = funds;
         bets["红心"]= totalBet;

    }else{
        //分配下注总数
        let remaining = totalBet;

        do{
            let bet = rand(1,remaining);
            let face = randFace();
            bets[face] = bets[face] + bet;
            remaining = remaining - bet;

        }while(remaining > 0);
    }
        funds = funds - totalBet;

    console.log("\tbets:"+ Object.keys(bets).map(face => `${face}; ${bets[face]} pence`).join(",")+`(total: ${totalBet} pence)`);

    //掷骰子
    const hand = [];
    for(let roll = 0; roll < 3; roll++){
        hand.push(randFace());
    }
    console.log(`\thand: ${hand.join(',')}`);

    //收集赢到的钱
    let winings = 0;
    for(let die=0; die<hand.length; die++){
        let face = hand[die];
        if(bets[face] > 0) winings = winings + bets[face];
    }
    funds = funds + winings;
    console.log(`\twinings: ${winings}`);
}
console.log(`\t ending funs: ${funds}`);     

4.2 JavaScript中的控制语句
从广义上讲,控制流分为两种:条件控制流和循环控制流。

4.2.1 控制流异常
 有四个语句可以改变控制流的正常处理流程。
  • break
  • continue
  • return
  • throw

4.2.2 链式 if...else 语句
如果托马斯每到周三只拿1个硬币:
if(new Date().getDate() === 3){
    totalBet = 1;
}else if(funds === 7){
    totalBet = funds;
}else{
    console.log("No superstition here!");
}

4.2.3 元语法
元语法是一种语法,可以用它来描述或传达另一种语法。
元语法只有两个真正的元素:中括号内的内容不是必须的,省略号(一般是三个句号)表示“这里还有更多内容”。单词作为占位符,所表示的意思可从上下文猜出。
while 语句
    while(condition)
        statement
    当条件为真时,语句会被执行。

if..else 语句
    if(condition)
        statement1
    [else
        statement2]

do...while 语句
    do
        statement
    while(condition);

for 语句
    for([初始值]; [条件]; [终止表达式])
        语句

4.2.4 其他循环模式
通过逗号操作符,可将多个赋值操作和终止表达式连起来。
如下,for循环可以打印斐波那切数列。
for(let a=0,b=0,c=1; c<100; a=b, b=c,c=a+b){
    console.log(c);
}
  
    for([初始值]; [条件]; [终止表达式])
        语句


    [初始值】
    while([条件]){
        语句
        [终止表达式]
    }

是等效的。

for循环的好处是所有与循环相关的信息都会出现在第一行。
同时,for循环的初始变量的作用范围仅仅在循环体内部,而while将扩大到循环体外。

4.2.5 switch 语句
switch(表达式){
    case值1:
        //当表达式的执行结果跟值1匹配的时候执行
    [break;]
    case值2:
        //当表达式的执行结果跟值2匹配的时候执行
    [break;]
    ...case值N:
        //当表达式的执行结果跟值N匹配的时候执行
    [break;]
    default:
        //当表达式的结果跟任何一个值都不匹配的时候执行
    [break;]
}

4.2.6 for...in 循环
为对象中有属性key而设计的。

4.2.7 for...of 循环
ES6新语法。
提供了另一种在集合中遍历元素的方法。
for( 变量 of 对象)
    语句
for...of 循环可以用在数组上,但一般它可以用于遍历任何可迭代的对象。
如果要遍历一个数组,但不需要知道每个元素的索引,for...of 是一个好选择。如果需要知道索引,就用常规for循环.

4.3 实用的控制流模式
4.3.1 使用continue 减少条件嵌套
while(funds > 1 && funds < 100){
    let totalBet = rand(1,funds);
    if(totalBet === 13){
        console.log("Unlicky! Skip this round...");
    }else{
        //play
    }
}
可以使用continue 语句使结构更加“扁平”。
while(funds > 1 && funds < 100){
    let totalBet = rand(1,funds);
    if(totalBet === 13){
        console.log(("Unlicky! Skip this round...");
        continue;
    }
    //play...
}
如果循环体不是1行,而是20行。从嵌套的控制流中删除这些行,会使代码更易于理解并大大提高可读性。

4.3.2 使用 break 或 return 避免不必要的计算
如果循环仅仅是为了找到一个特定值,就没有必要在已经找到目标值后还继续执行到最后。
找到目标值后,就可以立即使用break语句结束循环。
let firstPrime = null;
for(let n of bigArrayOfNumbers){
    if(isPrime(n)){
        firstPrime = n;
        break;
    }
}

4.3.3 在循环结束后使用索引的值
有时,需要获得循环被break 语句终止时当前元素的索引值。
这时可利用一个特性:当for 循环结束时,索引变量的值依然被保留在循环体内。
使用这种模式,有一个边缘情况是,循环成功地执行到最后,break 语句没有被调用。
比如用该模式找到数组中第一个素数的索引:
let i = 0;
for(; i < bigArrayOfNumbers.length; i++){
    if(isPrime(bigArrayOfNumbers[i])) break;
}

if(i === bigArrayOfNumbers.length) console.log('No Prime numbers!");
else console.log(`First prime number found at position ${i}`);

4.3.4 列表变动时索引递减
在循环一个列表的同时还在修改它,需要相应的修改循环终止条件,否则容易出现问题。常见做法是使用索引递减的循环方式。这样,对列表进行增删操作,就不会影响循环终止条件。
for(let i = bigArrayOfNumbers.length-1; i >= 0; i--){
    if(isPrime(bigArrayOfNumbers[i])) bigArrayOfNumbers.splice(i, 1);
}


猜你喜欢

转载自blog.csdn.net/kjhz_liang/article/details/80524181