资讯专栏INFORMATION COLUMN

JS能力测评经典题

zhangke3016 / 3501人阅读

每道题都写多种解法,开阔思路。一共45道题。
因为牛客网oj不支持ES6语法,所以大多数写法只给出传统写法。

题目描述
找出元素 item 在给定数组 arr 中的位置

输出描述:
如果数组中存在 item,则返回元素在数组中的位置,否则返回 -1
输入例子:
indexOf([ 1, 2, 3, 4 ], 3)
输出例子:
2

// 一般写法
function indexOf(arr, item) {
    for (var i = 0; i < arr.length; ++i) {
        if (item === arr[i]) {
            return i;
        }
    }
    return -1;
}

// 简单粗暴版(因为js自带的indexOf函数功能已经实现了)
function indexOf(arr, item) {
    return arr.indexOf(item);
}

// 每次比较后都将数组首元素去掉,同时计数器加1,直到找到元素item
function indexOf(arr, item) {
    var count = 0, len = arr.length;
    while (arr.length !== 0 && arr[0] !== item) {
        arr.shift();
        count++;
    }

    return count === len ? -1 : count;
}

// 较复杂的写法(不建议使用)
function indexOf(arr, item) {
    var pos = arr.map(function(e, index) {
        return e === item ? index: -1;
    }).filter(function(e) {
        return e !== -1;
    });

    return pos.length === 0 ? -1 : pos[0];
}

// forEach加try-catch语句(不建议使用)
function indexOf(arr, item) {
    try {
        arr.forEach((e, i) => {
            if (e === item) {
                throw new Error(i);
            }
        } catch (err) {
            return err.message;
        }
        return -1;
    }
}

题目描述

计算给定数组 arr 中所有元素的总和
输入描述:
数组中的元素均为 Number 类型
输入例子:
sum([ 1, 2, 3, 4 ])
输出例子:
10

// 一般写法
function sum(arr) {
    var sum = 0;
    for (var i = 0; i < arr.length; ++i) {
        sum += arr[i];
    }
    return sum;
}

// 使用reduce,且将sum初始化为0
function sum(arr) {
    return arr.reduce(function(sum, e) {
        return sum + e;
    }, 0);
}
// ES6写法,且将reduce中传的0省略,则sum在这里相当于初始化为arr的首元素
//【第一个sum为函数名,其余为函数内变量名】
const sum = (arr) => arr.reduce((sum, e) => sum + e);

题目描述

移除数组 arr 中的所有值与 item 相等的元素。不要直接修改数组 arr,结果返回新的数组
输入例子:
remove([1, 2, 3, 4, 2], 2)
输出例子:
[1, 3, 4]

// 一般写法
function remove(arr, item) {
    var tempArr = [];
    for (var i = 0; i < arr.length; ++i) {
        tempArr.push(arr[i]);
    }
    /* 对arr的拷贝可使用一个技巧,即 tempArr = arr.slice(0);
       以后均采用这种写法*/

    var index = tempArr.indexOf(item);
    while (index !== -1) {
        tempArr.splice(index, 1); // 每次删一个元素
        index = tempArr.indexOf(item);
    }

    return tempArr;
}


// 使用filter
function remove(arr, item) {
    return arr.filter(function(e) {
        return e !== item;
    });
};
// ES6写法
const remove = (arr, item) => arr.filter((e) => e !== item);

移除数组 arr 中的所有值与 item 相等的元素,直接在给定的 arr 数组上进行操作,并将结果返回

输入例子:
removeWithoutCopy([1, 2, 2, 3, 4, 2, 2], 2)
输出例子:
[1, 3, 4]

// 一般写法
function removeWithoutCopy(arr, item) {
    for (var i = 0; i < arr.length; ++i) {
        if (arr[i] === item) {
            arr.splice(i, 1);
            i--;
        };
    };

    return arr;
}

// 类似地
function removeWithoutCopy(arr, item) {
    var index = arr.indexOf(item);
    while (index !== -1) {
        arr.splice(index, 1);
        index = arr.indexOf(item);
    }

    return arr;
}

/* 因为filter会改变不修改数组本身,会返回一个新数组,所以此处不采用 */

题目描述

在数组 arr 末尾添加元素 item。不要直接修改数组 arr,结果返回新的数组
输入例子:
append([1, 2, 3, 4], 10)
输出例子:
[1, 2, 3, 4, 10]

function append(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.push(item);

    return tempArr;
}

题目描述

删除数组 arr 最后一个元素。不要直接修改数组 arr,结果返回新的数组
输入例子:
truncate([1, 2, 3, 4])
输出例子:
[1, 2, 3]

// 一般写法
function truncate(arr) {
    var tempArr = arr.slice(0);
    tempArr.splice(arr.length - 1);

    return tempArr;
}

// 使用pop
function truncate(arr) {
    var tempArr = arr.slice(0);
    tempArr.pop();

    return tempArr;
}

题目描述

在数组 arr 开头添加元素 item。不要直接修改数组 arr,结果返回新的数组
输入例子:
prepend([1, 2, 3, 4], 10)
输出例子:
[10, 1, 2, 3, 4]

// 使用splice添加元素
function prepend(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.splice(0, 0, item);

    return tempArr;
}

// 直接使用unshift添加首元素方法
function prepend(arr, item) {
    var tempArr = arr.slice(0);
    tempArr.unshift(item);

    return tempArr;
}

题目描述

删除数组 arr 第一个元素。不要直接修改数组 arr,结果返回新的数组
输入例子:
curtail([1, 2, 3, 4])
输出例子:
[2, 3, 4]

// 使用splice删除元素
function curtail(arr) {
    var tempArr = arr.slice();
    tempArr.splice(0, 1);

    return tempArr;
}

// 直接使用shift删除首元素方法
function curtail(arr) {
    var tempArr = arr.slice();
    tempArr.shift();

    return tempArr;
}

题目描述

合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组
输入例子:
concat([1, 2, 3, 4], ["a", "b", "c", 1])
输出例子:
[1, 2, 3, 4, "a", "b", "c", 1]

// 简单粗暴版,js已实现此函数功能
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    return tempArr.concat(arr2);
}

// 直接将arr2中的元素一个个push
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    arr2.forEach(function(e) {
        tempArr.push(e);
    });

    return tempArr;
}

// 简化版,使用apply
function concat(arr1, arr2) {
    var tempArr = arr1.slice(0);
    [].push.apply(tempArr, arr2); // 简写版,可替换成下面一行,数组原型方法
    /* Array.prototype.push.apply(tempArr, arr2); */

    return tempArr;
}

题目描述

在数组 arr 的 index 处添加元素 item。不要直接修改数组 arr,结果返回新的数组
输入例子:
insert([1, 2, 3, 4], "z", 2)
输出例子:
[1, 2, "z", 3, 4]

// 使用splice添加元素
function insert(arr, item, index) {
    var tempArr = arr.slice(0);
    tempArr.splice(index, 0, item);

    return tempArr;
}

题目描述

统计数组 arr 中值等于 item 的元素出现的次数
输入例子:
count([1, 2, 4, 4, 3, 4, 3], 4)
输出例子:
3

// 一般写法
function count(arr, item) {
    var count = 0;
    arr.forEach(function(e) {
        e === item ? count++ : 0;
    });

    return count;
}

// 使用ES6的for...of循环
function count(arr, item) {
    let cnt = 0;
    for (let e of arr) {
        e === item ? cnt++ : 0;
    }
    return cnt;
}

// 使用reduce,归约写法
function count(arr, item) {
   return arr.reduce(function(cnt, e) {
       return cnt + (e === item ? 1 : 0);
   }, 0);
}
// 使用ES6箭头函数
const count = (arr, item) =>
    arr.reduce((cnt, e) =>
        cnt + (e === item ? 1 : 0), 0);

// 使用filter,返回一个新数组,其长度即为所求
const count = (arr, item) => arr.filter(e => e === item).length;

题目描述
找出数组 arr 中重复出现过的元素

输入例子:
duplicates([1, 2, 4, 4, 3, 3, 1, 5, 3]).sort()
输出例子:
[1, 3, 4]

关于indexOf与lastIndexOf的文档

// 一般写法,排序之后判断相邻元素是否相等
function duplicates(arr) {
    var sortedArr = arr.sort();
    var tempArr = [];
    for (var i = 0; i < sortedArr.length; ++i) {
        if (sortedArr[i] === sortedArr[i + 1] &&
             tempArr.indexOf(sortedArr[i]) === -1) {
            tempArr.push(sortedArr[i]);
        }
    }

    return tempArr;
}

// indexOf和lastIndexOf的妙用
function duplicates(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
       if (arr.indexOf(e) !== arr.lastIndexOf(e) &&
            tempArr.indexOf(e) === -1) {
           tempArr.push(e);
       }
    });

    return tempArr;
}

// 使用reduce
function duplicates(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
        tempArr[e] = (tempArr[e] === undefined ? 1 : tempArr[e] + 1);
        /* 计算每个元素出现次数 */
    });

    return tempArr.reduce(function(ret, e, item) {
        if (e && e !== 1 && ret.indexOf(item) === -1) {
            ret.push(item);
            /* 当元素存在,且出现次数不为1,且未push进ret中时... */
        }
        return ret;
    }, []);
}

题目描述

为数组 arr 中的每个元素求二次方。不要直接修改数组 arr,结果返回新的数组
输入例子:
square([1, 2, 3, 4])
输出例子:
[1, 4, 9, 16]

// 一般写法
function square(arr) {
    var tempArr = [];
    arr.forEach(function(e) {
        tempArr.push(e * e);
    });

    return tempArr;
}

// 使用map
function square(arr) {
    return arr.map(function(e) {
        return e * e;
    })
}
// ES6箭头函数版
const square = arr => arr.map(e => e * e);

题目描述

在数组 arr 中,查找值与 item 相等的元素出现的所有位置
输入例子:
findAllOccurrences("abcdefabc".split(""), "a").sort()
输出例子:
[0, 6]

// 一般写法(类C,不推荐)
function findAllOccurrences(arr, item) {
    var tempArr = [];
    for (var i = 0; i < arr.length; i++){
        if (arr[i] === item) {
            tempArr.push(i);
        }
    }

    return tempArr;
}

// 改进版
function findAllOccurrences(arr, item) {
    var tempArr = [];
    arr.forEach(function(e, index) {
        e !== item || tempArr.push(index);
    });

    return tempArr;
}

// 使用map和filter
function findAllOccurrences(arr, item) {
    return arr.map(function(ele, index) {
        return ele === item ? index : -1;
        /* 样例返回结果为[ -1, -1, -1, -1, -1, -1, -1, 0, 6 ] */
    }).filter(function(e) {
        return e !== -1;
        /* 过滤掉 e === -1 的情况 */
    })
}
// ES6箭头函数版
const findAllOccurrences = (arr, item) =>
    arr.map((ele, index) => ele === item ? index : -1).filter(e => e !== -1);

题目描述

给定的 js 代码中存在全局变量,请修复

function globals() {
    myObject = {
      name : "Jory"
    };
    return myObject;
}
/* 在JavaScript中,如果不使用var声明变量,则该变量被视为全局变量。*/

// 直接加var (在ES6标准中,最好替换成const或let)
function globals() {
    var myObject = {
      name : "Jory"
    };

    return myObject;
}

// 把对象归属改为原型
function globals() {
    globals.prototype.myObject = {
        name : "Jory"
    };

    return globals;
}

// 把对象改为匿名的
function globals() {
    return { name : "Jory" };
}

题目描述

请修复给定的 js 代码中,函数定义存在的问题

function functions(flag) {
    if (flag) {
      function getValue() { return "a"; }
    } else {
      function getValue() { return "b"; }
    }
    return getValue();
}

输入例子:
functions(true)
输出例子:
a

/* else中的语句相当于将if中的function重写,因此无论flag为何值,返回的方法始终为重写后的方
   法。将方法赋值给一个变量,方法就不会被重写 */

// 将方法赋值给一个变量
function functions(flag) {
    var getValue = null;
    if (flag) {
        getValue = function () { return "a"; }
    } else {
        getValue = function () { return "b"; }
    }

    return getValue();
}

// 修改为闭包形式
function functions(flag) {
    if (flag) {
        return (function() { return "a"; })();
    } else {
        return (function() { return "b"; })();
    }
}

// 使用 ?: 判断语句整合版
function functions(flag) {
    function getValue() {
        return flag ? "a" : "b";
    }

    return getValue();
}
// ES6箭头函数形式(精简版)
const functions = flag => flag ? "a" : "b";

题目描述

修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例

function parse2Int(num) {
    return parseInt(num);
}

输入例子:
parse2Int("12"); parse2Int("12px"); parse2Int("0x12")
输出例子:
12; 12; 0

/* parseInt(string, radix);
   当参数radix的值为0,或没有设置该参数时,parseInt()会根据 string 来判断数字的基数。
   如果string以"0x"开头,parseInt()会把string的其余部分解析为十六进制的整数。
   如果string以0开头,那么ECMAScript3允许parseInt()的一个实现把其后的字符解析为八进制
   或十六进制的数字。如果string以1~9的数字开头,parseInt()将把它解析为十进制的整数 */

// 将所有输入转换成十进制输出
function parse2Int(num) {
    return parseInt(num, 10);
}

题目描述

判断 val1 和 val2 是否完全等同

function identity(val1, val2) {
    return val1 === val2;
}

题目描述

实现一个打点计时器,要求
1、从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1
2、返回的对象中需要包含一个 cancel 方法,用于停止定时操作
3、第一个数需要立即输出

setTimeout和setInterval的语法相同。它们都有两个参数,一个是将要执行的代码字符串,还有一个
是以毫秒为单位的时间间隔,当过了那个时间段之后就将执行那段代码。
不过这两个函数还是有区别的,setInterval在执行完一次代码之后,经过了那个固定的时间间隔,它还
会自动重复执行代码,而setTimeout只执行一次那段代码。
window.setInterval("function", time); //设置一个超时对象,周期="交互时间"
window.setTimeout("function", time);  //设置一个超时对象,只执行一次,无周期
/* 停止定时 */
window.clearInterval(对象);   // 清除已设置的setInterval对象
window.clearTimeout(对象);    // 清除已设置的setTimeout对象
setInterval setTimeout clearInterval() clearTimeout()
// 一般写法,使用setInterval
function count(start, end) {
    console.log(start++);

    var timer = setInterval(function() {
        if (start <= end) {
            console.log(start++);
        } else {
            clearInterval(timer);
        }
    }, 100);

    return {
        cancel: function() {
            clearInterval(timer);
        }
    }
}

// 用setTimeout模拟setInterval,递归写法,表述较简洁
function count(start, end) {
    if (start <= end) {
        console.log(start++);

        st = setTimeout(function() {
            count(start, end);
        }, 100);
    }

    return {
        cancel: function() {
            clearTimeout(st);
        }
    }
}

// 这种写法不符合函数式编程的特点,不推荐
function count(start, end) {
    var timer = null;
    console.log(start);

    var obj = {
        timer: setInterval(function() {
            if (start <= end) {
                start++;
                console.log(start);
            } else {
                clearInterval(this.timer);
            }
        }, 100),
        cancel: function() {
          clearInterval(this.timer);
        }
    }

    return obj;
}

题目描述

实现 fizzBuzz 函数,参数 num 与返回值的关系如下:
1、如果 num 能同时被 3 和 5 整除,返回字符串 fizzbuzz
2、如果 num 能被 3 整除,返回字符串 fizz
3、如果 num 能被 5 整除,返回字符串 buzz
4、如果参数为空或者不是 Number 类型,返回 false
5、其余情况,返回参数 num
输入例子:
fizzBuzz(15)
输出例子:
fizzbuzz

// 一般写法
function fizzBuzz(num) {
    if (num % 3 === 0 && num % 5 === 0) {
    /* 特殊地,可换为 if (num % 15 === 0) */
        return "fizzbuzz";
    } else if (num % 3 === 0) {
        return "fizz";
    } else if (num % 5 === 0) {
        return "buzz";
    }

    if (num === null || num === "" || typeof num !== "number") {
        return false;
    }

    return num;
}

// 改进写法
function fizzBuzz(num) {
    if (num === null || num === "" || typeof num !== "number") {
        return false;
    }

    var result = "";
    if (num % 3 === 0) {
        result += "fizz";
    }
    if (num % 5 === 0) {
        result += "buzz";
    }

    return result ? result : num;
}

题目描述

将数组 arr 中的元素作为调用函数 fn 的参数
输入例子:
argsAsArray(function (greeting, name, punctuation) {return greeting + ", " + name + (punctuation || "!");}, ["Hello", "Ellie", "!"])
输出例子:
Hello, Ellie!

// 直接法
function argsAsArray(fn, arr) {
    return fn(arr[0],arr[1],arr[2]);
}

/* 调用函数可以使用call或者apply这两个方法,区别在于call需要将传给函数的参数明确写出来,是
   多少参数就需要写多少参数。而apply则将传递给函数的参数放入一个数组中,传入参数数组即可 */
function argsAsArray(fn, arr) {
    return fn.apply(this, arr);
}

题目描述

将函数 fn 的执行上下文改为 obj 对象
输入例子:
speak(function () {return this.greeting + ", " + this.name + "!!!";}, {greeting: "Hello", name: "Rebecca"})
输出例子:
Hello, Rebecca!!!

// apply
function speak(fn, obj) {
    return fn.apply(obj, []); // 第二个参数可省略
}

// call
function speak(fn, obj) {
    return fn.call(obj);
}

// bind
function speak(fn, obj) {
    return fn.bind(obj)();
}

题目描述

实现函数 functionFunction,调用之后满足如下条件:
1、返回值为一个函数 f
2、调用返回的函数 f,返回值为按照调用顺序的参数拼接,拼接字符为英文逗号加一个空格,即 ", "
3、所有函数的参数数量为 1,且均为 String 类型
输入例子:
functionFunction("Hello")("world")
输出例子:
Hello, world

// 一般写法
function functionFunction(str) {
    function f(s) {
        return str + ", " + s; // 可替换为 return [str, s].join(", "); 
    }

    return f;
}

// 精简版,省略内部命名函数
const functionFunction = str => s => [str, s].join(", ");

题目描述

实现函数 makeClosures,调用之后满足如下条件:
1、返回一个函数数组 result,长度与 arr 相同
2、运行 result 中第 i 个函数,即 result[i](),结果与 fn(arr[i]) 相同
输入例子:

var arr = [1, 2, 3]; 
var square = function (x) { 
    return x * x; 
}; 
var funcs = makeClosures(arr, square); 
funcs[1]();

输出例子:
4

理解闭包
// 这种写法比较绕(多层嵌套)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(function(num) {
            return function() {
                return fn(num);
            };
        }(e));
    });

    return result;
}

// 较简洁版(一般按这种方式)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(function() {
            return fn(e);
        });
    });

    return result;
}

// bind的妙用(推荐写法)
function makeClosures(arr, fn) {
    var result = [];
    arr.forEach(function(e) {
        result.push(fn.bind(this, e));
    });

    return result;
}

/* 为了更清晰地作对比,对这几种写法分别用箭头函数表示 */
// 1
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push(num => () => fn(num))(e));
    return result;
}
// 2
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push((e => () => fn(e))(e)));
    return result;
} 
// 3
function makeClosures(arr, fn) {
    let result = [];
    arr.forEach(e => result.push(fn.bind(null, e))); 
    return result;
}

题目描述

已知函数 fn 执行需要 3 个参数。请实现函数 partial,调用之后满足如下条件:
1、返回一个函数 result,该函数接受一个参数
2、执行 result(str3) ,返回的结果与 fn(str1, str2, str3) 一致
输入例子:
var sayIt = function(greeting, name, punctuation) { return greeting + ", " + name + (punctuation || "!"); }; partial(sayIt, "Hello", "Ellie")("!!!");
输出例子:
Hello, Ellie!!!

关于js中 call、apply、bind 的用法可参考这篇博客
// 一般写法
function partial(fn, str1, str2) {
    function result(str3) {
        return fn(str1, str2, str3);
    }

    return result;
}

// call
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.call(this, str1, str2, str3);
    }

     return result;
}

// apply(这里只是为了对照)
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.apply(this, [str1, str2, str3]);
    }

    return result;
}

// 这个bind会生成一个新函数对象, 它的str1, str2参数都定死了, str3未传入, 一旦传入就会执行
function partial(fn, str1, str2) {
    return fn.bind(this, str1, str2); // 或 return fn.bind(null, str1, str2);
}

// bind同上, 多了一步, 把str3传入的过程写在另一个函数里面, 而另一个函数也有str1, str2参数
function partial(fn, str1, str2) {
    function result(str3) {
        return fn.bind(this, str1, str2)(str3);
    }

    return result;
}

// 匿名函数
function partial(fn, str1, str2) {
    return function(str3) {
        return fn(str1, str2, str3);
    }
}
// ES6
const partial = (fn, str1, str2) => str3 => fn(str1, str2, str3);

题目描述

函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。
输入例子:
useArguments(1, 2, 3, 4)
输出例子:
10

关于arguments的介绍
// 一般写法,直接利用arguments只有length属性的特点
function useArguments() {
    var sum = 0;
    for (var i = 0; i < arguments.length; ++i) {
        sum += arguments[i];
    }

    return sum;
}

// call
function useArguments() {
    var arr = [].slice.call(arguments); // 转成数组 ([]为Array.prototype的语法糖)
    return arr.reduce(function(a, b) {
        return a + b;
    });
}
/* call, bind, apply会改变生成函数对象的this, 使得arguments可以直接使用数组的方法,
   所以也可不转换成数组而直接使用reduce */

// call同上, 精简版
function useArguments() {
    return [].reduce.call(arguments, function(a, b) {
        return a + b;
    });
}

// bind
function useArguments() {
    return [].reduce.bind(arguments, function(a, b) {
        return a + b;
    })();
}

// apply
function useArguments() {
    return [].reduce.apply(arguments, [function(a, b) {
        return a + b;
    }]);
}

// eval的妙用,但不推荐使用eval
function useArguments() {
    var arr = Array.prototype.slice.call(arguments);
    return eval(arr.join("+"));
}

题目描述

实现函数 callIt,调用之后满足如下条件
1、返回的结果为调用 fn 之后的结果
2、fn 的调用参数为 callIt 的第一个参数之后的全部参数
输入例子:
var a = 1; var b = 2; var test = function (first, second) { return first === a && second === b;}; callIt(test, a, b);
输出例子:
true

箭头函数的arguments 剩余参数(rest parameter)
// slice
function callIt(fn) {
    var arr = [].slice.call(arguments, 1); 
    /* 将arguments转成数组并只截取从1开始之后的所有元素 */
    return fn.apply(this, arr);
}

// shift
function callIt(fn) {
    return [].shift.call(arguments).apply(null, arguments);
    /* [].shift.call(arguments)返回了第一个参数fn, 因为这里fn等价于arguments[0] */
}

// ES6语法糖
const callIt = (fn, ...args) => fn(...args);

题目描述

实现函数 partialUsingArguments,调用之后满足如下条件:
1、返回一个函数 result
2、调用 result 之后,返回的结果与调用函数 fn 的结果一致
3、fn 的调用参数为 partialUsingArguments 的第一个参数之后的全部参数以及 result 的调用参数
输入例子:
var a = 1; var b = 2; var c = 3; var d = 4;var test = function (first, second, third, forth) {return first + second + third + forth;};partialUsingArguments(test, a, b)(c, d);
输出例子:
10

function partialUsingArguments(fn) {
    var arr = [].slice.call(arguments, 1); 
    /* arr是由partialUsingArguments传的arguments转换而来 */
    
    function result() {
        var arrFromResult = [].slice.call(arguments);
        /* arrFromResult则从函数result中传的arguments转换, 所以不能在result外获取 */
        return fn.apply(null, arr.concat(arrFromResult));
    }

    return result;
}

// 稍微简化,跟上面差不多
function partialUsingArguments(fn) {
    var arr = [].slice.call(arguments, 1);
    
    return function() {
        return fn.apply(this, arr.concat([].slice.call(arguments)));
    }
}

题目描述

已知 fn 为一个预定义函数,实现函数 curryIt,调用之后满足如下条件:
1、返回一个函数 a,a 的 length 属性值为 1(即显式声明 a 接收一个参数)
2、调用 a 之后,返回一个函数 b, b 的 length 属性值为 1
3、调用 b 之后,返回一个函数 c, c 的 length 属性值为 1
4、调用 c 之后,返回的结果与调用 fn 的返回值一致
5、fn 的参数依次为函数 a, b, c 的调用参数
输入例子:
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);
输出例子:
6

JS中的柯里化(currying)
// apply
function curryIt(fn) {
    var arr = [];
    return function(a) {
        arr.push(a);
        return function(b) {
            arr.push(b);
            return function(c) {
                arr.push(c);
                return fn.apply(this, arr);
            }
        }
    }
}

// 推荐写法
function curryIt(fn) {
    return function(e1) {
        return function(e2) {
            return function(e3) {
                return fn(e1, e2, e3); // return fn.call(this, e1, e2, e3); 与之等价
            }
        }
    }
}
// 箭头函数
const curryIt = fn => e1 => e2 => e3 => fn(e1, e2, e3);

题目描述

返回参数 a 和 b 的逻辑或运算结果
输入例子:
or(false, true)
输出例子:
true

function or(a, b) {
    return a || b;
}

题目描述

返回参数 a 和 b 的逻辑且运算结果
输入例子:
and(false, true)
输出例子:
false

function and(a, b) {
    return a && b;
}

题目描述

完成函数 createModule,调用之后满足如下要求:
1、返回一个对象
2、对象的 greeting 属性值等于 str1, name 属性值等于 str2
3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ", " + name属性值

// 推荐写法
function createModule(str1, str2) {
    return {
        greeting: str1,
        name: str2,
        sayIt: function() {
            return [this.greeting, this.name].join(", ");
        }
    }
}

// Constructor grammer
function createModule(str1, str2) {
    function Obj() {
        this.greeting = str1;
        this.name = str2;
        this.sayIt = function() {
            return this.greeting + ", " + this.name;
        }
    }
    
    return new Obj();   
}

题目描述

获取数字 num 二进制形式第 bit 位的值。注意:
1、bit 从 1 开始
2、返回 0 或 1
3、举例:2 的二进制为 10,第 1 位为 0,第 2 位为 1
输入例子:
valueAtBit(128, 8)
输出例子:
1

// 推荐写法 (时间复杂度是O(log bit))
function valueAtBit(num, bit) {
    return (num & Math.pow(2, bit - 1)) === 0 ? 0 : 1;
}

// 利用运算符特性,简洁写法 (时间复杂度O(n))
function valueAtBit(num, bit) {
    return num >> (bit - 1) & 1;
}

// 转成字符串 (不推荐)
function valueAtBit(num, bit) {
    var s = num.toString(2);
    var len = s.length;
    return parseInt(s[len - bit]);
}

题目描述

给定二进制字符串,将其换算成对应的十进制数字
输入例子:
base10("11000000")
输出例子:
192

// parseInt(string, radix) 的可选参数是操作数的进制说明,不是目标的进制。
function base10(str) {
    return parseInt(str, 2);
}

题目描述

将给定数字转换成二进制字符串。如果字符串长度不足 8 位,则在前面补 0 到满8位。
输入例子:
convertToBinary(65)
输出例子:
01000001

// 前三种都是采用拼接方法
function convertToBinary(num) {
    var s = num.toString(2);
    var len = s.length;
    if (len < 8) {
        s = "0000000".slice(0, 8 - len) + s;
    }
    
    return s;
}

function convertToBinary(num) {
    var s = num.toString(2);
    while (s.length < 8) {
        s = "0" + s;
    }
     
    return s;
}

function convertToBinary(num) {
    var s = num.toString(2);
    return s.length < 8 ? new Array(8 - s.length + 1).join("0").concat(s) : s;
}

// 推荐写法, 如果长度过长, 则截取后8位(倒数第8位开始到最后1位)
function convertToBinary(num) {
    var s = num.toString(2);
    return s.length < 8 ? ("00000000" + s).slice(-8) : s;
}

题目描述

求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题
输入例子:
multiply(3, 0.0001)
输出例子:
0.0003

String.prototype.substring() Number.prototype.toFixed()
// 推荐写法
function multiply(a, b) {
    a = a.toString();
    b = b.toString();
    var aLen = a.substring(a.indexOf(".") + 1).length;
    var bLen = b.substring(b.indexOf(".") + 1).length; 
    
    return (a * b).toFixed(Math.max(aLen, bLen));
    /* 本题未说明保留小数位数, 这里假定得出的结果不含多余的0, 即0.0003000...需转成0.0003 */
}

题目描述

将函数 fn 的执行上下文改为 obj,返回 fn 执行后的值
输入例子:
alterContext(function() {return this.greeting + ", " + this.name + "!"; }, {name: "Rebecca", greeting: "Yo" })
输出例子:
Yo, Rebecca!

/* 将函数fn的执行上下文改为obj对象, 只需要将obj作为call或apply的第一个参数传入即可 */
// call
function alterContext(fn, obj) {
    return fn.call(obj); // 这里的第二个参数可有可无, 如有, 则作为fn的参数(下同)
}

// apply
function alterContext(fn, obj) {
  return fn.apply(obj); 
}

// bind
function alterContext(fn, obj) {
  return fn.bind(obj)(); // .bind()返回的是一个函数, 需要立即执行 
}

题目描述

给定一个构造函数 constructor,请完成 alterObjects 方法,将 constructor 的所有实例的 greeting 属性指向给定的 greeting 变量。
输入例子:
var C = function(name) {this.name = name; return this;}; var obj1 = new C("Rebecca"); alterObjects(C, "What"s up"); obj1.greeting;
输出例子:
What"s up

继承与原型链(prototype chain)
/* 每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个
   指向原型对象的内部指针 */

function alterObjects(constructor, greeting) {
    constructor.prototype.greeting = greeting;
}

题目描述

找出对象 obj 不在原型链上的属性(注意这题测试例子的冒号后面也有一个空格~)
1、返回数组,格式为 key: value
2、结果数组不要求顺序
输入例子:
var C = function() {this.foo = "bar"; this.baz = "bim";}; C.prototype.bop = "bip"; iterate(new C());
输出例子:
["foo: bar", "baz: bim"]

Object.getOwnPropertyNames()
Object.keys()
Object.prototype.hasOwnProperty()
// 前两种均使用map (推荐写法)
function iterate(obj) {
    return Object.getOwnPropertyNames(obj).map(function(key) {
        return key + ": " + obj[key];
    });
}

function iterate(obj) {
    return Object.keys(obj).map(function(key) {
        return key + ": " + obj[key];
    });
}

/*用for-in遍历可枚举的属性, 用hasOwnProperty()方法判断是否是自有属性(即不在原型链上)*/
function iterate(obj) {
    var arr = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            arr.push(key + ": " + obj[key]);
        }
    }
    
    return arr;
}

以下为正则表达式相关题目

可以通过下面两种方法创建一个正则表达式:

使用一个正则表达式字面量,如下所示:

re = /ab+c/;

正则表达式字面量在脚本加载后编译。若你的正则表达式是常量,使用这种方式可以获得更好的性能。

调用RegExp对象的构造函数,如下所示:

re = new RegExp("ab+c");

使用构造函数,提供了对正则表达式运行时的编译。当你知道正则表达式的模式会发生改变, 或者你事先并不了解它的模式或者是从其他地方(比如用户的输入),得到的代码这时比较适合用构造函数的方式。

///

题目描述

给定字符串 str,检查其是否包含数字,包含返回 true,否则返回 false
输入例子:
containsNumber("abc123")
输出例子:
true

d 匹配一个数字, 等价于[0-9]。
例如,  /d/ 或者 /[0-9]/ 匹配 "B2 is the suite number." 中的"2"。
test()方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。返回true或false。
function containsNumber(str) {
    return /d/.test(str);
}

题目描述

给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false
输入例子:
containsRepeatingLetter("rattler")
输出例子:
true

[xyz] 一个字符集合, 匹配方括号的中任意字符。可以使用破折号(-)来指定一个字符范围。
对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。他们不必进行转义,不过转义也是起作用的。
例如,[abcd] 和[a-d]是一样的。他们都匹配"brisket"中的‘b’,也都匹配“city”中的‘c’。
/[a-z.]+/ 和/[w.]+/都匹配“test.i.ng”中的所有字符。

(x) 匹配 "x" 并且记住匹配项,就像下面的例子展示的那样。括号被称为"捕获括号"。
模式/(foo) (bar) 1 2/中的"(foo)"和"(bar)"匹配并记住字符串"foo bar foo bar"中前两个单词。
模式中的 1 和 2 匹配字符串的后两个单词。注意 1、2、
是用在正则表达式的匹配环节。
在正则表达式的替换环节,则要使用像 $1、$2、$n 这样的语法,例如,
"bar foo".replace( /(...) (...)/, "$2 $1" )。 
function containsRepeatingLetter(str) {
    return /([a-zA-Z])1/.test(str);
}

题目描述

给定字符串 str,检查其是否以元音字母结尾
1、元音字母包括 a,e,i,o,u,以及对应的大写
2、包含返回 true,否则返回 false
输入例子:
endsWithVowel("gorilla")
输出例子:
true

$ 匹配输入的结束。如果多行标示被设置为true,那么也匹配换行符前的位置。
例如,/t$/ 并不会匹配 "eater" 中的 "t",但是会匹配 "eat" 中的 "t"。

通过标志进行高级搜索
正则表达式有四个可选参数进行全局和不分大小写搜索。
这些参数既可以多带带使用也可以一起使用在任何顺序和包含正则表达式的部分中。

正则表达式标志
标志    描述
g      全局搜索。
i      不区分大小写搜索。
m      多行搜索。
y      执行“粘性”搜索,匹配从目标字符串的当前位置开始,可以使用y标志。
function endsWithVowel(str) {
    return /[aeiou]$/i.test(str);
}

题目描述

给定字符串 str,检查其是否包含连续3个数字
1、如果包含,返回最新出现的3个数字的字符串
2、如果不包含,返回 false
输入例子:
captureThreeNumbers("9876543")
输出例子:
987

String.prototype.match()
function captureThreeNumbers(str) {
    var arr = str.match(/d{3}/); // 寻找三个数字字符 d{3}
    return arr ? arr[0] : false;
}

题目描述

给定字符串 str,检查其是否符合如下格式
1、XXX-XXX-XXXX
2、其中 X 为 Number 类型
输入例子:
matchesPattern("800-555-1212")
输出例子:
true

^ 匹配输入的开始。如果多行标志被设置为true,那么也匹配换行符后紧跟的位置。
例如,/^A/ 并不会匹配 "an A" 中的 "A",但是会匹配 "An E" 中的 "A"。
当 "^" 作为第一个字符出现在一个字符集合模式时,它将会有不同的含义。
function matchesPattern(str) {
    return /^(d{3}-){2}d{4}$/.test(str);
}

题目描述

给定字符串 str,检查其是否符合美元书写格式
1、以 $ 开始
2、整数部分,从个位起,满 3 个数字用 , 分隔
3、如果为小数,则小数部分长度为 2
4、正确的格式如:$1,023,032.03 或者 $2.03,错误的格式如:$3,432,12.12 或者 $34,344.3
输入例子:
isUSD("$20,933,209.93")
输出例子:
true

? 匹配前面一个表达式0次或者1次。等价于 {0,1}。
例如,/e?le?/ 匹配 "angel" 中的 "el",和 "angle" 中的 "le" 
(注意第二个 ? 前面的匹配表达式是 e 而不是 le) 以及 "oslo" 中的"l"。

如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪的(匹配尽量少的字符),和缺省
使用的贪婪模式(匹配尽可能多的字符)正好相反。
例如,对 "123abc" 应用 /d+/ 将会返回 "123",如果使用 /d+?/,那么就只会匹配到 "1"。
还可以运用于向前断言 正向肯定查找x(?=y) 和 正向否定查找x(?!y) 。

* 匹配前一个表达式0次或多次。等价于 {0,}。
例如,/bo*/会匹配 "A ghost boooooed" 中的 "booooo" 和 "A bird warbled" 中的 "b", 
但是在 "A goat grunted" 中将不会匹配任何东西。

. (小数点)匹配  除了换行符(
)之外的任何单个字符。
例如, /.n/将会匹配"nay, an apple is on the tree"中的"an"和"on", 但是不会匹配 "nay"。
function isUSD(str) {
    return /^$d{1,3}(,d{3})*(.d{2})?$/.test(str);
}

如有错误,恳请指正,也欢迎各位大佬贡献出更好的解法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81901.html

相关文章

  • JavaScript书籍测评

    摘要:前言今天和大家一起聊聊的推荐书籍,每一本都是精选,做前端开发的朋友们如果没读过,可以尝试一下。如果怕麻烦,也可以关注晓舟报告,发送获取书籍,四个字,就可以得到电子书的提取码。 前言 今天和大家一起聊聊JavaScript的推荐书籍,每一本都是精选,做前端开发的朋友们如果没读过,可以尝试一下。下面给大家简单介绍了书的内容,还有读书的方法,希望可以帮大家提升读书效率。 一、《JavaScr...

    X1nFLY 评论0 收藏0
  • 求职准备 - 收藏集 - 掘金

    摘要:一基础接口的意义百度规范扩展回调抽象类的意义想不想通过一线互联网公司面试文档整理为电子书掘金简介谷歌求职记我花了八个月准备谷歌面试掘金原文链接翻译者 【面试宝典】从对象深入分析 Java 中实例变量和类变量的区别 - 掘金原创文章,转载请务必保留原出处为:http://www.54tianzhisheng.cn/... , 欢迎访问我的站点,阅读更多有深度的文章。 实例变量 和 类变量...

    cuieney 评论0 收藏0
  • 前端经典面试经典不要star!

    摘要:前言上一期说好的的核心模块进阶以及基本应用的使用将在号或者号与大家见面在此之前我想跟大家分享几个前端经典的面试题为什么我突然想写这么一篇文章呢今天我应公司要求去面试了下几位招聘者然后又现场整不出几个难题就搜了一下前端变态面试题,前提我并不是 前言 上一期说好的node.js的核心模块进阶以及基本web应用的使用将在2号或者3号与大家见面,在此之前我想跟大家分享几个前端经典的面试题,为什...

    codergarden 评论0 收藏0
  • 前端经典面试经典不要star!

    摘要:前言上一期说好的的核心模块进阶以及基本应用的使用将在号或者号与大家见面在此之前我想跟大家分享几个前端经典的面试题为什么我突然想写这么一篇文章呢今天我应公司要求去面试了下几位招聘者然后又现场整不出几个难题就搜了一下前端变态面试题,前提我并不是 前言 上一期说好的node.js的核心模块进阶以及基本web应用的使用将在2号或者3号与大家见面,在此之前我想跟大家分享几个前端经典的面试题,为什...

    archieyang 评论0 收藏0

发表评论

0条评论

zhangke3016

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<