常见前端面试手写题

143 阅读3分钟

1. 实现 new()

function myNew (fun, ...args) {
  let obj = {};
  obj.__proto__ = fun.prototype;
  let res = fun.apply(obj, args);
  return res instanceof Object ? res : obj;
}

function Animal(name) {
  this.name = name;
}

let animal = myNew(Animal, 'dog');
console.log(animal.name)  // dog

2. 实现 call()

Function.prototype.myCall = function (context, ...rest) {
  context.fn = this;
  var result = context.fn(...rest);
  delete context.fn;
  return result;
}

// test
let obj = {
  name: 'jack'
}
function test(arg1, arg2, arg3) {
  console.log(this.name)   // jack
  console.log(arg1, arg2, arg3);  // 1 2 3
}
test.myCall(obj, 1,2,3);

3. 实现 apply()

Function.prototype.myApply = function (context, args) {
  context.fn = this;
  let res;
  if (!args){
    res = context.fn();
  } else  {
    res = context.fn(...args)
  }
  return res;
}

// test
let obj = {
  name: 'jack'
}
function test(arg1, arg2, arg3) {
  console.log(this.name)   // jack
  console.log(arg1, arg2, arg3);  // 1 2 3
}
test.myApply(obj, [1,2,3]);

4. 实现 bind()

Function.prototype.bindNew = function (context, ...args) {
  return (...newArgs) => this.apply(context, [...args, ...newArgs]);
};

// test
const test = {
  name: "fy",
  showName: function (last: string) {
    console.log(this.name + " is " + last);
  },
};
test.showName("handsome"); // fy is handsome
test.showName.bind({ name: "Mr.fy" })("handsome");
test.showName.bindNew({ name: "Mr.fy" })("handsome");

5. 实现 debounce()

function debounce(fn, wait) {
  let timeout = null;
  return function() {
    let context = this;
    let args = arguments;
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  }
}

6. 实现 throttle()

function throttle(fn, wait) {
  let  pre = new Date();
  return function() {
    let context = this;
    let args = arguments;
    let now = new  Date();
    if (now - pre >= wait) {
      fn.apply(context, args);
      pre = now;
    }
  }
}

7. 实现 Promise()

const PENDING = Symbol();
const REJECTED = Symbol();
const FULLFILLED = Symbol();

const MyPromise = function(fn) {
  this.state = PENDING;
  this.value = '';

  const resolve = (value) => {
    this.state = FULLFILLED;
    this.value = value;
  }

  const reject = (error) => {
    this.state = REJECTED;
    this.value = error;
  }

  this.then = (onFullFill, onReject) => {
    if (this.state == FULLFILLED) {
      onFullFill(this.value);
    } else {
      onReject(this.value);
    }
  }

  try {
    fn(resolve, reject);
  } catch(error) {
    reject(error);
  }
}

// test
let p = new MyPromise((resolve, reject) => {
  resolve('hello');
})
p.then(res => {
  console.log(res);  // hello
})

8. 实现 Promise.all()

function isPromise(object) {
  return (
    !!object && (typeof obj === 'function' || typeof obj === 'object') && object instanceof Promise
  );
}
function PromiseAll(arr) {
  return new Promise((resolve, reject) => {
    const len = arr.length,
      result = [];
    let succeed = 0;
    for (let i = 0; i < len; ++i) {
      const cur = arr[i];
      if (isPromise(cur)) {
        arr[i].then((res) => {
          process(i, res);
        }, reject);
      } else {
        process(i, cur);
      }
    }
    function process(index, value) {
      result[index] = value;
      if (++succeed === len) {
        resolve(result);
      }
    }
  });
}

function myPromiseAll(arr) {
  let res = [];
  let containPromise = false;
  return new Promise((resolve, reject) => {
    for (let i = 0; i < arr.length; i++) {
      if (isPromise(arr[i])) {
        containPromise = true;
        arr[i]
          .then((data) => {
            res[i] = data;
            if (res.length === arr.length) {
              resolve(res);
            }
          })
          .catch((error) => {
            reject(error);
          });
      } else {
        res[i] = arr[i];
      }
    }
    if (!containPromise) resolve(res);
  });
}

9. 实现 Promise.race()

function myPromiseRace(arr) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < arr.length; i++) {
      return arr[i].then(resolve, reject)
    }
  })
}

10. 实现 Proxy

const deepClone = require('./deepclone');

function MyProxy(obj, handler) {
  let _target = deepClone(obj);
  Object.keys(_target).forEach(key => {
    Object.defineProperty(_target, key, {
      get: () => handler.get && handler.get(obj, key),
      set: newVal => handler.set && handler.set(obj, key, newVal),
    });
  });
  return _target;
}

let person = {
  name: 'jack',
  city: 'Beijing',
};

let proxy = new MyProxy(person, {
  get: (target, propKey) => target[propKey],
  set: (target, propKey, value) => {
    target[propKey] = value;
  },
});

// test
console.log(proxy.name); // jack
proxy.city = 'Nanjing'; 
console.log(proxy.city);  // Nanjing
console.log(person); // { name: 'jack', city: 'Nanjing' }

11. 深拷贝

function deepClone(obj) {
  // 先判断是对象还是数组
  let copy = obj instanceof Array ? [] : {};
  for (let key in obj) {
    // 判断是否是对象上的属性,而不是原型上的属性
    if (obj.hasOwnProperty(key)) {
      // obj[key] 是否是对象,如果是对象,递归遍历
      copy[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
    }
  }
  return copy;
}

// test
// console.log(deepClone({name: 'jack', birth: {year: '1997', month: '10'}})) // {name: 'jack', birth: {…}}

module.exports = deepClone;

12. 函数柯里化

函数柯里化(function currying):是把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,并且返回接收余下的参数而且返回结果的新函数的技术。

/**
 * 写法一
 * 通用的 curry 化
 * @param {*} targetfn 
 * @returns 
 */
function curry(targetfn) {
  var numOfArgs = targetfn.length;
  return function fn() {
    if (arguments.length < numOfArgs) {
      return fn.bind(null, ...arguments);
    } else {
      return targetfn.apply(null, arguments);
    }
  }
}

function sum(a, b, c) {
  return a + b + c;
}
const curried = curry(sum);
console.log(curried(1)(2)(3)) // 6
console.log(curried(1,2)(3)) // 6

/**
* 写法二
*/
function sum2(...args1) {
  let x = args1.reduce((prev, next) => {return prev+next;})
  return function(...args2) {
    if (args2.length == 0) return x;
    let y = args2.reduce((prev, next) => {return prev+next;})
    return sum2(x+y)
  }
}
console.log(sum2(1,2,2,5)(7)()) // 17

13. 数组拍平

var flatten = function(arr) {
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      res = res.concat(flatten(arr[i]))
    } else {
      res.push(arr[i])
    }
  }
  return res;
}

console.log(flatten([1,[1,2,[2,4]],3,5]));  // [1, 1, 2, 2, 4, 3, 5]

14. 数组去重

/**
 * 数组去重
 *
 * @param {(number | string)[]} array
 * @returns {(number | string)[]}
 */
function unique(array) {
  for (let i = 0; i < array.length - 1; i++) {
    for (let j = i + 1; j < array.length; j++) {
      if (array[j] === array[i]) {
        array.splice(j, 1);
        j--;
      }
    }
  }
  return array;
}

15. 快速排序

function quicksort(arr) {
  if (arr.length <= 1) return arr;
  let pivotIndex = arr.length >> 1;
  let pivot = arr.splice(pivotIndex, 1)[0];
  let left = [];
  let right = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] <= pivot)  {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quicksort(left).concat(pivot, quicksort(right));

}

console.log(quicksort([4,3,5,2,1,6]));   //  [1, 2, 3, 4, 5, 6]

来自:github.com/Mayandev/fe…