Javascript 经典 Q&A
Q1. 柯里化¶
已知 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 的调用参数
function curryIt(fn) {
var args = [],
l = fn.length; //函数的 length 为形参个数
var tmpFunc = function(arg){
args.push(arg);
//递归停止条件,当参fn参数收集完毕
if(args.length >= fn.length)
return fn.apply(null, args)
return tmpFunc
}
return tmpFunc;
}
var fn = function (a, b, c) {return a + b + c};
curryIt(fn)(1)(2)(3); //output: 6
Q2. 检查重复字符串¶
给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false
function containsRepeatingLetter(str) {
var reg = new RegExp(/([a-zA-Z])\1/);
return reg.test(str)
}
用到正则表表达式 分组和引用 的概念,利用()进行分组,使用斜杠加数字表示引用。
注意:引用的就是匹配成功后的文本内容,引用的是结果,而不是表达式。
Q3. Thunk¶
thunk 函数定义:把一个函数的**执行参数**,回调函数 以及**函数本身**进行包装,变成单数的形式。
fn( args, callback ) ==> thunk( fn )( args )( callback )
function thunk(fn){
return function(){
var args = Array.from(arguments);
return function(callback){
args.push(callback);
return fn.apply(null, args);
}
}
}
// 测试用例 add
function add(x,y,z,cb){
cb();
return x+y+z;
//setTimeout(() => cb(x+y+z), 3000);
}
// 直接调用 add 函数
add(1,2,3, () => console.log('add completed!'))
// thunkify add 函数
thunk(add)(1,2,3)(() => console.log('thunk add completed!'));
深拷贝¶
function deepCopy(src){
if(typeof src !== 'object') //递归终止条件
return src;
var dst = src.constructor === Array ? [] : {};
if(window.JSON){
dst = JSON.stringify(src); //系列化对象
dst = JSON.parse(dst); //还原
} else {
for(var i in obj){
dst[i] = typeof src[i] === 'object' ?
deepCopy(src[i]) : src[i];
}
}
return dst;
};
重复一个字符串n次¶
编写一个函数repeat( str, n ), 将字符串str重复n次并输出。
1. Answer 1¶
创建长度为n+1的空数组,并以str为间隔来join
。
function repeat( str, n ){
return Array(n+1).join(str);
}
2. Answer 2¶
基于 Answer 1 的改进,使用call
方法。
function repeat( str, n ){
return Array.prototype.join.call( { length: n+1 }, str)
}
3. Answer 3¶
对 Answer 2 使用闭包。
var repeat = (function(){
//利用闭包, 缓存数组原型join方法, 省得每次都重复创建
let join = Array.prototype.join,
obj = {};
return function( str, n ){
obj.length = n+1;
return join.call( obj, str)
}
})()
4. Answer 4¶
使用二分法,降低时间复杂度到o(logn)。
function repeat( str, n ){
let result = [];
for(; n > 0; n >>= 1){
if(n%2)
result.push(str);
if(n == 1)
break;
str += str;
}
return result.join('');
}
5. Answer 5¶
更加直观的二分法。
function repeat( str, n ){
let c = n * str.length, s = str;
for(; n > 0; n >>= 1){
s += s;
}
return s.substring( 0, c );
}
6. Answer 6¶
递归,时间复杂度为o(logn)。
function repeat( str, n ){
if(n == 1) return str;
let s = repeat(str, n>>1);
s += s;
if(n%2) s += str;
return s;
}