JavaScript算法题整理(二)

JavaScript算法题

获取url中参数

描述

获取 url 中的参数

  1. 指定参数名称,返回该参数的值 或者 空字符串

  2. 不指定参数名称,返回全部的参数对象 或者 {}

  3. 如果存在多个同名参数,则返回数组

  4. 不支持URLSearchParams方法

示例1

输入:

http://www.nowcoder.com?key=1&key=2&key=3&test=4#hehe key

输出:

[1, 2, 3]

分析

获取url中参数,首先取得?#中的部分,再使用split()正则表达式获取参数的序列.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getUrlParam(sUrl, sKey) {
let paramArr = sUrl.split("?")[1].split("#")[0].split("&");
let obj = {};
let arr = [];
paramArr.forEach((e) =>{
let [key,value] = e.split("=");
if(key in obj){
obj[key] = [].concat(obj[key],value);
}else{
obj[key] = value;
}
});
return sKey ? obj[sKey] || "" : obj;
}

数组去重

描述

为 Array 对象添加一个去除重复项的方法

示例1

输入:

[false, true, undefined, null, NaN, 0, 1, {}, {}, ‘a’, ‘a’, NaN]

输出:

[false, true, undefined, null, NaN, 0, 1, {}, {}, ‘a’]

分析

使用ES6Set去重,在使用数组的from方法将Set转化为数组。

1
2
3
4
5
Array.prototype.uniq = function () {
return Array.from(new Set(this));
//ES6写法
//return [...new Set(this)];
}

知识点

数据结构Set

类似于数组,但成员的值都是唯一的,无重复值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//初始化
const s = new Set();
//初始化时加入值
const s = new Set([1,2,3,3,4,2,5]);
//展开为(...为展开符号)
[...s]//[1,2,3,4,5]
//使用add方法加入值
[1,2,3,3,4,2,5].forEach(x => s.add(x))
//set大小
s.size//输出5

//数组去重
[...new Set(array)]
//字符串去重
[...new Set('ababbc')].join('')//abc

Set中,判断两个值是否不同使用精确相等运算符===,在Set内部,两个NaN相等,但两个空对象不相等,会被视为两个值。

一些Set方法

  • add(): 加入值

  • has(): 判断是否存在某个值,返回布尔值

  • delete(): 删除某个值,返回布尔值,即是否删除成功

  • clear(): 清空Set。

  • Array.from(set): 将Set结构转为数组。

计时器

描述

实现一个打点计时器,要求

  1. 从 start 到 end(包含 start 和 end),每隔 100 毫秒 console.log 一个数字,每次数字增幅为 1

  2. 返回的对象中需要包含一个 cancel 方法,用于停止定时操作

  3. 第一个数需要立即输出

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//setInterval
function count(start, end) {
console.log(start++);
let timer = setInterval(function(){
if(start <= end){
console.log(start++);
}else{
clearInterval(timer);
}
},100);
return {
cancel: function(){
clearInterval(timer);
}
};

}
//setTimeout
function count(start, end) {
if(start <= end){
console.log(start);
start++;
st = setTimeout(function(){
count(start, end)
}, 100);
}
return {
cancel: function(){clearTimeout(st);}
}
}

知识点

  1. setInterval()

以固定的时间间隔,重复运行一段代码,每次调用之间有固定的时间延迟。返回一个时间间隔ID,该ID唯一标识时间间隔,可以通过调用clearInterval()来删除。

1
var intervalID = setInterval(func, delay, [arg1,...,argx]);
  • func: 要调用的函数,每经过指定delayms后执行的函数。不接受任何参数,也没有返回值

  • delay: 每次延迟的毫秒数。

  • intervalID: 非零数值,用来标识通过setInterval()创建的计时器,可以作为clearInterval()的参数来清除计时器。

  1. setTimeout()

在指定的时间后执行一段代码。

1
var timeoutID = setTimeout(function[,delay,arg1,...,argx]);
  • function: 延迟时间delay后执行的函数

  • delay(可选): 若不设置,默认为0,即马上执行。

  • timeoutID: 正整数,表示定时器的编号,可以传递给clearTimeout()来取消定时器。

  1. 递归setTimeout()可以实现setInterval()的效果

如上算法题解显示,在setTimeout()中递归调用count方法,等同于setInterval()的效果

区别在于:

递归调用方法setTimeout()保证执行之间的延迟delay相同。即上面的算法题,无论代码运行多久,间隔都是100ms。

但直接使用方法setInterval(),他的间隔delay包含运行代码花费的时间,即若console.log(start++)运行花费30ms,则间隔就为60ms。

使用闭包

描述

实现函数 makeClosures,调用之后满足如下条件:

  1. 返回一个函数数组 result,长度与 arr 相同

  2. 运行 result 中第 i 个函数,即 resulti,结果与 fn(arr[i]) 相同

示例1

输入:

1
2
3
[1, 2, 3], function (x) { 
return x * x;
}

输出:

4

1
2
3
4
5
6
7
8
9
function makeClosures(arr, fn) {
let result = [];
for(let i = 0;i<arr.length;i++){
result[i] = ()=>{
return fn(arr[i]);
};
}
return result;
}

知识点

函数闭包

函数闭包,即可以允许在一个内层函数中访问到其外层函数的作用域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//示例1
function makeAdder(x) {
return function(y) {
return x + y;
};
}
//add5、add10为makeAdder方法返回的函数function(y)的实例
var add5 = makeAdder(5);//即外层函数中x=5
var add10 = makeAdder(10);//即外层函数中x=10

console.log(add5(2)); // 即function(y=2){}。输出7
console.log(add10(2)); //即function(y=2){}。输出12

//示例二
//如下,size为makeSizer方法中外部定义的参数。
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
//新定义的size12、size14、size16为makeSizer方法返回的匿名函数function的实例。
var size12 = makeSizer(12);//则其设置size=12
var size14 = makeSizer(14);//设置size=14
var size16 = makeSizer(16);//设置size=16

柯里化

描述

已知 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 的调用参数

示例一

输入:

1
var fn = function (a, b, c) {return a + b + c}; curryIt(fn)(1)(2)(3);

输出:

6

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function curryIt(fn) {
//获取fn参数的数量
var n = fn.length;
//声明一个数组args
var args = [];
//返回一个匿名函数
return function(arg){
//将curryIt后面括号中的参数放入数组
args.push(arg);
//如果args中的参数个数小于fn函数的参数个数,
//则执行arguments.callee(其作用是引用当前正在执行的函数,这里是返回的当前匿名函数)。
//否则,返回fn的调用结果
if(args.length < n){
return arguments.callee;
}else return fn.apply("",args);
}
}
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020-2024 Aweso Lynn
  • PV: UV: