1. 函数的call() / apply() / bind()
function call (fn, obj, ...args) {
if (obj===null || obj===undefined) {
return fn(...args)
}
obj.tempFn = fn
const result = obj.tempFn(...args)
delete obj.tempFn
return result
}
Function.prototype.myCall = function () {
const args = Array.prototype.slice.call(arguments);
const t = args.shift();
if (t === null || t === undefined) {
t = window;
return fn(...args);
}
const self = this;
t.fn = self;
const res = t.fn(...args);
delete t.fn;
return res;
};
function fn(a, b) {
console.log("a", a);
console.log("b", b);
console.log("this", this);
return "hello";
}
const res = fn.myCall({ x: 10 }, 20, 30);
function apply (fn, obj, args) {
if (obj===null || obj===undefined) {
obj = window
}
obj.tempFn = fn
const result = obj.tempFn(...args)
delete obj.tempFn
return result
}
function bind (fn, obj, ...args) {
return function (...args2) {
return call(fn, obj, ...args, ...args2)
}
}
2. 函数的节流(throttle)与防抖(debounce)
function throttle (callback, delay) {
let start = 0
return function (event) {
const current = Date.now()
if (current-start>delay) {
callback.call(event.target, event)
start = current
}
}
}
function debounce (callback, delay) {
return function (event) {
if (callback.timeoutId) {
clearTimeout(callback.timeoutId)
}
callback.timeoutId = setTimeout(() => {
callback.call(event.target, event)
delete callback.timeoutId
}, delay);
}
}
3. 数组去重(unique)
function unique1 (array) {
const arr = []
array.forEach(item => {
if (arr.indexOf(item)===-1) {
arr.push(item)
}
})
return arr
}
function unique2 (array) {
const arr = []
const obj = {}
array.forEach(item => {
if (!obj.hasOwnProperty(item)) {
obj[item] = true
arr.push(item)
}
})
return arr
}
function unique3 (array) {
return [...new Set(array)]
}
4. 数组扁平化(flatten)
function flatten1 (array) {
return array.reduce((pre, item) => {
if (Array.isArray(item) && item.some((cItem => Array.isArray(cItem)))) {
return pre.concat(flatten1(item))
} else {
return pre.concat(item)
}
}, [])
}
function flatten2 (arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
var arr = [
[1, 2, 2],
[3, 4, 5, 5],
[5, 6, 7, 8, 9],
[11, 12, [12, 12, [13]]],
10,
];
Array.prototype.flat = function () {
const result = this.map((item) => {
if (Array.isArray(item)) {
return item.flat();
}
return [item];
});
return [].concat(...result);
};
Array.prototype.unique = function () {
return [...new Set(this)];
};
const sortFn = (a, b) => {
return a - b;
};
const a = arr.flat().unique().sort(sortFn);
console.log(a);
5. 深拷贝
const obj = {
a: {
m: 1
},
b: [3, 4],
fn: function (){},
d: 'abc'
}
obj.a.c = obj.b
obj.b[2] = obj.a
export function deepClone1(target) {
return JSON.parse(JSON.stringify(target))
}
function getType(data) {
return Object.prototype.toString.call(data).slice(8, -1)
}
function deepClone2(target) {
const type = getType(target)
if (type==='Object' || type==='Array') {
const cloneTarget = type === 'Array' ? [] : {}
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone2(target[key])
}
}
return cloneTarget
} else {
return target
}
}
function deepClone3(target, map = new Map()) {
const type = getType(target)
if (type==='Object' || type==='Array') {
let cloneTarget = map.get(target)
if (cloneTarget) {
return cloneTarget
}
cloneTarget = type==='Array' ? [] : {}
map.set(target, cloneTarget)
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone3(target[key], map)
}
}
return cloneTarget
} else {
return target
}
}
function deepClone4(target, map = new Map()) {
const type = getType(target)
if (type==='Object' || type==='Array') {
let cloneTarget = map.get(target)
if (cloneTarget) {
return cloneTarget
}
if (type==='Array') {
cloneTarget = []
map.set(target, cloneTarget)
target.forEach((item, index) => {
cloneTarget[index] = deepClone4(item, map)
})
} else {
cloneTarget = {}
map.set(target, cloneTarget)
Object.keys(target).forEach(key => {
cloneTarget[key] = deepClone4(target[key], map)
})
}
return cloneTarget
} else {
return target
}
}
6. 自定义new和instanceof工具函数
function newInstance(Fn, ...args) {
const obj = {}
const result = Fn.apply(obj, args)
if (result instanceof Object) {
return result
}
obj.__proto__ = Fn.prototype
return obj
}
function Fn () {
this.name = 'tom'
return []
}
new Fn()
function myInstanceOf(obj, Type) {
let protoObj = obj.__proto__
while(protoObj) {
if (protoObj === Type.prototype) {
return true
}
protoObj = protoObj.__proto__
}
return false
}
7. 字符串处理
function reverseString(str) {
return Array.from(str).reverse().join('')
}
function palindrome(str) {
return str === reverseString(str)
}
function truncate(str, num) {
return str.length > num ? str.slice(0, num) + '...' : str
}
abcdd...
8. 简单排序: 冒泡 / 选择 / 插入
function bubbleSort (array) {
var length = array.length;
for (var i = length - 1; i >= 0; i--) {
for (var j = 0; j < i; j++) {
if (array[j] > array[j + 1]) {
[array[j + 1], array[j]] = [array[j], array[j + 1]];
}
}
}
return arr;
}
function selectSort (array) {
var length = array.length
for (var i = 0; i < length - 1; i++) {
var min = i
for (var j = min + 1; j < length; j++) {
if (array[min] > array[j]) {
min = j
}
}
if (min !== i) {
[array[min], array[i]] = [array[i], array[min]];
}
}
return arr;
}
function insertSort (array) {
var length = array.length
for (var i = 1; i < length; i++) {
var j = i
var temp = array[i]
while (j > 0 && array[j - 1] > temp) {
array[j] = array[j - 1]
j--
}
array[j] = temp
}
return array
}
products.sort((item1, item2) => {
return item1.price - item2.price
})
9、继承
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.eat = function () {
console.log("螺蛳粉");
}
function Student(classRoom, score, name, age, sex) {
this.classRoom = classRoom;
this.score = score;
Person.call(this, name, age, sex)
}
Student.prototype = new Person;
Student.prototype.constructor = Student;
Student.prototype.study = function () {
console.log("面向对象");
}
var s1 = new Student(405, 100, "张三", 18, "男");
console.log(s1);
console.log(s1.eat);
console.log(s1.study);
console.log(s1.constructor);
10、js调度器(并发编程)
class Scheduler {
constructor(max) {
this.max = max;
this.count = 0;
this.queue = [];
}
async add(fn) {
if (this.count >= this.max) {
await new Promise((resolve) => this.queue.push(resolve));
}
this.count++;
const res = await fn();
let a = 0
a++
console.log(res, a)
this.count--;
this.queue.length && this.queue.shift()();
return res;
}
}
const sleep = (time) =>
new Promise((resolve) => {
setTimeout(resolve, time);
});
const scheduler = new Scheduler(2);
const addTask = (time, val) => {
scheduler.add(() => {
return sleep(time).then(() => {
console.log(val);
});
});
};
addTask(1000, "1");
addTask(200, "5");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
11、手写async和await
function* gen() {
yield 1
yield 2
yield 3
return 4
}
const g = gen()
console.log(g.next())
console.log(g.next())
console.log(g.next())
console.log(g.next())
async function sixuetang() {
const data1 = await getData(1);
const data2 = await getData(data1);
return `success: ${data2}`;
}
function* sixuetang() {
const data1 = yield getData(1);
const data2 = yield getData(data1);
return `success: ${data2}`;
}
const g = sixuetang();
const next1 = g.next();
next1.value.then((data1) => {
console.log("data1: ", data1);
const next2 = g.next(data1);
next2.value.then((data2) => {
console.log("data2: ", data2);
console.log(g.next(data2));
});
});
function generatorToAsync(generatorFun) {
return function () {
return new Promise((resolve, reject) => {
const g = generatorFun();
const next1 = g.next();
next1.value.then((data1) => {
const next2 = g.next(data1);
next2.value.then((data2) => {
resolve(g.next(data2).value);
});
});
});
};
}
function generatorToAsync(generatorFun) {
return function () {
const gen = generatorFun.apply(this.arguments);
return new Promise((resolve, reject) => {
function step(key, arg) {
let res;
try {
res = gen[key](arg);
} catch (error) {
return reject(error);
}
const { value, done } = res;
if (done) {
return resolve(value);
} else {
return Promise.resolve(value).then(
(val) => step("next", val),
(err) => step("throw", err)
);
}
}
step("next");
});
};
}
const asyncFn = generatorToAsync(sixuetang);
asyncFn().then((res) => console.log(res));
12、函数柯里化
精简版柯里化
const curring = (protocol) => {
return function (hostname, pathname) {
return `${protocol}${hostname}${pathname}`;
};
};
const https = curring("https://");
const uri = https('www.baidu.com', '/picture')
console.log(uri)
const list = [
{mid:'123', per:'123'},
{mid: 'qqq', per: '2222'}
]
const curring = key => item => item[key]
const mid = curring('mid')
const per = curring('per')
console.log(list.map(mid))
console.log(list.map(per))
柯里化 (隐式调用)
function num(...args) {
console.log(...args)
return args
}
num(1,2,3)
function add(a) {
let args = Array.prototype.slice.call(arguments);
let inner = function () {
args.push(...arguments)
let sum = args.reduce(function (perv, cur) {
return prev + cur
})
return sum
}
return inner
}
console.log(add(1)(2))
function add(a) {
let args = Array.prototype.slice.call(arguments);
let inner = function () {
args.push(...arguments)
return inner
}
inner.toString = function () {
return args.reduce(function (prev, cur) {
return prev + cur
})
}
return inner
}
柯里化
const curring = (func) => {
const args = [];
return function result(...rest) {
if(rest.length === 0) {
return func(...args)
} else {
args.push(...rest);
return result;
}
}
}
定制柯里化
const sumFn = (...args) => {
return args.reduce((a, b) => {
return a + b;
});
};
const sortFn = (...args) => {
return args.sort((a, b) => {
a - b;
});
};
const curring = (func) => {
const args = [];
return function result(...rest) {
if (rest.length === 0) {
return func(...args);
} else {
args.push(...rest);
return result;
}
};
};
console.log(curring(sumFn)(1, 2, 3, 4, 5)(6)() )
console.log(curring(sortFn)(1)(3)(2)(5, 4)() )
参考