JavaScript专项算法题(1):回调和高阶函数

2023-02-14 14:02:55 浏览数 (2)

问题:

构建一个addTwo函数,作用为接受一个参数并将参数加2。

题解: // Challenge 1 function addTwo(num) { return num 2; }

// To check if you've completed it, uncomment these console.logs! console.log(addTwo(3)); console.log(addTwo(10)); 挑战2 addS 问题:

构建一个addS函数,作用为接受一个参数并将参数与“S”拼接。

题解: // Challenge 2 function addS(word) { return word "S"; }

// uncomment these to check your work console.log(addS('pizza')); console.log(addS('bagel')); 挑战3 map 问题:

构建一个map函数,其接受两个参数:

数值型数组 回调函数——一个应用于上述数值型数组中的每一个元素的函数(于map函数内) map函数的返回值为包含上述数值型数组元素逐个运行回调函数后生成的元素值的新数组。

1 2 3 map([1,2,3,4,5], multiplyByTwo); //-> [2,4,6,8,10] multiplyByTwo(1); //-> 2 multiplyByTwo(2); //-> 4 题解: // Challenge 3 function map(array, callback) { var newArray = []; for (let i = 0; i < array.length; i ) {

代码语言:javascript复制
newArray.push(callback(array[i]));

} return newArray; }

console.log(map([1, 2, 3], addTwo)); 挑战4forEach 问题:

函数forEach接受一个数组和一个回调函数,运行回调函数于输入数组的每一个元素。forEach函数无返回值。 let alphabet = ''; const letters = ['a', 'b', 'c', 'd']; forEach(letters, function(char) { alphabet = char; }); console.log(alphabet); //prints 'abcd' 题解: // Challenge 4 function forEach(array, callback) { for (let i =0; i < array.length; i ) {

代码语言:javascript复制
callback(array[i]);

} }

// see for yourself if your forEach works! let alphabet = ''; const letters = ['a', 'b', 'c', 'd']; forEach(letters, function(char) { alphabet = char; }); console.log(alphabet); //prints 'abcd' 挑战5 mapWith 问题:

在这个挑战中,你需要将map函数重构为mapWith。这一次你要在mapWith中使用forEach函数而不是使用for循环。

题解: // Challenge 5 function mapWith(array, callback) { var newArray = []; forEach(array, function(item){

代码语言:javascript复制
newArray.push(callback(item))});

return newArray; }

console.log(mapWith([1, 2, 3], addTwo)); 挑战6 reduce 问题:

函数reduce接受一个数组并将数组内的所有值合并为一个值。比如,它可以将数组求和,求积,以及其它你想加进函数中的操作。 const nums = [4, 1, 3]; const add = function(a, b) { return a b; } reduce(nums, add, 0); //-> 8 以下是它的运行原理。函数有一个“累加器值”(第三个参数),作用为充当初始值并且累加每一次循环的输出值。数组参数会被遍历,传递“累加器值“和新的数组元素值作为参数到回调函数中。回调函数的返回值会成为新的”累加器值“。下一个循环会使用这个新”累加器值“。在上面的例子中,”累加器值“刚开始为0,调用add(0, 4),”累加器值“变为4,然后add(4, 1)将其变为5,最后add(5, 3)得到8并最终返回。

题解: // Challenge 6 function reduce(array, callback, initialValue) { // // Solution 1: // var callbackValue = 0; // var finalResult = 0; // for(let i = 0; i<array.length; i ) { // if (i == 0){ // callbackValue = array[i]; // finalResult = callback(callbackValue, initialValue); // } else { // finalResult = callback(finalResult, array[i]); // } // } // return finalResult;

// Solution 2: let reduceValue = initialValue; for(let i = 0; i < array.length; i ){

代码语言:javascript复制
reduceValue = callback(array[i], reduceValue);

} return reduceValue; }

const nums = [4, 1, 3]; const add = function(a, b) { return a b; } console.log(reduce(nums, add, 0)); //-> 8 挑战7 intersection 问题:

构建intersection函数,作用为比较输入进来的多组数组并返回一个包含数组间共同元素的新数组。奖励:使用reduce!

题解: // Challenge 7 function intersection(arrays) { // Solution 1 (without reduce): // var obj = {}; // for(let i=0; i<arrays.length; i ){ // if(i==0){ // for(var j=0;j<arrays[i].length; j ){ // objarrays[i]=arraysi; // } // } else { // for(var j=0;j<arrays[i].length; j ){ // // console.log(objarrays[i]) // if(objarrays[i] != undefined){ // objarrays[i]= objarrays[i] 1; // } // } // } // } // for(var k in obj) { // if(k != obj[k] - arrays.length 1) { // delete obj[k]; // } // } // var intersectionArray = []; // for(var z in obj){ // intersectionArray.push(parseInt(z)); // } // return intersectionArray;

// Solution 2 (with reduce): return arrays.reduce((acc, curr) => {

代码语言:javascript复制
return curr.filter(el => acc.includes(el));

}) }

console.log(intersection([[5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]])); // should log: [5, 15] 挑战8 union 问题:

构建union函数,作用为比较输入进来的多组数组并返回一个包含输入数组中所有元素的新数组。如果存在重复元素,则新数组中仅保留一个,另外需保留新数组的元素顺序为从第一个输入数组的第一个元素开始。奖励:使用reduce!

题解: // Challenge 8 function union(arrays) { // // Solution 1 (without reduce): // var obj = {}; // for(let i=0; i<arrays.length; i ){ // if(i==0){ // for(var j=0;j<arrays[i].length; j ){ // objarrays[i]=arraysi; // } // } else { // for(var j=0;j<arrays[i].length; j ){ // // console.log(objarrays[i]) // if(objarrays[i] == undefined){ // objarrays[i]= arraysi; // } // } // } // } // var unionArray = []; // for(var z in obj){ // unionArray.push(parseInt(z)); // } // return unionArray;

// Solution 2 (with reduce): return arrays.reduce((acc, curr) => {

代码语言:javascript复制
const newElements = curr.filter(el => !acc.includes(el));
return acc.concat(newElements);

} ) }

console.log(union([[5, 10, 15], [15, 88, 1, 5, 7], [100, 15, 10, 1, 5]])); // should log: [5, 10, 15, 88, 1, 7, 100] 挑战9 objOfMatches 问题:

构建objOfMatches函数,接受两个数组和一个回调函数作为参数,作用为创建一个特定对象并返回。objOfMatches会使用回调函数测试第一个数组的每一个元素以确认其输出是否匹配于第二个数组内相同下标的元素。如果匹配,第一个数组内的这个元素会成为所创建对象的键,而第二个数组内的相同下标元素则会成为对应的值。

题解: // Challenge 9 function objOfMatches(array1, array2, callback) { const matchObj = {}; for (let i = 0; i < array1.length; i ){

代码语言:javascript复制
if(callback(array1[i]) === array2[i]) {
  matchObj[array1[i]] = array2[i];
}

} return matchObj; }

console.log(objOfMatches(['hi', 'howdy', 'bye', 'later', 'hello'], ['HI', 'Howdy', 'BYE', 'LATER', 'hello'], function(str) { return str.toUpperCase(); })); // should log: { hi: 'HI', bye: 'BYE', later: 'LATER' } 挑战10 multiMap 问题:

构建multiMap函数,接受两个数组作为参数,第一个数组的元素为值而第二个数组的元素为回调函数。multiMap会返回一个特定对象,该对象的键为第一个数组的值,键对应的值则是将键依序传入第二个数组的回调函数中得到的返回值组成的新数组。

题解: // Challenge 10 function multiMap(arrVals, arrCallbacks) { const multiMapObj = {}; let tempArray = []; arrVals.forEach(el => {

代码语言:javascript复制
tempArray = [];
for(let i =0; i<arrCallbacks.length; i  ){
  tempArray.push(arrCallbacks[i](el));
}
multiMapObj[el] = tempArray;

}) return multiMapObj; }

console.log(multiMap(['catfood', 'glue', 'beer'], [function(str) { return str.toUpperCase(); }, function(str) { return str[0].toUpperCase() str.slice(1).toLowerCase(); }, function(str) { return str str; }])); // should log: { catfood: ['CATFOOD', 'Catfood', 'catfoodcatfood'], glue: ['GLUE', 'Glue', 'glueglue'], beer: ['BEER', 'Beer', 'beerbeer'] } 挑战11 objectFilter 问题:

构建objectFilter函数,第一个参数为对象,第二个参数为回调函数。objectFilter函数会返回特定对象。此特定对象所包含的属性为输入对象中值与其对应键传入回调函数得到的返回值一致的键值对。

题解: // Challenge 11 function objectFilter(obj, callback) { const objectFilterObj = {}; for(let key in obj) {

代码语言:javascript复制
if(obj[key] === callback(key)){
  objectFilterObj[key] = obj[key];
}

} return objectFilterObj; }

const cities = { London: 'LONDON', LA: 'Los Angeles', Paris: 'PARIS', }; console.log(objectFilter(cities, city => city.toUpperCase())) // Should log { London: 'LONDON', Paris: 'PARIS'} 挑战12 majority 问题:

构建majority函数,接受参数为一个数组和一个回调函数。回调函数的返回值为true或false。majority会遍历输入数组的元素并且对其运行回调函数,直到能够确定大多数回调函数的返回值为true。如果返回true的数目与返回false的数目相同,majority应返回false。

题解: // Challenge 12 function majority(array, callback) { let trueCounter = 0; let falseCounter = 0; array.forEach(el => {

代码语言:javascript复制
if(callback(el)) {
  trueCounter  ;
} else{
  falseCounter  ;
}

}); return (trueCounter>falseCounter)?true:false;

}

/ Uncomment these to check your work! / // const isOdd = function(num) { return num % 2 === 1; }; console.log(majority([1, 2, 3, 4, 5], isOdd)); // should log: true console.log(majority([2, 3, 4, 5], isOdd)); // should log: false 挑战13 prioritize 问题:

构建prioritize函数,接受参数为一个数组和一个回调函数。回调函数的返回值为true或false。prioritize会遍历输入数组的元素并且对其运行回调函数,然后返回一个新数组。这个新数组会先储存输入数组中被回调函数返回true的元素,再储存输入数组中剩下的元素。

题解: // Challenge 13 function prioritize(array, callback) { const prioritizeArray = []; const restArray = []; array.forEach(el => {

代码语言:javascript复制
if(callback(el)){
  prioritizeArray.push(el);
} else {
  restArray.push(el);
}

}) return prioritizeArray.concat(restArray); }

/ Uncomment these to check your work! / const startsWithS = function(str) { return str[0] === 's' || str[0] === 'S'; }; console.log(prioritize(['curb', 'rickandmorty', 'seinfeld', 'sunny', 'friends'], startsWithS)); // should log: ['seinfeld', 'sunny', 'curb', 'rickandmorty', 'friends'] 挑战14 countBy 问题:

构建countBy函数,接受参数为一个数组和一个回调函数,返回值为一个特定对象。countBy会遍历输入数组的元素并对其运行回调函数。每一个运行回调函数得到的返回值会被储存为特定对象的键,而键对应的值则为得到此返回值的回调函数运行的次数。

题解: // Challenge 14 function countBy(array, callback) { const countByObj = {}; array.forEach(el => {

代码语言:javascript复制
if(countByObj[callback(el)] == undefined) {
  countByObj[callback(el)] = 1;
} else {
  countByObj[callback(el)]  ;
}

}) return countByObj; }

/ Uncomment these to check your work! / console.log(countBy([1, 2, 3, 4, 5], function(num) { if (num % 2 === 0) return 'even'; else return 'odd'; })); // should log: { odd: 3, even: 2 } 挑战15 groupBy 问题:

构建groupBy函数,接受参数为一个数组和一个回调函数,返回值为一个特定对象。groupBy会遍历输入数组的元素并对其运行回调函数。每一个运行回调函数得到的返回值会被储存为特定对象的键,而键对应的值则为一个由导致回调函数产生此返回值的输入数组的元素组成的数组。

题解: // Challenge 15 function groupBy(array, callback) { const groupByObj = {}; array.forEach(el => {

代码语言:javascript复制
if(groupByObj[callback(el)] === undefined) {
  groupByObj[callback(el)] = [el];
} else {
  groupByObj[callback(el)] = groupByObj[callback(el)].concat([el]); 
}

}) return groupByObj; }

/ Uncomment these to check your work! / const decimals = [1.3, 2.1, 2.4]; const floored = function(num) { return Math.floor(num); }; console.log(groupBy(decimals, floored)); // should log: { 1: [1.3], 2: [2.1, 2.4] } 挑战16 goodKeys 问题:

构建goodKeys函数,接受参数为一个对象和一个回调函数。回调函数的返回值为true或false。goodKeys会遍历输入对象并运行回调函数于对象的值上。goodKeys的返回值为一个由运行回调函数后返回true的对象值所对应的对象键组成的数组。

题解: // Challenge 16 function goodKeys(obj, callback) { const goodKeysArray = []; for(let key in obj) {

代码语言:javascript复制
if(callback(obj[key])) {
  goodKeysArray.push(key);
}

} return goodKeysArray; }

/ Uncomment these to check your work! / const sunny = { mac: 'priest', dennis: 'calculating', charlie: 'birdlaw', dee: 'bird', frank: 'warthog' }; const startsWithBird = function(str) { return str.slice(0, 4).toLowerCase() === 'bird'; }; console.log(goodKeys(sunny, startsWithBird)); // should log: ['charlie', 'dee'] 挑战17 commutative 问题:

构建commutative函数,接受参数为两个回调函数和一个值。commutative会返回一个布尔值,从而表明运行第一个回调函数于输入值,再将得到的返回值输入到第二个回调函数中运行,得到的结果与逆序操作是否相同(即运行输入值于第二个回调函数,得到的返回值再输入到第一个回调函数中)。

题解: // Challenge 17 function commutative(func1, func2, value) { if(func1(func2(value)) === func2(func1(value))) {

代码语言:javascript复制
return true;

} else {

代码语言:javascript复制
return false; 

} }

/ Uncomment these to check your work! / const multBy3 = n => n * 3; const divBy4 = n => n / 4; const subtract5 = n => n - 5; console.log(commutative(multBy3, divBy4, 11)); // should log: true console.log(commutative(multBy3, subtract5, 10)); // should log: false console.log(commutative(divBy4, subtract5, 48)); // should log: false 挑战18 objFilter 问题:

构建objFilter函数,接受参数为一个对象和一个回调函数,返回值为一个特定对象。objFilter会遍历输入对象,使用输入对象的键作为回调函数的输入。如果回调函数的输出与对应的对象值相等,此键值对会被复制到特定对象中。最后objFilter返回此特定对象。

题解: // Challenge 18 function objFilter(obj, callback) {

代码语言:javascript复制
const objectFilterObj = {};

for(let key in obj) {

代码语言:javascript复制
if(obj[key] === callback(key)){
  objectFilterObj[key] = obj[key];
}

} return objectFilterObj; }

/ Uncomment these to check your work! / const startingObj = {}; startingObj[6] = 3; startingObj[2] = 1; startingObj[12] = 4; const half = n => n / 2; console.log(objFilter(startingObj, half)); // should log: { 2: 1, 6: 3 } 挑战19 rating 问题:

构建rating函数,接受参数为一个由函数组成的数组和一个值。数组中的函数的返回值皆为true或false。rating会返回一个表明将输入值运行于数组中的函数会返回true的百分比数。

题解: // Challenge 19 function rating(arrOfFuncs, value) { let trueCounter = 0; arrOfFuncs.forEach(el=> {

代码语言:javascript复制
if(el(value)){
  trueCounter  ;
}

}) return trueCounter/arrOfFuncs.length * 100; }

/ Uncomment these to check your work! / const isEven = n => n % 2 === 0; const greaterThanFour = n => n > 4; const isSquare = n => Math.sqrt(n) % 1 === 0; const hasSix = n => n.toString().includes('6'); const checks = [isEven, greaterThanFour, isSquare, hasSix]; console.log(rating(checks, 64)); // should log: 100 console.log(rating(checks, 66)); // should log: 75 挑战20 pipe 问题:

构建pipe函数,接受参数为一个由函数组成的数组和一个值。pipe会将输入值输入到数组的第一个函数中,然后再将得到的输出值输入到第二个函数中,然后输出值又再输入到第三个函数中,一直下去,直到得到数组的最后一个函数的输出值。pipe会返回这个最终输出值。

题解: // Challenge 20 function pipe(arrOfFuncs, value) { let output = value; arrOfFuncs.forEach(el => {

代码语言:javascript复制
output = el(output);

}) return output; }

/ Uncomment these to check your work! / const capitalize = str => str.toUpperCase(); const addLowerCase = str => str str.toLowerCase(); const repeat = str => str str; const capAddlowRepeat = [capitalize, addLowerCase, repeat]; console.log(pipe(capAddlowRepeat, 'cat')); // should log: 'CATcatCATcat' 挑战21 highestFunc 问题:

构建highestFunc函数,接受参数为一个对象(包含函数)和一个值。highestFunc会返回输入对象中运行输入值后得到最高值的函数所对应的键。

题解: // Challenge 21 function highestFunc(objOfFuncs, subject) { let maxKey = ""; let maxNumber = Number.NEGATIVE_INFINITY; for(let key in objOfFuncs) {

代码语言:javascript复制
if(objOfFuncs[key](subject) > maxNumber) {
  maxNumber = objOfFuncs[key](subject);
  maxKey = key;
}

} return maxKey; }

/ Uncomment these to check your work! / const groupOfFuncs = {}; groupOfFuncs.double = n => n * 2; groupOfFuncs.addTen = n => n 10; groupOfFuncs.inverse = n => n * -1; console.log(highestFunc(groupOfFuncs, 5)); // should log: 'addTen' console.log(highestFunc(groupOfFuncs, 11)); // should log: 'double' console.log(highestFunc(groupOfFuncs, -20)); // should log: 'inverse' 挑战22 combineOperations 问题:

构建combineOperations函数,接受参数为一个初始值和一个由函数组成的数组。conbineOperations会将初始值输入到输入数组的第一个函数中,得到的输出值再输入到第二个函数中,一直下去,直到输入数组中的每一个函数都被调用。combineOperations会返回输入数组的最后一个函数的输出值。

题解:

// Challenge 22 function combineOperations(startVal, arrOfFuncs) { let output = startVal; arrOfFuncs.forEach(el => {

代码语言:javascript复制
output = el(output);

}) return output; }

function add100(num) { return num 100; }

function divByFive(num) { return num / 5; }

function multiplyByThree(num) { return num * 3; }

function multiplyFive(num) { return num * 5; }

function addTen(num) { return num 10; }

/ Uncomment these to check your work! / console.log(combineOperations(0, [add100, divByFive, multiplyByThree])); // Should output 60 --> console.log(combineOperations(0, [divByFive, multiplyFive, addTen])); // Should output 10 挑战23 myFunc 问题:

构建myFunc函数,接受参数为一个数组和一个回调函数。myFunc会依序将输入数组的元素输入到回调函数中。如果回调函数返回值为true,myFunc会返回当前数组元素的下标。如果回调函数从不返回true,myFunc会返回-1。

题解: // Challenge 23 function myFunc(array, callback) { let returnIndicator = false; for(let i = 0; i< array.length; i ){

代码语言:javascript复制
if(callback(array[i])){
  returnIndicator = true;
  return i;
}

} if(!returnIndicator){

代码语言:javascript复制
return -1;

} }

const numbers = [2, 3, 6, 64, 10, 8, 12]; const evens = [2, 4, 6, 8, 10, 12, 64];

function isOdd(num) { return (num % 2 !== 0); }

/ Uncomment these to check your work! / console.log(myFunc(numbers, isOdd)); // Output should be 1 console.log(myFunc(evens, isOdd)); // Output should be -1 挑战24 myForEach 问题:

编写myForEach函数,接受参数为一个数组和一个回调函数。myForEach应该依序输入数组的每一个元素到回调函数中。myForEach的作用应该尽可能与原生的JavaScript数组方法.forEach()类似。

题解:

// Challenge 24 function myForEach(array, callback) {

代码语言:javascript复制
for (let i =0; i < array.length; i  ) {
    // To solve edge case: 
    // var arr=[0, undefined, 2]; arr[10] = 10;
    // From https://gist.github.com/alexhawkins/28aaf610a3e76d8b8264#gistcomment-2209454
    if(i in array){
        callback(array[i]);
    }

} }

// You could not use arrow function to assign prototype method! Array.prototype.myForEach = function(callback) { for(let i =0; i<this.length; i ){

代码语言:javascript复制
if(i in this) {
    callback(this[i], i, this);
}

} };

let sum = 0;

function addToSum(num) { sum = num; }

/ Uncomment these to check your work! / const numsArray = [1, 2, 3]; myForEach(numsArray, addToSum); console.log(sum); // Should output 6

sum = 0; numsArray.myForEach(addToSum); console.log(sum); // Should output 6, too.

0 人点赞