一天一個仿lodash函數實現-utils系列

貌似閒置了兩週沒寫了。
這次直接完成util系列的方法,在實現array系列的時候,開始發現一些示例用了其他utils,所以就不完全按順序來實現,而且在實現過程中發現,其實有些方法其實是另一個方法的進階使用。

這次主要實現了除match、mixin幾個還沒理解透的函數。

簡單方法:

function identity(value){
  return value
}
function noop(){}
function stubArray(){
  return []
}
function stubFalse(){
  return false
}
function stubObject(){
  return {}
}
function stubString(){
  return ''
}
function stubTrue(){
  return true
}

工具函數:

// 運行函數,如果函數調用異常則返回異常。
function attempt(func, ...args){
  let result;
  try{
    result = func.apply(null, args);
  }catch(e){
    result = e;
  }finally{
    return result
  }
}
// 按次數執行函數,次數序號爲函數調用參數
function times(n, iteratee){
  return Array(n).fill(1).map((_, i)=>iteratee(i))
}
// 判斷參數是否爲NaN、null或undefined
function isN(val){
  if(typeof val === 'number' && val !== val) {
    return true
  }
  return val == null;
}
// 用於設定默認值
function defaultTo(val, defaultValue){
  return isN(val)?defaultValue:val
}
// 把路徑字符串轉換成數組
function toPath(path){
  return path.replace(/\]/g,'').split(/\.|\[/)
}
let idIndex = 0
function uniqueId(prefix){
  return prefix!=null?`${prefix}${idIndex++}`:`${idIndex++}`;
}
function constant(value){
  return () => value;
}

function bindAll(obj, methodNames){
  methodNames.forEach(m => {
    obj[m] = obj[m].bind(obj)
  })
}

高階函數:

// 條件判斷函數,類似if判斷
function cond(pairs){
  return (...args)=>{
    for(let i=0;i<pairs.length;i++){
      if(pairs[i][0].apply(this, args)){
        return pairs[i][1].apply(this, args)
      }
    }
    return
  }
}
// 滿足source所有條件才返回true
function conforms(source){
  return (obj) => {
    const keys = Object.keys(source)
    for(let i=0;i<keys.length;i++){
      if(!source[keys[i]](obj[keys[i]])){
        return false;
      }
    }
    return true
  }
}

function flow(funcs){
  return (...args)=>{
    return funcs.reduce((pre, cur)=>{
      return cur.apply(this, [].concat(pre))
    }, args)
  }
}
function flowRight(funcs){
  return (...args)=>{
    return funcs.reverse().reduce((pre, cur)=>{
      return cur.apply(this, [].concat(pre))
    }, args)
  }
}

function iteratee(arg){
  let func;
  if(typeof arg === 'string'){
    func = obj => obj[arg]
  }else if(arg instanceof Array){
    func = obj => obj[arg[0]] === arg[1]
  }else if(typeof arg === 'function') {
    func = arg
  }else{
    const keys = Object.keys(arg);
    func = obj => {
      for(let i=0;i<keys.length;i++){
        if(obj[keys[i]]!==arg[keys[i]]) return false
      }
      return true
    }
  }
  return func
}

function method(path, ...args){
  return obj => {
    return propertyOf(obj)(path).apply(obj,args)
  }
}
function methodOf(obj, ...args){
  return path => {
    return method.call(this, path,...args)(obj)
  }
}

function nthArg(n){
  return (...args)=>{
    return nth(args, n)
  }
}
function over(iteratees){
  return (...args)=>{
    return iteratees.map(it=>{
      return it.apply(this, args);
    })
  }
}
function overEvery(predicates){
  return (...args)=>{
    for(let i=0;i<predicates.length;i++){
      if(!predicates[i].apply(this, args)){
        return false
      }
    }
    return true;
  }
}
function overSome(predicates){
  return (...args)=>{
    for(let i=0;i<predicates.length;i++){
      if(predicates[i].apply(this, args)){
        return true
      }
    }
    return false;
  }
}
function property(path){
  const pathArr = path instanceof Array?path:toPath(path);
  return obj=>{
    return pathArr.reduce((pre, cur)=>{
      return pre[cur]
    }, obj)
  }
}
function propertyOf(obj){
  return path => {
    return property(path)(obj)
  }
}
// 當step爲0的時候baseRange的做法是先確定數組個數,step會取1,但是在構造元素的時候通過start+=step, 這裏我在實現上放棄了這種方式。
function range(...args){
  let start = 0;
  let end;
  let step = 1;
  if(args.length===1) {
    end = args[0];
    if(end<0){
      step = -1
    }
    if(end===0){
      return [];
    }
  }else if(args.length===2){
    start = args[0]
    end = args[1]
    if(start<0) {
      step = -1;
    } 
  }else {
    start = args[0]
    end = args[1]
    step = args[2]
  }
  if(step===0) {
    return [];
  }
  if(step>0&&end<start){
    return [];
  }
  if(step<0&&end>start){
    return [];
  }
  let tmp = start;
  let result = [];
  let length = (end - start)/step;
  while(length--){
    result.push(tmp)
    tmp+=step
  }
  return result;
}
function rangeRight(...args){
  return range.apply(this. args).reverse();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章