习题
范围的和
在本书的前言中,提到过一种很好的计算固定范围内数字之和的方法:
console.log(sum(range(1, 10)));
编写一个range
函数,接受两个参数:start
和end
,然后返回包含start
到end
(包括end
)之间的所有数字。
接着,编写一个sum
函数,接受一个数字数组,并返回所有数字之和。运行示例程序,检查一下结果是不是 55。
附加题是修改range
函数,接受第 3 个可选参数,指定构建数组时的步长(step
)。如果没有指定步长,构建数组时,每步增长 1,和旧函数行为一致。调用函数range(1, 10, 2)
,应该返回[1, 3, 5, 7, 9]
。另外确保步数值为负数时也可以正常工作,因此range(5, 2, -1)
应该产生[5, 4, 3, 2]
。
// Your code here.
console.log(range(1, 10));
// → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(range(5, 2, -1));
// → [5, 4, 3, 2]
console.log(sum(range(1, 10)));
// → 55
逆转数组
数组有一个reverse
方法,它可以逆转数组中元素的次序。在本题中,编写两个函数,reverseArray
和reverseArrayInPlace
。第一个函数reverseArray
接受一个数组作为参数,返回一个新数组,并逆转新数组中的元素次序。第二个函数reverseArrayInPlace
与第一个函数的功能相同,但是直接将数组作为参数进行修改来,逆转数组中的元素次序。两者都不能使用标准的reverse
方法。
回想一下,在上一章中关于副作用和纯函数的讨论,哪个函数的写法的应用场景更广?哪个执行得更快?
// Your code here.
console.log(reverseArray(["A", "B", "C"]));
// → ["C", "B", "A"];
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
实现列表
对象作为一个值的容器,它可以用来构建各种各样的数据结构。有一种通用的数据结构叫作列表(list)(不要与数组混淆)。列表是一种嵌套对象集合,第一个对象拥有第二个对象的引用,而第二个对象有第三个对象的引用,依此类推。
let list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
最后产生的对象形成了一条链,如下图所示:
使用列表的一个好处是,它们之间可以共享相同的子列表。举个例子,如果我们新建了两个值:{value: 0,result: list}
和{value: -1,result: list
}(list
引用了我们前面定义的绑定)。这是两个独立的列表,但它们之间却共享了同一个数据结构,该数据结构包含列表末尾的三个元素。而且我们前面定义的list
仍然是包含三个元素的列表。
编写一个函数arrayToList
,当给定参数[1, 2, 3]
时,建立一个和示例相似的数据结构。然后编写一个listToArray
函数,将列表转换成数组。再编写一个工具函数prepend
,接受一个元素和一个列表,然后创建一个新的列表,将元素添加到输入列表的开头。最后编写一个函数nth
,接受一个列表和一个数,并返回列表中指定位置的元素,如果该元素不存在则返回undefined
。
如果你觉得这都不是什么难题,那么编写一个递归版本的nth
函数。
// Your code here.
console.log(arrayToList([10, 20]));
// → {value: 10, rest: {value: 20, rest: null}}
console.log(listToArray(arrayToList([10, 20, 30])));
// → [10, 20, 30]
console.log(prepend(10, prepend(20, null)));
// → {value: 10, rest: {value: 20, rest: null}}
console.log(nth(arrayToList([10, 20, 30]), 1));
// → 20
深层比较
==
运算符可以判断对象是否相等。但有些时候,你希望比较的是对象中实际属性的值。
编写一个函数deepEqual
,接受两个参数,若两个对象是同一个值或两个对象中有相同属性,且使用deepEqual
比较属性值均返回true
时,返回true
。
为了弄清楚通过身份(使用===
运算符)还是其属性比较两个值,可以使用typeof
运算符。如果对两个值使用typeof
均返回"object"
,则说明你应该进行深层比较。但需要考虑一个例外的情况:由于历史原因,typeof null
也会返回"object"
。
当你需要查看对象的属性来进行比较时,Object.keys
函数将非常有用。
// Your code here.
let obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: 1, object: 2}));
// → false
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
// → true