专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷
现给定一个函数 fn,一个参数数组 args 和一个时间间隔 t,返回一个取消函数 cancelFn。函数 fn 应该立即使用 args 调用,并且在每个 t 毫秒内再次调用,直到调用 cancelFn。
定时器、闭包
这题主要考察定时器的使用,它的计数器的调用类似,区别是:
/**
* @param {Function} fn
* @param {Array} args
* @param {number} t
* @return {Function}
*/
var cancellable = function(fn, args, t) {
fn(...args);
let timer = setInterval(() => {
fn(...args)
},t);
return cancelFn = () => {
clearInterval(timer);
}
};
/**
* const result = []
*
* const fn = (x) => x * 2
* const args = [4], t = 20, cancelT = 110
*
* const log = (...argsArr) => {
* result.push(fn(...argsArr))
* }
*
* const cancel = cancellable(fn, args, t);
*
* setTimeout(() => {
* cancel()
* console.log(result) // [
* // {"time":0,"returned":8},
* // {"time":20,"returned":8},
* // {"time":40,"returned":8},
* // {"time":60,"returned":8},
* // {"time":80,"returned":8},
* // {"time":100,"returned":8}
* // ]
* }, cancelT)
*/
设计一个类 Calculator 。该类应提供加法、减法、乘法、除法和乘方等数学运算功能。同时,它还应支持连续操作的方法链式调用。Calculator 类的构造函数应接受一个数字作为 result 的初始值。
你的 Calculator 类应包含以下方法:
add - 将给定的数字 value 与 result 相加,并返回更新后的 Calculator 对象。
subtract - 从 result 中减去给定的数字 value ,并返回更新后的 Calculator 对象。
multiply - 将 result 乘以给定的数字 value ,并返回更新后的 Calculator 对象。
divide - 将 result 除以给定的数字 value ,并返回更新后的 Calculator 对象。如果传入的值为 0 ,则抛出错误 “Division by zero is not allowed” 。
power - 将 result 的值乘以给定的数字 value ,并返回更新后的 Calculator 对象。
getResult - 返回 result 的值。
结果与实际结果相差在 10-5 范围内的解被认为是正确的。
模拟,throw
一个含简单的模拟题,初始化的时候将 class 的 value 值设置为传入的值,之后的操作都是对这个 value 进行操作,加法减法乘法直接模拟即可,pow 操作调用 Math 库的 api 或者直接模拟,触发需要判定一下,如果是除 0 操作我们需要 throw 一个错误。
class Calculator {
/**
* @param {number} value
*/
constructor(value) {
this.value = value
}
/**
* @param {number} value
* @return {Calculator}
*/
add(value){
this.value += value
}
/**
* @param {number} value
* @return {Calculator}
*/
subtract(value){
this.value -= value
}
/**
* @param {number} value
* @return {Calculator}
*/
multiply(value) {
this.value *= value
}
/**
* @param {number} value
* @return {Calculator}
*/
divide(value) {
if(value == 0){
throw "Division by zero is not allowed"
}
this.value /= value
}
/**
* @param {number} value
* @return {Calculator}
*/
power(value) {
this.value = Math.pow( this.value,value )
}
/**
* @return {number}
*/
getResult() {
return this.value
}
}
给定一个对象或数组,判断它是否为空。
一个空对象不包含任何键值对。
一个空数组不包含任何元素。
你可以假设对象或数组是通过 JSON.parse 解析得到的。
判空
简单的分类讨论,如果是数组,判断其长度,如果是对象,判断其 key 值数组的长度即可
/**
* @param {Object | Array} obj
* @return {boolean}
*/
var isEmpty = function(obj) {
if(!Array.isArray(obj)){
return Object.keys(obj).length == 0;
}else{
return obj.length == 0;
}
};
之前还有两个困难题目我们来补一下
现给定一个函数 fn ,返回该函数的一个 记忆化 版本。
一个 记忆化 的函数是一个函数,它不会被相同的输入调用两次。而是会返回一个缓存的值。
函数 fn 可以是任何函数,对它所接受的值类型没有任何限制。如果两个输入值在 JavaScript 中使用 === 运算符比较时相等,则它们被视为相同。
哈希表
这题和 2623. 记忆函数 的区别是传入的内容可以是任何值,也就是说我们简单的使用 toString 获得的内容不一定是可以标识参数的,那么此时我们需要转换一下思路,我们还是按照 2623. 记忆函数 的写法来写这题,那么怎么样我们的参数才能按照原先的逻辑处理呢,那么就是我们再用一个哈希表,把传入的参数映射成一个 int 类型,这样我们再用 join(“-”) 串起整个处理后的参数列表就可以唯一标识一组参数了,下面是具体实现:
/**
* @param {Function} fn
*/
function memoize(fn) {
const map = new Map();
const hash = new Map();
let now = 0;
return function (...args) {
let kk = [];
for (var i = 0; i < args.length; i++) {
if(!hash.has(args[i])){
hash.set(args[i], now++);
}
kk.push(hash.get(args[i]))
}
let key = kk.join("-");
if (!map.has(key)) map.set(key, fn.apply(null, args));
return map.get(key);
}
}
有时候你会有一个长时间运行的任务,并且你可能希望在它完成之前取消它。为了实现这个目标,请你编写一个名为 cancellable 的函数,它接收一个生成器对象,并返回一个包含两个值的数组:一个 取消函数 和一个 promise 对象。
你可以假设生成器函数只会生成 promise 对象。你的函数负责将 promise 对象解析的值传回生成器。如果 promise 被拒绝,你的函数应将该错误抛回给生成器。
如果在生成器完成之前调用了取消回调函数,则你的函数应该将错误抛回给生成器。该错误应该是字符串 “Cancelled”(而不是一个 Error 对象)。如果错误被捕获,则返回的 promise 应该解析为下一个生成或返回的值。否则,promise 应该被拒绝并抛出该错误。不应执行任何其他代码。
当生成器完成时,您的函数返回的 promise 应该解析为生成器返回的值。但是,如果生成器抛出错误,则返回的 promise 应该拒绝并抛出该错误。
生成器、Promise
这是目前未知逻辑最复杂的题目,很多人可能连题目都读不懂,我们先来解读一下题目:
/**
* @param {Generator} generator
* @return {[Function, Promise]}
*/
var cancellable = function (generator) {
let isCancel = false; //是不是取消
let isError = false; //是不是错误
let cancel = null; // 取消函数
let p = new Promise((res, rej) => {
cancel = () => {
isError = true;
isCancel = true;
run("Cancelled")
return
};
let run = (val) => {
try {
let re = null;
if (isError) {
re = generator.throw(val);
// 被取消
if (isCancel) {
res(re.value);
return;
}else{
isError = false;
}
} else {
// 正常执行
re = generator.next(val);
}
if (re.done) {
res(re.value);
return;
} else {
re.value.then((e) => {
run(e);
}).catch((e) => {
isError = true;
run(e);
})
}
} catch (e) {
rej(e);
}
}
run(null);
})
return [cancel, p]
};
/**
* function* tasks() {
* const val = yield new Promise(resolve => resolve(2 + 2));
* yield new Promise(resolve => setTimeout(resolve, 100));
* return val + 1;
* }
* const [cancel, promise] = cancellable(tasks());
* setTimeout(cancel, 50);
* promise.catch(console.log); // logs "Cancelled" at t=50ms
*/