实战
在初步进入 JavaScript 的世界后,实战是十分重要的。本章是一些经典的案例,可以进行总结与测试。
成年判断
请给出一个函数 isAdult
。该函数接受一个数字参数,值为年龄,返回一个布尔值,为对应年龄是否成年。
isAdult(6); // false
isAdult(18); // true
isAdult(50); // true
答案解析[1]。
买书
请给出一个函数 bookPrice
。该函数接受两个数字参数,第一个是书的价格,第二个是书的单价。作为一个精明的老板,您决定:
- 买 10 本以下,不打折
- 满 10 本,打九折
- 满 20 本,打八折
不给钱就打骨折😒
该函数返回您要让他付的钱。
bookPrice(20,5); // 100
bookPrice(12,12); // 129.6
bookPrice(6,30); // 144
答案解析[2]。
数组中特定元素出现次数
请给出一个函数 getTimes
。该函数有两个参数,第一个参数是一个未知长度的装满数字的数组,第二个参数是一个数字。函数返回这个数字在数组中出现的次数。
getTimes([1, 1, 2, 3, 4, 4, 4], 1); // 2
getTimes([1, 1, 2, 3, 4, 4, 4], 5); // 0
getTimes([1, 1, 2, 3, 4, 4, 4], 4); // 3
答案解析[3]。
小九九
请给出一个函数 nineNine
。该函数通过遍历返回一个小九九,该小九九不重复。
即一一得一,一二得二,二二得四,一三得三,二三得六...
nineNine(); // ['1 × 1 = 1', '1 × 2 = 2','2 × 2 = 4','1 × 3 = 3', ...,'9 × 9 = 81']
答案解析[4]。
扩展
请给出一个函数 pickNumber
。该函数返回传入字符串中的所有数字。
pickNumber("zhangbowang"); // ''
pickNumber("z1han2g"); // '12'
pickNumber("1234"); // '1234'
答案解析[5]。
答案
这道题的逻辑是: 如果
age >=18
返回true
,反之返回false
。逻辑图如下:
最简单的想法肯定是使用 if 条件判断,把上面的流程图写下来:
const isAdult = function (age) { if (age >= 18) return true; else return false; };
果然,它正常工作了😁。开心的您准备去交差。
突然,您想起了文档上有这么一句话😳:
JavaScript 引擎遇到
return
语句,就直接返回return
后面的那个表达式的值,后面即使还有语句,也不会得到执行。
于是乎,您去掉了
else
😮const isAdult = function (age) { if (age >= 18) return true; return false; };
接着,懒惰的您想起了箭头函数
const functionName = (arg1, arg2, ...) => value;
的写法。决定投个懒😏
const isAdult = (age) => { if (age >= 18) return true; return false; };
成了! 现在函数更简洁了,但是这还不够。
您又想起了条件表达式就是布尔值, 也就是说
age >= 18
本身就是一个布尔值。😉现在当它是
true
就return true
,是false
就return false
看起来就变成了一个愚蠢的主意😑,于是乎您又改写了一下:const isAdult = (age) => { return age >= 18; };
这不就变成了只有一条语句的箭头函数了么? 我们当然可以直接返回它!😆
const isAdult = (age) => age >= 18;
最后,是时候去掉那个愚蠢的括号了!
const isAdult = age => age >= 18;
恭喜您,您已经得到了最简形式! 😆 ↩︎
答案
判断顾客买书的个数。
如果
ammount < 10
不打折,10 <= ammount < 20
打九折,ammount > 20
打八折同时 $\text{顾客最终付款} = \text{书的个数} × \text{书的价格} × \text{打折力度}$
很简单,只是需要用多次 if 判断,我们把它逻辑图描述如下:
照着写,您得到了:
const bookPrice = (price, ammount) => { let percent; let result; if (ammount < 10) percent = 1; else if (10 <= ammount && ammount <= 20) percent = 0.9; else if (ammount >= 20) percent = 0.8; result = price * ammount * percent; return result; };
与此同时,您发现您的 if 逻辑判断有重复,当第 6 行执行的时候,
ammount
已经不可能小于 10 了,否则它会执行第 5 行。最后一个判断也是没有必要的您还发现,如果直接返回
price * ammount * percent
就无需声明result
。您想了想,重新画了流程图:
对应的函数为:
const bookPrice = (price, ammount) => { let percent; if (ammount < 10) percent = 1; else if (ammount <= 20) percent = 0.9; else percent = 0.8; return price * ammount * percent; };
接着您突发奇想,突然不想声明
percent
了,您又改了流程图:您得到了:
const bookPrice = (price, ammount) => { if (ammount < 10) return price * ammount; else if (ammount <= 20) return price * ammount * 0.9; return price * ammount * 0.8; };
您突然响起了 Mr.Hope 说过的单行代码挑战,结合三元运算符,您又一次压缩了代码:
const bookPrice = (price, ammount) => ammount < 10 ? price * ammount : ammount <= 20 ? price * ammount * 0.9 : price * ammount * 0.8;
结合运算符顺序,您去掉了没用的括号,并将它写在一行:
const bookPrice = (price, ammount) => ammount < 10 ? price * ammount : ammount <= 20 ? price * ammount * 0.9 : price * ammount * 0.8;
它太长了,为什么不把公共的
price * ammount
提取出来呢?const bookPrice = (price, ammount) => price * ammount * (ammount < 10 ? 1 : ammount <= 20 ? 0.9 : 0.8);
我们也可以用更简洁的参数把它变得更短:
↩︎const bookPrice = (p, a) => p * a * (a < 10 ? 1 : a <= 20 ? 0.9 : 0.8);
答案
我们最简单的想法就是将想要统计 element 与数组的每一个 x 进行比较,如果匹配默默的记一个数,当全部比较完成后返回这个数。
用流程图就是:
接下来,我们就要细化了。我们希望循环数组,从第一个元素
arr[0]
到 最后一个元素。回忆一下,如果数组有 $x$ 个元素,那么数组的索引值是 $0$ 到 $x - 1$。所以最后一个元素是
arr[arr.length - 1]
。我们只需要创建一个变量 i,让它从 0 循环到
arr.length - 1
即可,这样我们就可以在每次循环中通过访问arr[i]
来依次访问数组的每一个元素了。所以新的流程图是:
const getTimes = (arr, element) => { let count = 0; let i = 0; while (i <= arr.length - 1) { if (element === arr[i]) count = count + 1; i = i + 1; } return count; };
您想起了自加自减运算符,同时您发现由于 i 是整数,
i <= arr.length - 1
和i < arr.length
等价,于是您做了一些改动:const getTimes = (arr, element) => { let count = 0; let i = 0; while (i < arr.length) { if (element === arr[i]) count += 1; i += 1; } return count; };
经验告诉您,用 for 循环体将循环变量的处理写在一起更好一些:
const getTimes = (arr, element) => { let count = 0; for (let i = 0; i <= arr.length; i++) if (element === arr[i]) count++; return count; };
单行挑战:
const getTimes = (a, e, c = 0) => a.length === 0 ? c : getTimes(a, e, c + Number(a.pop() === e));
const getTimes = (a, e, c = 0) => a.length === 0 ? c : getTimes(a, e, c + (a.pop() === e ? 1 : 0));
思路:
或
const getTimes = (a, e, c = 0, p = 0) => p === a.length ? c : getTimes(a, e, c + (a[p] === e ? 1 : 0), p + 1);
const getTimes = (a, e, c = 0, p = 0) => p === a.length ? c : getTimes(a, e, c + Number(a[p] === e), p + 1);
思路:
↩︎答案
思路:
这个函数显然要用两层循环,设置第一个变量从 $1$ 到 $9$ 循环,在这个循环之中让第二个变量从 $1$ 到
第一个变量
循环。然后在每次循环中向数组新增一项对应的字符串。流程图:
所以很容易就可以写出:
↩︎const nineNine = () => { const arr = []; for (let i = 1; i <= 9; i++) for (let j = 1; j <= i; j++) arr.push(`${i} × ${j} = ${i * j}`); return arr; };
答案
这道题真的很简单,就是把数组中特定元素出现次数中判断元素相等的表达式换成判断是否是数字就可以了。所以答案在此省略。 ↩︎