hookex
11/25/2019 - 8:16 AM

JavaScript工具函数

JavaScript工具函数

function flatArr(arr: any[]) {
  let result = [];
  for(let i=0; i<arr.length; i++) {
    const cur = arr[i];
    console.log('cur', cur)
    if (Array.isArray(cur)) {
      result = result.concat(flatArr(cur));
    } else {
      result.push(cur);
    }
  }
  return result;
}


console.log(flatArr([1,2,3, [2, 3, [4, 5]], 2, 0]))
// 不立即执行
function log() {
  return console.log.bind(null, ...arguments);
}

log(1,2,3)()

// 立即执行
function log() {
  console.log.apply(null, arguments); 
}
log(1,2,3);
const sleep = (time) => {
  return new Promise(resolve => setTimeout(resolve, time))
}

sleep(1000).then(() => {
    // 这里写你的骚操作
})
// 异步队列,同时最多只有10个promise在执行
// 自己想的,应该还不对

const throttlePromise = (function() {
  let queue = [];
  let callbacks = [];
  let count = 0;

  function tick() {
    if (count < 3 && queue.length) {
      let current = queue.shift();
      let func = callbacks.shift();
      count++;

      current.then(() => {
        func();
        count--;
        tick();
      });
    }
  }

  return (pro: Promise<any>, callback: Function) => {
    queue.push(pro);
    callbacks.push(callback);
    tick();
  };
})();

let testPromise = new Promise(resolve => {
  setTimeout(resolve, 2000);
});

let count = 0;

throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
throttlePromise(testPromise, _ => console.log(count++));
export default class Events {
  constructor () {
    this._queue = []
  }

  on (key, callback) {
    this._queue[key] = this._queue[key] || []
    this._queue[key].push(callback)
    return this
  }

  off (key, callback) {
    if (this._queue[key]) {
      const index = typeof (callback) === 'undefined' ? -2 : this._queue[key].indexOf(callback)
      if (index === -2) {
        delete this._queue[key]
      } else if (index !== -1) {
        this._queue[key].splice(index, 1)
      }
      if (this._queue[key] && this._queue[key].length === 0) delete this._queue[key]
    }
    return this
  }

  has (key) {
    return !!this._queue[key]
  }

  trigger (key, ...args) {
    if (this._queue[key]) {
      this._queue[key].forEach((callback) => callback.apply(this, args))
    }
    return this
  }
}
function memo(func: Function) {
  const cache = {};

  return function(...args) {
    const key = arguments.length + args.join();
    if (key in cache) {
      return cache[key];
    }
    return (cache[key] = func.apply(this, arguments));
  };
}

function add(a, b) {
  console.log("add", a, b);
  return a + b;
}

const memoAdd = memo(add);

console.log(memoAdd(1, 2));
console.log(memoAdd(1, 2));
console.log(memoAdd(2, 2));
function transfer(number) {
    let str = String(number);
    let len = str.length;
    
    let result = '';
    
    for(let i=len-1; i >= 0; i--) {
        result = str[i] + result;
        if ((len-i) % 3 === 0 && i !== 0) {
            result = ',' + result;
        }
    }
    
    return result;
}

console.log(transfer(10000000))
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})
function create(Con: Function, ...args) {
  var obj = {};
  Object.setPrototypeOf(obj, Con.prototype);
  Con.apply(obj, args);
  return obj;
}

function Car(name: string) {
  this.name = name;
}

console.log(Array.apply(Array, [1, 2]));
console.log(create(Car, "volvo"));
const hasOwn = Object.prototype.hasOwnProperty;

function is(x, y) {
  if (x === y) {
    // +0和-0
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    // NaN equal NaN
    return x !== x && y !== y;
  }
}

console.log(is(Number.MAX_VALUE, Number.MAX_VALUE));

function shallowEqual(objectA: any, objectB: any): boolean {
  if (objectA === objectB) {
    return true;
  }

  if (typeof objectA !== "object" || objectA === null) {
    return false;
  }

  if (typeof objectB !== "object" || objectB === null) {
    return false;
  }

  const keysA = Object.keys(objectA);
  const keysB = Object.keys(objectB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  for (let i = 0; i < keysA.length; i++) {
    const key = keysA[i];
    if (!hasOwn.call(objectB, key) || !is(objectA[key], objectB[key])) {
      return false;
    }
  }

  return true;
}

shallowEqual({ a: 1 }, { b: 2 });
function isSimple(from: unknown) {
  if (from === null || typeof from !== "object") {
    return true;
  }
  return false;
}

function copy(from: unknown) {
  if (isSimple(from)) {
    return from;
  }

  let v = Array.isArray(from) ? [] : {};

  for (let k in from as any) {
    if (from.hasOwnProperty(k)) {
      v[k] = isSimple(from[k]) ? from[k] : copy(from[k]);
    }
  }

  return v;
}

console.log(copy(1));
console.log(copy([{ a: 1 }]));
console.log(copy({ a: { b: 2 } }));








var assign =  function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) {
          if (Object.prototype.hasOwnProperty.call(s, p)) {
              t[p] = s[p];            
          }
        }
    }
    return t;
}


var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);

function shallowCopy(src) {
  var dst = {};
  for (var prop in src) {
    if (src.hasOwnProperty(prop)) {
      dst[prop] = src[prop];
    }
  }
  return dst;
}
/**
 Semantic Versioning 是一个前端通用的版本定义规范。格式为“{MAJOR}.{MINOR}.{PATCH}-{alpha|beta|rc}.{number}”,要求实现 compare(a, b) 方法,比较 a, b 两个版本大小。
  1. 当 a > b 是返回 1;
  2. 当 a = b 是返回 0;
  3. 当 a < b 是返回 -1;
  4. 其中,rc > beta > alpha,major > minor > patch;
  5. 例子,1.2.3 < 1.2.4 < 1.3.0.alpha.1 < 1.3.0.alpha.2 < 1.3.0.beta.1 < 1.3.0.rc.1 < 1.3.0
 */

function compareTag(tag1?: string, tag2?: string) {
  const tags = ["alpha", "beta", "rc", undefined];
  return tags.indexOf(tag1) - tags.indexOf(tag2);
}

function compareVersion(v1: string, v2: string) {
  let [major1, minor1, patch1, tag1, tagNum1] = v1.split(".");
  let [major2, minor2, patch2, tag2, tagNum2] = v2.split(".");

  if (parseInt(major1, 10) > parseInt(major2, 10)) {
    return 1;
  }

  if (parseInt(major1, 10) < parseInt(major2, 10)) {
    return -1;
  }

  if (parseInt(minor1, 10) > parseInt(minor2, 10)) {
    return 1;
  }

  if (parseInt(minor1, 10) < parseInt(minor2, 10)) {
    return -1;
  }

  if (parseInt(patch1, 10) > parseInt(patch2, 10)) {
    return 1;
  }

  if (parseInt(patch1, 10) < parseInt(patch2, 10)) {
    return -1;
  }

  const tagResult = compareTag(tag1, tag2);

  if (tagResult > 0) {
    return 1;
  } else if (tagResult < 0) {
    return -1;
  }

  if (tagNum1 !== undefined && tagNum2 !== undefined) {
    if (parseInt(tagNum1, 10) > parseInt(tagNum2, 10)) {
      return 1;
    }

    if (parseInt(tagNum1, 10) < parseInt(tagNum2, 10)) {
      return -1;
    }
  }

  return 0;
}

// 1.2.3 < 1.2.4 < 1.3.0.alpha.1 < 1.3.0.alpha.2 < 1.3.0.beta.1 < 1.3.0.rc.1 < 1.3.0

console.log(compareVersion("1.2.3", "1.2.4"));
console.log(compareVersion("1.2.4", "1.3.0.alpha.1"));
console.log(compareVersion("1.3.0.alpha.1", "1.3.0.alpha.2"));
console.log(compareVersion("1.3.0.alpha.2", "1.3.0.beta.1"));
console.log(compareVersion("1.3.0.beta.1", "1.3.0.rc.1"));
console.log(compareVersion("1.3.0.rc.1", "1.3.0"));
// 节流函数: 在n秒内忽略随后发出的源值
// 实现思路:每次触发事件时,都判断当前是否有延时函数
function throttle(fn, time) {
  let canRun = true

  return function() {
    if (canRun) {
      fn.apply(this, arguments);
      canRun = false;
      setTimeout(() => {
        canRun = true
      }, time)
    }
  }
}

function throttle2(fn, gapTime) {
  let lastTime = 0;

  return function() {
    if (Date.now() - lastTime > gapTime) {
      fn.apply(this, arguments);
      lastTime = Date.now()
    }
  }
}
static getRandom(num1, num2?): number {
  if (num1 !== undefined && num2 !== undefined) {
    return num1 + Math.random() * (num2 - num1);
  } else if (num1 !== undefined && num2 === undefined) {
    return Math.random() * num1;
  } else {
    return Math.random();
  }
}
function add(x) {
    function helper(y, x) {
        var sum = y + x;
        var f = helper.bind(null, sum);
        f.toString = function () {
            return '' + sum;
        };
        f.valueOf = function () {
            return sum;
        };
        return f;
    }
    return helper(x, 0);
}
console.log(+add(10)(10)); // 20
console.log(+add(10)(20)(50)); // 80
console.log(+add(10)(20)(50)(100)); // 180

var add30 = add(10)(20); // 30
var add100 = add30(30)(40); // 100
var add31 = add30(1); // 31
var add40 = add31(9); // 40

console.log(+add30, +add100, +add31, +add40);



function foo(x) {
    x = 0 + x;
    var bar = function (y) {
        x = x + y;
        return bar;
    };

    bar.show  = function() {
        console.log(x)
    }

    return bar;
}

foo(1)(2)(3)
// 防抖函数
function debounce(fn, delay) {
  delay = 200 || delay
  
  var timer;
  
  return function() {
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay)
  }
}
function sayHi() {
  console.log('hi')
}

window.addEventListener('scroll', debounce(sayHi, 1000));

// window.addEventListener('resize', debouceFunc)



// underscore版本
_.debounce = function(func, wait, immediate) {
  var timeout, args, context, timestamp, result;
  
  var later = function() {
    var last = _.now() - timestamp;
    if (last < wait && last >= 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };
  
  return function() {
    context = this;
    args = arguments;
    timestamp = _.now();
    var callNow = immediate && !timeout;
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }
    return result;
  };
};