Skip to content

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;
}