各种前端手写

135 阅读2分钟

1.手写bind函数

es6:

Function.prototype.bind = function(context, ...args) {
    var fn = this;
    return function(...rest) {
        return fn.apply(context,[...args, ...rest]);
    }
}

es5:

// 定义这个方法为myBind
Function.prototype.myBind = function(thisArg) {
  if (typeof this !== 'function') {
    return;
  }
  var _self = this;
  var args = Array.prototype.slice.call(arguments, 1) //从第二个参数截取
  return function() {
    return _self.apply(thisArg, args.concat(Array.prototype.slice.call(arguments))); // 注意参数的处理
  }
}

2.手写new

function Otaku () { …… } 
// 使用 new 
var person = new Otaku(……); 

// 使用 objectFactory 
var person = objectFactory(Otaku, ……)


function objectFactory() {

    var obj = new Object(),

    var Constructor = [].shift.call(arguments);
    // 本函数传入的第一个参数为构造函数

    obj.__proto__ = Constructor.prototype;

    Constructor.apply(obj, arguments);

    return obj;

};

3.数组扁平化

1.递归

function flatten(arr) {
    var res = [];
    arr.forEach(item => {
        if(Array.isArray(item)) {
            res = res.concat(flatten(item));
        } else {
            res.push(item);
        }
    });
    return res;
}

2.reduce

// 说白了还是在递归
function flatten(arr) {  
    return arr.reduce((result, item)=> {
        return result.concat(Array.isArray(item) ? flatten(item) : item);
    }, []);
}

3.toString & split或者join & split

function flatten(arr) {
    return arr.toString().split(',').map(function(item) {
        return Number(item);
    })
} 
// join的话,用join',')替代toString(),parseInt替换Number就好。

4.concat

function flatten(arr) {
    while(arr.some(item=>Array.isArray(item))) {
        arr = [].concat(...arr);
    }
    return arr;
}
// concat每次都能处理一层,[].concat(1, 2, 3, [4, 5])会返回[1,2,3,4,5]

4.函数柯里化

1:
function curry(fn) {
  // 获取原函数的参数长度
  const argLen = fn.length;
  // 保存预置参数
  const presetArgs = [].slice.call(arguments, 1)
  // 返回一个新函数
  return function(...args) {
    // 新函数调用时会继续传参
    const allArgs = [...presetArgs, ...args]
    if (allArgs.length >= argLen) {
      // 如果参数够了,就执行原函数
      return fn.apply(this, allArgs)
    } else {
      // 否则继续柯里化
      return curry.call(null, fn, ...allArgs)
    }
  }
}
总结:首先返回的是一个函数,这个函数的功能是,若能下一步调用出结果就出结果。否则,当做第一次柯里化的时候就带上了参数,供后面使用,每次创建新闭包,也有了新的闭包数据。

法2:
function curry(fn){
  let judge = (...args) => {
    if(args.length === fn.length) return fn(...args)
    return (...arg) =>{judge(...args,...arg)}
  } 
  return judge
}
第二种更牛逼,用第二种吧


function fn(a, b, c) {
  return a + b + c;
}
var curried = curry(fn);
curried(1, 2, 3); // 6
curried(1, 2)(3); // 6
curried(1)(2, 3); // 6
curried(1)(2)(3); // 6
curried(7)(8)(9); // 24

5.手写promise.all

function PromiseAll(promiseArray) {    //返回一个Promise对象
     return new Promise((resolve, reject) => {
        const result = []
        let count = 0                         //设置一个计数器
        promiseArray.forEach((item,index) =>{
          item.then(res =>{
            count++
            result[index] = res
            if(count === promiseArr.length){
             resolve(result)
            }
          }).catch(err =>{
             reject(err)
          })
        })
    })
}

6.手写instanceOf

function _instanceof(A, B) {
    var O = B.prototype; 
    A = A.__proto__;
    while (true) {
        if (A === null)
            return false;
        if (O === A)
            return true;
        A = A.__proto__;
    }
}

7.手写reduce

Array.prototype.myReduce = function (cb, initialValue) {
  const array = this//获取数组
  let acc = initialValue || array[0]//acc相当于pre
  const startIndex = initialValue ? 0 : 1
  for (let i = startIndex; i < array.length; i++) {
    const cur = array[i]
    acc = cb(acc, cur, i, array)
  }
  return acc
}