编程
防抖+节流
function debounce(fn, wait, immediate) {
let timer = null
return function() {
let args = arguments
let context = this
if (immediate && !timer) {
fn.apply(context, args)
}
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
function throttle(fn, wait, immediate) {
let timer = null
let callNow = immediate
return function() {
let context = this,
args = arguments
if (callNow) {
fn.apply(context, args)
callNow = false
}
if (!timer) {
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, wait)
}
}
}
手写call、apply和bind
Function.prototype.call = function(context = window) {
context.fn = this; // func.call(obj,p1,p2) this为func
const args = Array.from(arguments).slice(1); // arguments[0]为content,所以去掉
const res = context.fn(...args);
delete context.fn; // 删除自己添加的属性
return res; // 返回执行结果
}
// 跟call只有传参不一样
Function.prototype.apply = function(context = window) {
context.fn = this; // func.call(obj,p1,p2) this为func
const res = arguments.length > 0 ? context.fn(arguments[0]) : context.fn() ;
delete context.fn; // 删除自己添加的属性
return res; // 返回执行结果
}
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fbound = function () {
self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
}
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
return fbound;
}
柯里华
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = Array.prototype.slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var _adder = function() {
_args.push(...arguments);
return _adder;
};
// 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
有n步台阶,一次只能上1步或2步,共有多少种走法
// 普通版
function f(n) {
if (n <= 2) return n;
return f(n-1) + f(n-2);
}
// 优化版
const arr = [];
function f(n) {
if (n <= 2) arr[n] = n;
if (arr[n] > 0) return arr[n];
arr[n] = f(n-1) + f(n-2);
return arr[n];
}
给一个无序数组,N个数加起来等于M
const search = (arr, count, sum) => {
// 计算某选择情况下有几个 `1`,也就是选择元素的个数
const n = num => {
let count = 0
while(num) {
num = (num - 1) & num
count++
}
console.log('count',count)
return count
}
let len = arr.length, bit = 1 << len, res = []
console.log('bit',bit)
// 遍历所有的选择情况
for(let i = 1; i < bit; i++){
// 满足选择的元素个数 === count
if(n(i) === count){
let s = 0, temp = []
// 每一种满足个数为 N 的选择情况下,继续判断是否满足 和为 M
for(let j = 0; j < len; j++){
// 建立映射,找出选择位上的元素
if((i & 1 << j) !== 0) {
s += arr[j]
temp.push(arr[j])
}
}
// 如果这种选择情况满足和为 M
if(s === sum) {
res.push(temp)
}
}
}
return res
}
console.log(search([1,2,3,4,5],3,7))
完整深拷贝
function deepClone(o) {
// 判断如果不是引用类型,直接返回数据即可
if (typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' || typeof o === 'undefined') {
return o
} else if (Array.isArray(o)) { // 如果是数组,则定义一个新数组,完成复制后返回
// 注意,这里判断数组不能用typeof,因为typeof Array 返回的是object
var _arr = []
o.forEach(item => {
if (typeof item === 'object') {
_arr.push(deepClone(item));
} else {
_arr.push(item);
}
})
return _arr
} else if (typeof o === 'object') {
var _o = {}
for (let key in o) {
if (o[key] instanceof Date) { // 日期
_o[key] = new Date(o[key].valueOf())
} else if (o[key] instanceof RegExp) { // 正则
const pattern = o[key].valueOf();
let flags = '';
flags += pattern.global ? 'g' : '';
flags += pattern.ignoreCase ? 'i' : '';
flags += pattern.multiline ? 'm' : '';
_o[key] = new RegExp(pattern.source, flags);
} else if (o[key] instanceof HTMLElement) { // dom
_o[key] = o[key].cloneNode(true);
} else if (o[key] instanceof Function) { // 方法
_o[key] = function () {
return o[key].apply(this, arguments);
}
} else {
_o[key] = deepClone(o[key]);
}
}
return _o;
}
}
手写new
function mynew(Func, ...args) {
// 1.创建一个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}
观察者模式
// 观察者
class Observer {
constructor(name, subject) {
this.name = name;
if (subject) {
subject.addOberver(this);
};
};
notify(msg) {
console.log(msg);
}
}
// 被观察者
class subject {
constructor() {
this.observerList = [];
}
addOberver(observer) {
this.observerList.push(observer);
}
removeObserver(observer) {
const index = this.observerList.findIndex(item => item.name === observer.name);
this.observerList.splice(index, 1);
}
notifyObserver(msg) {
this.observerList.forEach(item => {
item.notify(msg);
});
}
}
走迷宫
只能向右和向下走,碰到1不能走,有几种走法
var arr = [
[0, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 0, 1],
[0, 0, 0, 0, 0, 1],
[0, 0, 0, 1, 0, 1],
[0, 1, 0, 0, 0, 0],
];
function f(i, j) {
if (arr[i][j] === 1) return 0;
if (i + j === 1) {
if (arr[i][j] === 1) {
return 0;
}
return 1;
}
if (i === 0) return f(0, j - 1);
if (j === 0) return f(i - 1, 0);
return f(i - 1, j) + f(i, j - 1);
}
顺时针打印矩阵(螺旋矩阵)
const arr = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
];
var spiralOrder = function (matrix) {
if (!matrix.length || !matrix[0].length) {
return [];
}
const rows = matrix.length, columns = matrix[0].length;
const visited = new Array(rows).fill(0).map(() => new Array(columns).fill(false));
const total = rows * columns;
const order = new Array(total).fill(0);
let row = 0, column = 0;
let curDir = 1;
for (let i = 0; i < total; i++) {
order[i] = matrix[row][column];
visited[row][column] = true;
if (curDir === 2) {
if (row < rows - 1 && !visited[row + 1][column]) {
row = row + 1;
} else {
curDir = 3;
column = column - 1;
}
} else if (curDir === 1) {
if (column < columns - 1 && !visited[row][column + 1]) {
column = column + 1;
} else {
curDir = 2;
row = row + 1;
}
} else if (curDir === 4) {
if (row > 0 && !visited[row - 1][column]) {
row = row - 1;
} else {
curDir = 1;
column = column + 1;
}
} else if (curDir === 3) {
if (column > 0 && !visited[row][column - 1]) {
column = column - 1;
} else {
curDir = 4;
row = row - 1;
}
}
}
return order;
};
大数相加
function add(str1, str2) {
const arr1 = str1.split('');
const arr2 = str2.split('');
let flag = 0;
let result = '';
while (arr1.length || arr2.length || flag) {
const sum = ~~arr1.pop() + ~~arr2.pop() + flag;
result = sum % 10 + result;
flag = ~~(sum / 10);
}
return result;
}
打印二维数组,实现函数expand
输出// > 0, 6, 10, 16, 20, 1, 5, 11, 15, 21, 2, 8, 12, 18, 22, 3, 7, 13, 17, 23, 4, 14, 24, 9, 19
const arr = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
];
function demo(arr) {
let flag = 0;
const res = [];
const len = arr[0].length + arr[0].length % 2;
for (let i = 0; i < len; i += 1) {
flag = i;
for (let j = 0; j < arr.length; j += 1) {
if (arr[j][flag] !== undefined) {
res.push(arr[j][flag]);
}
if (i % 2 === 0) {
flag = j % 2 === 0 ? i + 1 : i;
} else {
flag = j % 2 === 0 ? i - 1 : i;
}
}
}
return res;
}
console.log(demo(arr));
快排
function quicksort(arr) {
if (arr.length <= 1) return arr;
const index = parseInt(arr.length / 2, 10);
const leftArr = [];
const rightArr = [];
for (let i = 0; i < arr.length; i += 1) {
if (i !== index) {
if (arr[i] < arr[index]) {
leftArr.push(arr[i]);
} else {
rightArr.push(arr[i]);
}
}
}
return quicksort(leftArr).concat(arr[index]).concat(quicksort(rightArr));
}
数组扁平化
1.reduce遍历数组每一项,若值为数组则递归遍历,否则concat。
function flatten(arr) {
return arr.reduce((result, item)=> {
return result.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
2.toString & split
function flatten(arr) {
return arr.toString().split(',').map(function(item) {
return Number(item);
})
}
3.join & split
function flatten(arr) {
return arr.join(',').split(',').map(function(item) {
return parseInt(item);
})
}
4.递归
function flatten(arr) {
var res = [];
arr.map(item => {
if(Array.isArray(item)) {
res = res.concat(flatten(item));
} else {
res.push(item);
}
});
return res;
}
5.扩展运算符
function flatten(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
留言