bytedance¶
- Great Frontend – Bytedance Guide
- Great Frontend – JavaScript Playbook
- BigFrontend – Company
- Frontend Interview Handbook – Bytedance/TikTok Questions
- BigFrontend – Company 1
- Great Frontend – TikTok Guide
- Great Frontend – User Interface
Debounce¶
每次触发事件时,重置定时器,推迟函数执行,直到事件停止触发超过 wait 时间。
export default function debounce(func, wait = 0) {
let timeoutID = null;
return function (...args) {
// Keep a reference to `this` so that
// func.apply() can access it.
const context = this;
clearTimeout(timeoutID);
timeoutID = setTimeout(function () {
timeoutID = null; // Not strictly necessary but good to do this.
func.apply(context, args);
}, wait);
};
}
Throttle¶
在 wait 时间内,函数最多执行一次;如果事件持续触发,函数会在每个 wait 时间窗口内执行一次(通常是窗口开始时)。
/**
* @callback func
* @param {number} wait
* @return {Function}
*/
export default function throttle(func, wait = 0) {
let shouldThrottle = false;
return function (...args) {
if (shouldThrottle) {
return;
}
shouldThrottle = true;
setTimeout(function () {
shouldThrottle = false;
}, wait);
func.apply(this, args);
};
}
map¶
/**
* @template T, U
* @param { (value: T, index: number, array: Array<T>) => U } callbackFn
* @param {any} [thisArg]
* @return {Array<U>}
*/
Array.prototype.myMap = function (callbackFn, thisArg) {
const len = this.length;
const array = new Array(len);
for (let k = 0; k < len; k++) {
// Ignore index if value is not defined for index (e.g. in sparse arrays).
if (Object.hasOwn(this, k)) {
array[k] = callbackFn.call(thisArg, this[k], k, this);
}
}
return array;
};
filter¶
/**
* @template T
* @param { (value: T, index: number, array: Array<T>) => boolean } callbackFn
* @param {any} [thisArg]
* @return {Array<T>}
*/
Array.prototype.myFilter = function (callbackFn, thisArg) {
const len = this.length;
const results = [];
for (let k = 0; k < len; k++) {
const kValue = this[k];
if (
// Ignore index if value is not defined for index (e.g. in sparse arrays).
Object.hasOwn(this, k) &&
callbackFn.call(thisArg, kValue, k, this)
) {
results.push(kValue);
}
}
return results;
};
Reduce¶
/**
* @template T, U
* @param {(previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U} callbackFn
* @param {U} [initialValue]
* @return {Array<U>}
*/
Array.prototype.myReduce = function (callbackFn, initialValue) {
const noInitialValue = initialValue === undefined;
const len = this.length;
if (noInitialValue && len === 0) {
throw new TypeError("Reduce of empty array with no initial value");
}
let acc = noInitialValue ? this[0] : initialValue;
let startingIndex = noInitialValue ? 1 : 0;
for (let k = startingIndex; k < len; k++) {
if (Object.hasOwn(this, k)) {
acc = callbackFn(acc, this[k], k, this);
}
}
return acc;
};
deep clone¶
/**
* @template T
* @param {T} value
* @return {T}
*/
export default function deepClone(value) {
if (typeof value !== "object" || value === null) {
return value;
}
if (Array.isArray(value)) {
return value.map((item) => deepClone(item));
}
return Object.fromEntries(
Object.entries(value).map(([key, value]) => [key, deepClone(value)])
);
}
bind¶
/**
* @param {any} thisArg
* @param {...*} argArray
* @return {Function}
*/
Function.prototype.myBind = function (thisArg, ...argArray) {
const originalMethod = this;
return function (...args) {
return originalMethod.apply(thisArg, [...argArray, ...args]);
};
};
Flatten¶
type ArrayValue = any | Array<ArrayValue>;
export default function flatten(value: Array<ArrayValue>): Array<any> {
const res = [];
const copy = value.slice();
while (copy.length) {
const item = copy.shift();
if (Array.isArray(item)) {
copy.unshift(...item);
} else {
res.push(item);
}
}
return res;
}
Promise.all¶
/**
* @param {Array} iterable
* @return {Promise<Array>}
*/
export default function promiseAll(iterable) {
return new Promise((resolve, reject) => {
const results = new Array(iterable.length);
let unresolved = iterable.length;
if (unresolved === 0) {
resolve(results);
return;
}
iterable.forEach(async (item, index) => {
try {
const value = await item;
results[index] = value;
unresolved -= 1;
if (unresolved === 0) {
resolve(results);
}
} catch (err) {
reject(err);
}
});
});
}
Promise.race¶
/**
* @param {Array} iterable
* @return {Promise}
*/
export default function promiseRace(iterable) {
return new Promise((resolve, reject) => {
if (iterable.length === 0) {
return;
}
iterable.forEach(async (item) => {
try {
const result = await item;
resolve(result);
} catch (err) {
reject(err);
}
});
});
}