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