1,手写题
参考文档:
1,函数柯里化
柯里化是高阶函数的一种特殊用法。接收函数作为参数的函数,都可以叫做高阶函数。 参考文档:
- 详解JS函数柯里化
函数柯里化的目的是为了多参函数实现递归降解。其实现的核心是: - 如何缓存每一次传入的参数。
- 传入的参数和目标函数的入参比较。 函数柯里化的好处:
- 参数复用
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt)
}
check(/\d+/g, 'test') //false
check(/[a-z]+/g, 'test') //true
// Currying后
function curryingCheck(reg) {
return function(txt) {
return reg.test(txt)
}
}
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
- 提前确认
var on = function(element, event, handler) {
if (document.addEventListener) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
} else {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
}
}
var on = (function() {
if (document.addEventListener) {
return function(element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
};
} else {
return function(element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
};
}
})();
//换一种写法可能比较好理解一点,上面就是把isSupport这个参数给先确定下来了
var on = function(isSupport, element, event, handler) {
isSupport = isSupport || document.addEventListener;
if (isSupport) {
return element.addEventListener(event, handler, false);
} else {
return element.attachEvent('on' + event, handler);
}
}
- 延迟执行
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}
1,柯里化通用式
const curry = (fn) => {
let params = [];
const next = (...args)=>{
params = [...params, ...args];
if(params.length < fn.length){
return next;
}else{
return fn.apply(fn, params);
}
}
return next;
}
const sum = (a, b, c, d) => {
return a + b + c + d;
}
const fn = curry(sum);
const res = fn(1)(2)(3);
console.log(res);
2,手写数组方法
1,map
Array.prototype.map = function (fn) {
const result = [];
for (let index = 0; index < this.length; index++) {
if (!this.hasOwnProperty(index)) {
continue;
}
//递归调用
result.push(fn(this[index], index, this))
}
return result;
}
const arr = [1, 2, 3];
const mapArr = arr.map(item => item * 2);
console.log(mapArr);
2,filter
Array.prototype.filter = function (fn) {
const result = [];
for (let index = 0; index < this.length; index++) {
if (!this.hasOwnProperty(index)) {
continue;
}
fn(this[index], index, this) && result.push(this[index]);
}
return result;
}
const arr = [1, 2, 3];
const filterArr = arr.filter(item => item > 2);
console.log(filterArr);
3,reduce
Array.prototype.reduce = function(fn, initValue) {
let result = initValue ? initValue : this[0];
for(let i = initValue ? 1 : 0; i < this.length; i++){
if(!this.hasOwnProperty(i)) continue;
result = fn(result, this[i], i, this);
}
return result;
}
const arr1 = [1, 2, 3];
const reduceArr1 = arr1.reduce((a, b) => a * b, 2);
console.log(reduceArr1);
4,every
Array.prototype.every = function(fn) {
let bool = true;
for (let index = 0; index < this.length; index++) {
if(!this.hasOwnProperty(index)){
continue;
}
if(!fn(this[index], index, this)){
bool = false;
}
return bool;
}
}
const arr1 = [1, 2, 3, 5];
const reduceArr1 = arr1.every(item => item > 3);
console.log(reduceArr1);
5,some
Array.prototype.some = function(fn) {
let bool = false;
for (let index = 0; index < this.length; index++) {
if(!this.hasOwnProperty(index)){
continue;
}
if(fn(this[index], index, this)){
bool = true;
break;
}
return bool;
}
}
const arr1 = [1, 2, 3, 5];
const reduceArr1 = arr1.some(item => item > 3);
console.log(reduceArr1);
6,find
Array.prototype.find = function(fn) {
let findIndex = -1;
for (let index = 0; index < this.length; index++) {
if(!this.hasOwnProperty(index)){
continue;
}
if(fn(this[index], index, this)){
findIndex = index;
break;
}
}
return this[findIndex];
}
const arr1 = [1, 2, 3, 5];
const reduceArr1 = arr1.find(item => item > 3);
console.log(reduceArr1);
7, 数组扁平化
- 使用es6的flat方法,默认扁平一层,传入参数可以指定扁平几层,不改变原数组。
- 使用reduce方法
function reduceFlat(arr) {
if(!Array.isArray(arr)) return;
return arr.reduce((a, b) => a.concat(!Array.isArray(b) ? b : reduceFlat(b)), []);
}
arr1 = [1, [1, [1, 2]]];
let arr2 = reduceFlat(arr1);
console.log(arr2);
- 模拟栈实现数组拉平
function stackFlat(arr) {
if(!Array.isArray(arr))
return;
const stackArr = [...arr];
const flatArr = [];
while(stackArr.length){
let value = stackArr.shift();
Array.isArray(value) ? stackArr.push(...value) : flatArr.push(value);
}
return flatArr;
}
let arr1 = [1, [2, [3]], 4];
let arr2 = stackFlat(arr1);
console.log(arr2);
3,图片懒加载
function lazyLoad(imgs) {
let count = 0;
const deleteImgs = [];
const handle = ()=> {
imgs.forEach((img, index) => {
const react = img.getBoundingClientRect();
if(react.top < window.innerHeight){
img.src = dataset.src;
count++;
deleteImgs.push(index);
if(count === img.length){
document.removeEventListener('scroll', lazyLoad);
}
}
});
imgs = imgs.filter((_, index) => {
!deleteImgs.includes(index);
})
}
return handle();
}
4,图片预加载
如果图片过大,可以预先将图片加载到缓存中,优化用户体验。
5,节流
1,实现1
const throttle = function (fn, waiting = 1000, options) {
let preTime = new Date(0).getTime(),
options = options || {
firstTime: true,
endTime: false
},
timer;
let _throttle = function (...params) {
let newTime = new Date().getTime();
if (!options.firstTime) {
if(timer) return;
timer = setTimeout(() => {
fn.apply(fn, args);
timer = null;
}, waiting);
}else if(newTime - preTime > waiting){
fn.apply(fn, args);
preTime = newTime;
}else if(options.endTime){
timer = setTimeout(() => {
fn.apply(fn, args);
timer = null
}, waiting);
}
};
_throttle.cancel = () => {
preTime = 0;
clearTimeout(timer);
timer = null;
}
return _throttle;
}
2,实现2
function throttle (f, wait) {
let timer
return (...args) => {
if (timer) { return }
timer = setTimeout(() => {
f(...args)
timer = null
}, wait)
}
}
需要节流的场景
- scroll事件,每隔一秒计算一次位置信息。
- input输入框实时搜索并展示下拉列表,
6,防抖
function debounce (f, wait) {
let timer
return (...args) => {
clearTimeout(timer)
timer = setTimeout(() => {
f(...args)
}, wait)
}
}
需要防抖的场景
- 登录,发短信等按钮用户点击过多,为了避免发送过多请求
- 文本编辑器实时保存,当无任何操作后一段时间自动保存
7,实现instanceof方法
function myInstanceOf(left, right) {
if (typeof left !== 'object' || left == null) {
return false;
}
let pro = Object.getPrototypeOf(left);
while(true) {
if (pro === null) {
return false;
}
if (pro === right.prototype) {
return true;
}
pro = Object.getPrototypeOf(pro);
}
}
8,斐波那契数列
1,递归
function f(n) {
if (n === 1 || n === 2) {
return 1;
} else {
return f(n-1) + f(n-2);
}
}
时间复杂度:O(2^n)
空间复杂度:O(n)
实现比较简洁,但是空间复杂度太大,容易导致栈溢出。
2,尾调用
function f(n, ac1=1, ac2=1) {
if (n<=2) {
return ac2;
}
return f(n-1, ac2, ac1+ac2);
}