Light functions
Encapsulate commonly used, lightweight utility functions.
1️⃣ Performance optimization
Debounce
debounce
Debounce function: The same event trigger within the specified time interval is only executed for the last time.
/**
* Front-end performance optimization: debounce function
* @param {Function} fn debounce processing callback
* @param {Number} delay time interval threshold
* @returns {Function} encapsulated debounce function
*/
export const debounce = (fn, delay = 200) => {
let timer;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
};
};
Throttling
throttle
Throttling function: The task will only be executed once within the specified time interval.
/**
* Front-end performance optimization: throttling function
* @param {Function} fn throttling processing callback
* @param {Number} delay time interval threshold
* @returns {Function} encapsulated throttling function
*/
export const throttle = (fn, delay = 200) => {
let timer;
return function () {
if (!timer) {
fn.apply(this, arguments);
timer = setTimeout(() => {
timer = null;
}, delay);
}
};
},
2️⃣ Time processing
Timestamp
GetTimestamp
Get the current timestamp
/**
* Get the current timestamp
* @return {String} timestamp
*/
export const getTimestamp = () => {
return new Date().getTime();
};
Timestamp format
TimestampToFormatTime
Convert timestamp to user-defined time format
/**
* Convert timestamp to user-defined time format
* @param {Number} timestamp timestamp
* @param {String} rule time format
* @returns {String}
*/
export const timestampToFormatTime = (timestamp, rule = "yyyy-MM-dd HH:mm:ss") => {
const D = new Date(timestamp);
const timeObj = {};
const rules = rule.match(/\w+/g);
let ft = rule;
timeObj["yyyy"] = D.getFullYear();
timeObj["MM"] = D.getMonth() + 1;
timeObj["dd"] = D.getDate();
timeObj["HH"] = D.getHours();
timeObj["mm"] = D.getMinutes();
timeObj["ss"] = D.getSeconds();
timeObj["ms"] = D.getMilliseconds();
rules.map((f) => {
let ff = f.length === 1 ? `${f}${f}` : f;
ft = ft.replace(new RegExp(f, "g"), fillingZero(f, timeObj[ff]));
});
return ft;
};
Time format
FormatTime
Format the time according to the rules
/**
* Format the time according to the rules
* @param {String} time The time to be formatted 2023-05-23T12:25:42.9703802 || 2023-05-23 12:25:42.9703802
* @param {String} rule Format rule yyyy-MM-dd HH:mm:ss || yyyy-M-d H:m:s Judged the zero padding
* @returns {String}
*/
export const formatTime = (time, rule = "yyyy-MM-dd HH:mm:ss") => {
const times = time.match(/\d+/g);
const timeObj = {};
const rules = rule.match(/\w+/g);
let mapping = ["yyyy", "MM", "dd", "HH", "mm", "ss", "ms"];
let ft = rule;
// 数组转对象
times.map((t, k) => {
timeObj[mapping[k]] = times[k];
});
rules.map((f) => {
let ff = f.length === 1 ? `${f}${f}` : f;
ft = ft.replace(new RegExp(f, "g"), timeObj[ff]);
// ft = ft.replace(new RegExp(f, "g"), fillingZero(f, timeObj[ff])); // Can be used with fillingZero
});
return ft;
};
Filling zeros
FillingZero
Automatically determine whether to fill zeros based on the time field name
/**
* Automatically determine whether to fill zeros based on the time field name
* @param {String} field time field name
* @param {String} value pre-processed value
* @returns {String|Number}
*/
export const fillingZero = (field, value) => {
switch (field) {
case "MM":
case "dd":
case "HH":
case "mm":
case "ss":
return value < 10 ? `0${+value}` : value;
case "M":
case "d":
case "H":
case "m":
case "s":
return +value;
default:
return value;
}
};
3️⃣ Mathematical operations
Four arithmetic operations
Calc
Basic mathematical operations can effectively avoid javascript precision issues.
/**
* Basic mathematical operations can effectively avoid javascript precision issues.
* @param { String | Number } num1 operand
* @param { String | Number } num2 operand
* @param { String } type calculation type
* @return { Number } result calculation result
*/
function calc(num1, num2, type) {
const n1 = num1.toString().split(".")[1] ?? "0";
const n2 = num2.toString().split(".")[1] ?? "0";
const point = 10 ** (+n1 > +n2 ? n1.length : n2.length); // Accuracy
let result = 0;
switch (type) {
case "+":
result = (num1 * point + num2 * point) / point;
break;
case "-":
result = (num1 * point - num2 * point) / point;
break;
case "*":
result = (num1 * point * (num2 * point)) / point / point;
break;
case "/":
result = (num1 * point) / (num2 * point);
break;
}
return result;
}
Random numbers
GetRandomInt
Get a random integer within the specified interval [min, max]
/**
* Get a random integer within the specified interval [min, max]
* @param {Number} min minimum value
* @param {Number} max maximum value
* @returns random integer
*/
export const getRandomInt = (min, max) => {
// Use Math.floor() to round down to ensure that the result is an integer
// Use Math.random() to generate a random decimal between 0 and 1
// Then multiply it by (max - min + 1) to get a random decimal between 0 and (max - min)
// Finally add min to move the result into the specified interval
return Math.floor(Math.random() * (max - min + 1)) + min;
};
Random number (adjacent duplicate removal)
GetRandomIntWithExclusion
Randomly generate an integer value in a specified interval, and allow to limit duplicate values to avoid consecutive random number duplication
/**
* Randomly generate an integer value in a specified interval, and allow to limit duplicate values to avoid consecutive random number duplication
* @param {Number} min minimum value
* @param {Number} max maximum value
* @param {Number|undefined} excludeValue limit duplicate value
* @returns {Number}
*/
export const getRandomIntWithExclusion = (min, max, excludeValue) => {
let randomValue;
do {
randomValue = Math.floor(Math.random() * (max - min + 1)) + min;
// Combined with the use of getRandomInt
// randomValue = getRandomInt(min, max)
} while (excludeValue !== undefined && randomValue === excludeValue);
return randomValue;
};
4️⃣ Interview hand tearing function
replace string
ReplaceString
Replace the specified string
/**
* Replace the specified string
* @param {String} sourceStr source modification content
* @param {String} checkStr content to be checked for matching
* @param {String} replaceStr planned replacement content
* @returns {String} replacement result
*/
function replaceString(sourceStr, checkStr, replaceStr = "") {
if (!sourceStr) return console.error("sourceStr Required field");
if (!checkStr) return console.error("checkStr Required field");
const reg = new RegExp(checkStr);
return sourceStr.replace(reg, replaceStr);
},
Thousands separator
Thousands separator
function thousandSeparator(number) {
let result = [];
let rest = String(number);
while (rest.length) {
result.unshift(rest.slice(-3));
rest = rest.slice(0, -3);
}
const tempRes = result.join(",");
return tempRes
}
console.log('thousandSeparator:', thousandSeparator(12378900)) // 12,378,900
checkIfInstanceOf
Check if it is an object instance of a class
const checkIfInstanceOf = (obj, classFunction) => {
if (classFunction === null) return false;
while (obj !== null) {
if (obj.__proto__ === classFunction.prototype) {
return true
};
obj = obj.__proto__;
}
return false;
}
class Animal {};
class Dog extends Animal {};
console.log('checkIfInstanceOf', checkIfInstanceOf(new Date(), Date)) // true
console.log('checkIfInstanceOf', checkIfInstanceOf(new Dog(), Animal)) // true
console.log('checkIfInstanceOf', checkIfInstanceOf(Date, Date)) // false
console.log('checkIfInstanceOf', checkIfInstanceOf(5, Number)) // true
console.log('checkIfInstanceOf', checkIfInstanceOf([], Array)) // true
Shallow Clone
ShallowClone
Shallow Clone
/**
* Shallowly copy an object or array
* @param {any} value - the value to be shallowly copied
* @returns {any} - the value after shallow copy
*/
function shallowClone(value) {
if (value === null || typeof value !== "object") {
return value;
}
const type = Object.prototype.toString.call(value);
if (type === "[object Array]") {
return [...value];
} else if (type === "[object Object]") {
return { ...value };
} else {
return value; // For non-ordinary object types such as Date, RegExp, Map, Set, etc., the original value is returned directly
}
}
Deep copy
DeepClone
Deep copy
/**
* Deep copy object or array
* @param {any} obj - value to be deep copied
*/
const deepClone = obj => {
if (obj === null) return null;
let clone = Object.assign({}, obj);
Object.keys(clone).forEach(
key =>
(clone[key] =
typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
);
if (Array.isArray(obj)) {
clone.length = obj.length;
return Array.from(clone);
}
return clone;
};
const a = { foo: 'bar', obj: { a: 1, b: 2 } };
const b = deepClone(a); // a !== b, a.obj !== b.obj
Array intersect
intersect
// I work remotely in a company in Seattle. Because of the mid-month algorithm assessment, half of my month’s performance bonus was lost. . .
const intersect = function (nums1, nums2) {
let result = []
let longArr = nums1.length > nums2.length ? nums1 : nums2;
let shortArr = nums1.length > nums2.length ? nums2 : nums1;
for (let i = 0; i < shortArr.length; i++) {
let longIndex = longArr.indexOf(shortArr[i])
if (longIndex != -1) {
result.push(longArr.splice(longIndex, 1)[0])
}
}
return result
};
intersect([1,2,1,2], [2,2,2]) // [2, 2, 2]
intersect([4,9,5], [9,4,9,8,4]) // [4, 9]
intersect([3,1,2], [2,2]) // [2]
Array sort
sortArray
/**
* @param {number[]} nums
* @return {number[]}
*/
const sortArray = function (nums) {
const { length } = nums;
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
[nums[j], nums[j + 1]] = [nums[j + 1], nums[j]];
}
}
}
return nums;
};
sortArray([1, 3, 9, 5, 2, 4, 6])
curry
curry
/*
In this case, the curry function accepts a function fn as a parameter and returns a new function curried.
When the curried function is called, it checks whether the number of parameters passed in is greater than or equal to the number of parameters (arity) of the original function fn.
If so, it calls the original function directly; otherwise, it returns a new function that accepts the remaining parameters (rest) and merges the previously passed parameters (args) with the remaining parameters before calling the curried function. In this way, function currying is achieved.
*/
const curry = (fn) => {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function (...rest) {
return curried.apply(this, args.concat(rest));
};
}
};
}
const getURL = (protocol, domain, path) => {
return protocol + "://" + domain + "/" + path;
}
const myurl = getURL('http', 'mysite', 'home.html');
const myurl2 = getURL('http', 'mysite', 'about.html');
console.log('myurl', myurl);
console.log('myurl2', myurl2);
const curry = (fn) => {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function (...rest) {
return curried.apply(this, args.concat(rest));
};
}
};
}
const getURL = (protocol, domain, path) => {
return protocol + "://" + domain + "/" + path;
}
const myurl = getURL('http', 'mysite', 'home.html');
const myurl2 = getURL('http', 'mysite', 'about.html');
console.log('myurl', myurl);
console.log('myurl2', myurl2);
// Reduce repeated passing of unchanged parameters
const superGetURL = curry(getURL)('https', 'mysite');
const myurl3 = superGetURL('detail.html')
console.log('myurl3', myurl3);