最常见前端手写代码及方法实现

1. 手写 new 操作符

function myNew(fn, ...args) {
    let obj = {};
    obj.__proto__ = fn.prototype;
    let res = fn.call(obj, ...args);
    if (res && (typeof res === "object" || typeof res === "function")) {
        return res;
    }
    return obj;
}
// 测试代码
function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.say = function() {
  console.log(this.age);
};
let p1 = myNew(Person, "lihua", 18);
p1.say();

2. 实现一个instanceof

function Instanceof(left, right) {
    let leftVal = left.__proto__;
    let rightVal = right.prototype;
    while(leftVal !== null) {
        if (leftVal === rightVal){
            return true;
        }
        leftVal = leftVal.__proto__;          // 继续查找原型链
    }
    return false;
}
// 测试代码
console.log(Instanceof([], Array));
console.log(Instanceof([], Object));

3. 实现深拷贝

function deepClone(objData) {
    let result = Array.isArray(objData) ? [] : {};
    for (let i in objData) {
        if (objData.hasOwnProperty(i)) {
            result[i] = typeof objData[i] === "object" ? deepClone(objData[i]) : objData[i];
        }
    }
    return result;
}
// 测试代码
var obj1 = {
    a: 1,
    b: {
        a: 2,
        c: {
          name: 'jack',
          age: 12
        }
    }
};
var obj2 = deepClone(obj1);
console.log(obj1);

4. 数组方式实现之 —— reduce 实现

Array.prototype.myReduce = function (fn, initvalue) {
    if(Object.prototype.toString.call(fn) !== "[object Function]" ) {
        throw new Error('第一个参数必须是函数');
    }
    // 第二个参数是可选的
    let pre = null;
    if (arguments.length > 1) {
        pre = initvalue
    } else {
        pre = this[0];
    }
    // 迭代 fn 方法:
    for (let i = 0; i < this.length; i++) {
        pre = fn(pre, this[i], i, this);
    }
    return pre;
}
// 测试代码
let arr = [1, 2, 3];
let result = arr.myReduce((pre, cur) => {
    return pre + cur;
}, 0)
console.log(result);

5. 数组方式实现之 —— filter 实现

Array.prototype.myFilter = function(fn) {
    if(Object.prototype.toString.call(fn) !== "[object Function]") {
        throw new Error('第一个参数必须是函数');
    }
    let list = [];
    for(let i =0; i < this.length; i++) {
        let result = fn(this[i], i, this);
        if (result) {
            list.push(this[i]);
        }
    }
    return list;
}
// 测试代码
console.log([2, 4, 6].myFilter(item => item < 3));

6. 数组方式实现之 —— map 实现

Array.prototype.myMap = function(fn) {
    if(Object.prototype.toString.call(fn) !== "[object Function]") {
        throw new Error('第一个参数必须是函数');
    }
    let list = [];
    for(let i = 0; i< this.length; i++) {
        let result = fn(this[i], i, this);
        list.push(result);
    }
    return list;
}
// 测试代码
console.log([1, 2, 3, 5].myMap(item => item * 10));

7. 数组方式实现之 —— every 实现

Array.prototype.myEvery = function(fn) {
    if(Object.prototype.toString.call(fn) !== "[object Function]") {
        throw new Error('第一个参数必须是函数');
    }
    for(let i = 0; i< this.length; i++) {
        if(!fn(this[i], i, this)) {
            return false;
        }
    }
    return true;
}
// 测试代码
console.log([1, 2, 3, 5].myEvery(item => item > 1));

8. 数组扁平化处理 flat 实现(三种方式)

// 1. reduce方法实现:
function flat01(arr) {
    if(!arr.length) return;
    return arr.reduce((pre, cur) => {
        return Array.isArray(cur) ? [...pre, ...flat01(cur)] : [...pre, cur]
    }, [])
}
// 2. 递归实现:
function flat02(arr) {
    if(!arr.length) return;
    let result = [];
    for(let i of arr) {
        if(!Array.isArray(i)) {
            result.push(i);
        } else {
            result = [...result, ...flat02(i)];
        }
    };
    return result;
}
// 3. 常规数组实现
function flat03(arr) {
    if(!arr.length) return;
    while(arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr);
    };
    return arr;
}

// 测试代码
console.log(flat01([1, 2, [1, [2, 3, [4, 5, [6]]]]]));
console.log(flat02([1, 2, [1, [2, 3, [4, 5, [6]]]]]));
console.log(flat03([1, 2, [1, [2, 3, [4, 5, [6]]]]]));

9. 函数柯里化的应用 —— curry

// 函数柯里化 —— 将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术
function curry(fn) {
    if(fn.length <= 1) return fn;  // 确定传入的函数的参数的个数
    const result = (...args) => {
        if(fn.length === args.length) {
            return fn(...args);
        } else {
            return (...argsNew) => {   // 递归取参数,然后在合并参数,一直到取到的参数数量和 fn 参数数量相等
                return result(...args, ...argsNew);
            }

        }
    }
    return result;
}
// 测试代码
let add = (a, b, c, d) => a + b+ c + d;
const curriedAdd = curry(add);
console.log(add(1, 2, 3, 5));
console.log(curriedAdd(1)(2)(3)(5));

10. 实现call方法

Function.prototype.myCall = function (context, ...args) {
    if (!context || context === null) {
        context = window;
    }
    let sym = Symbol();
    context[sym] = this; // 此时调用myCall方法的是context的sym属性(方法)
    const result = context[sym](...args); // 执行函数并返回结果 相当于把自身作为传入的context的方法进行调用了
    delete context[sym];   //删除该方法,不然会对传入对象造成污染(添加该方法)
    return result;
}
// 测试代码
function greet() {
    var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
    console.log(reply);
}
var obj = {
    animal: 'cats',
    sleepDuration: '12 and 16 hours'
};
greet.myCall(obj);

11. 实现apply方法

Function.prototype.myApply = function (context, args = []) {
    if (!context || context === null) {
        context = window;
    }
    // 创造唯一的key值  作为我们构造的context内部方法名
    let sym = Symbol();
    context[sym] = this;
    // 执行函数并返回结果
    let result = context[sym](...args);
    delete context[sym];
    return result;
};
// 测试代码
function greet() {
    var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
    console.log(reply);
}
var obj = {
    animal: 'cats',
    sleepDuration: '12 and 16 hours'
};
greet.myApply(obj);

12. 实现bind方法

Function.prototype.myBind = function(context, ...args) {
    const self = this;
    args = args ? args : [];
    return function() {
        let newArgs = [...arguments];
        return self.apply(context, args.concat(newArgs));
    }
}
// 测试代码
function greet() {
    var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
    console.log(reply);
}
var obj = {
    animal: 'cats',
    sleepDuration: '12 and 16 hours'
};
greet.myBind(obj)();

13. Object.create()的实现

// Object.create()会将参数对象作为一个新创建的空对象的原型, 并返回这个空对象
// 1. 简单版
function myCreate(obj) {
    function CreateObj() {};
    CreateObj.prototype = obj;
    return new CreateObj();
}
// 2. 官方版
if (typeof Object.create !== "function") {
    Object.create = function (proto, propertiesObject) {
        if (typeof proto !== 'object' && typeof proto !== 'function') {
            throw new TypeError('Object prototype may only be an Object: ' + proto);
        } else if (proto === null) {
            throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
        }

        if (typeof propertiesObject !== 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");

        function F() {}
        F.prototype = proto;

        return new F();
    };
}
// 测试代码
let a = {
    name: 'jack',
    age: 12
};
let b = myCreate(a);
console.log(b);    // {}
console.log(b.name)   // "jack"

14. 防抖、节流函数的实现

// 防抖函数 —— 连续触发在最后一次执行方法,场景:输入框匹配
function debounce(fn, time) {
    let timer = null;
    return function () {
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
        timer = setTimeout(() => {
            fn();
        }, time);
    }
}
// 节流函数 —— 在一定时间内只触发一次,场景:长列表滚动节流
function throttle(fn, time) {
    let isRuning = false;
    return function() {
        if(isRuning) {
            return;
        }
        isRuning = true;
        setTimeout(() => {
            fn();
            isRuning = false;
        }, time)
    }
}
// 测试代码
let fn = () => {
    console.log('fffffff')
}
setInterval(debounce(fn, 500), 1000) // 第一次在1500ms后触发,之后每1000ms触发一次
setInterval(throttle(fn, 1000), 1500) // 开启定时器任务测试

15. 手写一个简单的 ajax 请求

function ajax(options) {
    let url = options.url
    const method = options.method.toLocaleLowerCase() || 'get';
    const async = options.async != false; // 默认是异步的: true
    const data = options.data; // 携带参数
    const xhr = new XMLHttpRequest();  // 初始化 XMLHttpRequest 实例

    if (options.timeout && options.timeout > 0) {  // 请求超时时间
        xhr.timeout = options.timeout
    }

    return new Promise((resolve, reject) => {
        xhr.ontimeout = () => reject && reject('请求超时');   // 当请求超时时,会触发 ontimeout 方法; 此时抛出错误
        xhr.onreadystatechange = () => {
            if (xhr.readyState == 4) {
                if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
                    resolve && resolve(xhr.responseText);
                } else {
                    reject && reject();
                }
            }
        }
        xhr.onerror = err => reject && reject(err);   // 捕获错误信息
        // 处理参数信息:
        let paramArr = []
        let encodeData
        if (data instanceof Object) {
            for (let key in data) {
                paramArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
            }
            encodeData = paramArr.join('&')
        }
        // get 请求的处理
        if (method === 'get') {
            // 检测 url 中是否已存在 ? 及其位置
            const index = url.indexOf('?')
            if (index === -1) url += '?'
            else if (index !== url.length - 1) url += '&'
            // 拼接 url
            url += encodeData
        }

        xhr.open(method, url, async)
        if (method === 'get') {
            xhr.send(null);
        } else {
            // post 方式需要设置请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8')
            xhr.send(encodeData)
        }
    })
}
// 使用方法:
ajax({
    url: 'your request url',
    method: 'get',
    async: true,
    timeout: 1000,
    data: {
        test: 1,
        aaa: 2
    }
}).then(
    res => console.log('请求成功: ' + res),
    err => console.log('请求失败: ' + err)
)

16. 手写一个 jsonp

const jsonp = function (url, data) {
    return new Promise((resolve, reject) => {
        // 初始化url,构造完整的 url: 
        let dataString = url.indexOf('?') === -1 ? '?' : '';
        let callbackName = `jsonpCB_${Date.now()}`;
        url += `${dataString}callback=${callbackName}`;
        if (data) {
            // 有请求参数,依次添加到url
            for (let k in data) {
                url += `${k}=${data[k]}`;
            }
        }
        // 创建 script 标签:
        let jsNode = document.createElement('script');
        jsNode.src = url;
        // 触发callback,触发后删除js标签和绑定在window上的callback
        window[callbackName] = result => {
            delete window[callbackName]
            document.body.removeChild(jsNode)
            if (result) {
                resolve(result)
            } else {
                reject('没有返回数据')
            }
        }
        // js加载异常的情况
        jsNode.addEventListener('error', () => {
            delete window[callbackName]
            document.body.removeChild(jsNode)
            reject('JavaScript资源加载失败')
        }, false)
        // 添加js节点到document上时,开始请求
        document.body.appendChild(jsNode)
    })
}
// 代码实现: 
jsonp('http://192.168.0.103:8081/jsonp', {
    a: 1,
    b: 'heiheihei'
})
.then(result => {
    console.log(result)
})
.catch(err => {
    console.error(err)
})

17. 实现一个简单的发布订阅模式(EventEmitter的实现)

class EventEmitter {
    constructor() {
        this.events = {};
    }
    // 事件监听/订阅
    on(type, callBack) {
        let callbacks = this.events[type] || [];
        callbacks.push(callBack);
        this.events[type] = callbacks;
    }
    // 取消订阅
    off(type, callBack) {
        if (!this.events[type]) return;
        this.events[type] = this.events[type].filter(item => {
            return item !== callBack;
        })
    }
    // 触发事件
    emit(type, ...rest) {
        if (this.events[type] && this.events[type].length > 0) {
            for (let fn of this.events[type]) {
                fn(...rest);
            }
        } else {
            console.log('没有取到事件')
        }
    }
    // 触发一次
     once(type, callback) {
        let fn = function (...args) {
            callback(...args);
            this.off(type, fn);  // 触发一次之后取消订阅
        };
        this.on(type, wrapFun);
    }
}
// 测试代码
const llzevent = new EventEmitter();
const handle = (...rest) => {
    console.log(rest);
};
llzevent.on("click", handle);
console.log(llzevent)
llzevent.emit('click', 1, 2, 4);

18. 实现一个通用的事件侦听器函数

const EventUtils = {
  // 添加事件(视能力分别使用dom0||dom2||IE三种方式方式来绑定事件)
  addEvent: function(element, type, handler) {
    if (element.addEventListener) {
      element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
      element.attachEvent("on" + type, handler);
    } else {
      element["on" + type] = handler;
    }
  },
  // 移除事件
  removeEvent: function(element, type, handler) {
    if (element.removeEventListener) {
      element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
      element.detachEvent("on" + type, handler);
    } else {
      element["on" + type] = null;
    }
  },
 // 获取事件目标
  getTarget: function(event) {
    return event.target || event.srcElement;
  },
  // 获取 event 对象的引用,取到事件的所有信息,确保随时能使用 event
  getEvent: function(event) {
    return event || window.event;
  },
 // 阻止事件(主要是事件冒泡,因为 IE 不支持事件捕获)
  stopPropagation: function(event) {
    if (event.stopPropagation) {
      event.stopPropagation();
    } else {
      event.cancelBubble = true;
    }
  },
  // 取消事件的默认行为
  preventDefault: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
    } else {
      event.returnValue = false;
    }
  }
};

19. 实现一个事件委托 delegate

<ul class="container">
    <li class="item">1231<span style="color: red">123131</span></li>
    <li class="item">8888</li>
    <li class="item">第三行</li>
    <li class="item"><div>第四行</div></li>
</ul>

<script>
const container = document.querySelector(".container");
delegate(container, ".item", "click", (e, item) => {
    console.log(item.textContent);
});
function delegate(container, itemSelector, event, handler) {
    container.addEventListener(event, (e) => {
    let target = e.target;
        while (!target.matches(itemSelector) && target !== container) {
            target = target.parentNode;
        }
        if (target !== container) {
            handler(e, target);
        }
    });
}
</script>

20. 实现一个 scheduler 异步调度器

// 简单版本
class Scheduler {
    constructor(limit) {
        this.limit = limit
        this.number = 0
        this.queue = []
    }
    addTask(timeout, str) {
        this.queue.push([timeout, str])
    }
    start() {
        if (this.number < this.limit&&this.queue.length) {
            var [timeout, str] = this.queue.shift()
            this.number++
            setTimeout(() => {
                console.log(str)
                this.number--
                this.start()
            }, timeout * 1000);
            this.start()
        }
    }
 }
// 带并发限制的异步调度器 Scheduler,同时要可以限制并发数量
class Scheduler {
    constructor(maxCount) {
        this.maxCount = maxCount;
        this.queue = [];
        this.runCounts = 0;
    }
    // 增加任务队列
    add(time, order) {
        const promiseCreator = () => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    console.log(order);
                    resolve();
                }, time)
            })
        }
        this.queue.push(promiseCreator);
    }
    // 任务调度开始:
    taskStart() {
        for (let i = 0; i < this.maxCount; i++) {
            this.request();
        }
    }
    request() {
        if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
            return;
        }
        this.runCounts ++;
        this.queue.shift()().then(() => {
            this.runCounts --;
            this.request();
        })
    }
}

// 测试代码
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
  scheduler.add(time, order);
};
addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
scheduler.taskStart();

21. 实现一个可以拖拽的div

<div class="box"></div>
<style>
      .box {
        position: absolute;
        width: 100px;
        background-color: red;
        height: 100px;
        left: 0;
        top: 0;
      }
</style>
<script>
      let lastPosition = [];
      const boxEle = document.querySelector(".box");
      let isDraging = false;
      boxEle.addEventListener("mousedown", (e) => {
        isDraging = true;
        lastPosition[0] = e.clientX;
        lastPosition[1] = e.clientY;
      });
      document.addEventListener("mousemove", (e) => {
        if (!isDraging) return;
        const deltaX = e.clientX - lastPosition[0];
        const deltaY = e.clientY - lastPosition[1];
        const curLeft = parseInt(boxEle.style.left || 0);
        const curTop = parseInt(boxEle.style.top || 0);
        boxEle.style.cssText = `left: ${curLeft + deltaX}px;top: ${curTop + deltaY}px`;
        lastPosition[0] = e.clientX;
        lastPosition[1] = e.clientY;
      });
      document.addEventListener("mouseup", () => {
        isDraging = false;
      });
</script>

22. 实现一个 Promise

class MyPromise {
    constructor(func) {
        this.status = 'pending'
        this.result = undefined;
        this.error = undefined;

        this.resoledCallbacks = [];
        this.rejectedCallbacks = [];

        const resolve = (result) => {
            this.status = 'resolved'
            this.result = result;
            setTimeout(() => {
                this.resoledCallbacks.forEach((callback) => callback())
            })
        };
        const reject = (error) => {
            this.status = 'rejected'
            this.error = error;
            setTimeout(() => {
                this.rejectedCallbacks.forEach((callback) => callback())
            })
        };
        try {
            func && func(resolve, reject);
        } catch (err) {
            this.status = 'rejected';
            this.error = err;
        }
    }
    
    then(resolveCallback, rejectedCallback) {
        return new MyPromise((resolve, reject) => {
            setTimeout(() => {
                if (this.status === 'resolved') {
                    this.onResolve(resolveCallback, resolve, reject);
                } else if (this.status === 'rejected') {
                    this.onReject(rejectedCallback, resolve, reject);
                } else {
                    this.resoledCallbacks.push(() => this.onResolve(resolveCallback, resolve, reject));
                    this.rejectedCallbacks.push(() => this.onReject(rejectedCallback, resolve, reject));
                }
            })
        })
    }

    catch(callback) {
        return new MyPromise((resolve, reject) => {
            setTimeout(() => {
                if (this.status === 'resolved') {
                    resolve(this.result);
                } else if (this.status === 'rejected') {
                    this.onReject(callback, resolve, reject);
                } else {
                    this.resoledCallbacks.push(() => resolve(this.result));
                    this.rejectedCallbacks.push(() => this.onReject(callback, resolve, reject));
                }
            })
        })
    }
    
    finally(callback) {
        return new MyPromise((resolve, reject) => {
            if (this.status === 'pending') {
                this.resoledCallbacks.push(() => this.onFinally(callback, resolve, reject));
                this.rejectedCallbacks.push(() => this.onFinally(callback, resolve, reject));
            } else {
                this.onFinally(callback, resolve, reject);
            }
        })
    }

    onResolve(callback, resolve, reject) {
        if (!callback) return resolve();
        try {
            const result = callback(this.result);
            if (result instanceof MyPromise) {
                result.then((res) => {
                    resolve(res);
                }).catch((err) => {
                    reject(err);
                })
            } else if (result instanceof Object && result.then instanceof Function) {
                result.then(res => {
                    resolve(res);
                })
            } else {
                resolve(result);
            }
        } catch (err) {
            reject(err)
        }
    }

    onReject(callback, resolve, reject) {
        if (!callback) return reject(this.error);
        try {
            const res = callback(this.error);
            resolve(res)
        } catch (err) {
            reject(err);
        }
    }

    onFinally(callback, resolve, reject) {
        try {
            callback && callback();
            if (this.status === 'resolved') resolve(this.result);
            if (this.status === 'rejected') reject(this.error);
        } catch (err) {
            reject(err)
        }
    }
}

23. 实现 Promise.all, Promise.race, Promise.any, Promise.resolve, Promise.reject

function resolve(val) {
    if (val instanceof Promise) return val;
    if (val && val.then instanceof Function) { 
        return new Promise(val.then); 
    };
    return new Promise((resolve) => resolve(val));
}

function reject(val) {
    return new Promise((resolve, reject) => reject(val))
}

function all(promiseArr) {
    return new Promise((resolve, reject) => {
        if(!Array.isArray(promiseArr)) {
            reject(new Error('传参错误'))
        }
        let res = [];       // 消息搜集
        let counter = 0;
        for(let i = 0; i< promiseArr.length; i++) {
            Promise.resolve(promiseArr[i]).then((data) => {
                counter ++;
                res.push(data);
                if(counter === promiseArr.length) {
                    resolve(res);
                }
            }).catch(error => {
                reject(new Error('失败'));
            })
        }
    })
}

function race(promiseArr) {
    return new Promise((resolve, reject) => {
        if(!Array.isArray(promiseArr)){
            return reject(new Error('传入的参数必须是数组'));
        }
        for(let i = 0;i< promiseArr.length; i++) {
            Promise.resolve(promiseArr[i]).then((data) => {
                resolve(data);
            }).catch(error => {
                reject(new Error('失败'));
            })
        }
    })
}

function any(promises) {
    const errors = []
    let count = 0;
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then((result) => {
                resolve(result)
            }).catch((err) => {
                errors[i] = err;
                count++;
                if (count === promises.length) {
                    reject(errors)
                }
            })
        }
    })
}

module.exports = {
    resolve,
    reject,
    all,
    race,
    any
}

24. 实现寄生组合继承(es5、es6版本)

// es5版本
function Father(name) {
    this.name = name;
}
Father.prototype.printName = function() {
    console.log(this.name);
}
function Son(age) {
   this.age = age;
   Father.call(this); 
}
Son.prototype = Object.create(Father.prototype); // 把 Father.prototype 作为一个新创建的空对象的原型,并返回这个空对象
Son.prototype.constructor = Son;

// es6版本
class Father {
    constructor(name) {
        this.name = name;
    }
    printName() {
        console.log(this.name);
    }
}
class Son extends Father{
    constructor(name, age) {
        super(name);
        this.age = age;
    }
    printAll() {
        console.log(this.name, this.age);
    }
}

25. 实现一个sleep 函数

// setTimeout版本
const sleep = (fn, wait = 1000) => {
    return function() {
        setTimeout(() => {
            fn.apply(this, arguments);
        }, wait)
    } 
}
// async / await版本
const sleep = async function(fn, wait, ...args) {
    const innerFunc = () => {
        setTimeout(() => {
            fn(...args);
        }, wait)
    }
    await innerFunc();
}
//  promise 版本
const sleep = (wait = 1000) => {
    return new Promise((resolve) => {
        setTimeout(resolve, wait)
    })
}

26. 冒泡排序

function bubbleSort(arr) {
    let length = arr.length;
    for(let i =0; i< length; i++) {
        for(let j = i; j< length; j++) {
            if(arr[j] > arr[j+1]) {
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
            }
        }
    }
    return arr;
}

27. 选择排序

function selectSort(arr) {
    let length = arr.length;
    let minIndex;    // 用来缓存最小的一个值得 index
    for(let i = 0; i< length; i++) {
        minIndex = i;
        for(let j = i; j< length; j++) {
            if(arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
    }
    return arr;
}

28. 快速排序

function quickSort(arr) {
    if(arr.length < 2) {
        return arr;
    }
    let cur = arr[arr.length -1];  // 选取一个值作为分界点的值,也可以取arr[0]
    let leftarr = arr.filter((item, index) => item <= cur && index !== arr.length - 1);
    let rightArr = arr.filter((item, index) => item >= cur && index !== arr.length - 1);
    return [...quickSort(leftarr), cur, ...quickSort(rightArr)];
}

29. 二分法查找数组中的某一元素

function searchVal(arr, val, left = 0, right = arr.length - 1) {
    let midIndex = parseInt((left + right) / 2, 10);
    if (val > arr[midIndex]) {
        return searchVal(arr, val, midIndex + 1, right);
    } else if (val < arr[midIndex]) {
        return searchVal(arr, val, left, midIndex - 1);
    } else {
        return midIndex;
    }
}
// 测试代码
let arr = [1, 4, 5, 66, 7, 8, 34, 4344, 67];
console.log(searchVal(arr, 4));

30. 实现一个lazyman

// 实现一个:lazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
class LazyManClass {
    constructor(name) {
        this.name = name;
        this.queue = [];
        console.log(`HI i am ${this.name}`);
        setTimeout(() => {
            this.next();
        }, 0)
    }
    eat(food) {
        const fn = () => {
            console.log(`I am eating ${food}`);
            this.next();
        }
        this.queue.push(fn);
        return this;
    }
    sleep(time) {
        const fn = () => {
            setTimeout(() => {
                console.log(`等待了${time}秒...`);
                this.next();
            }, time * 1000);
        }
        this.queue.push(fn);
        return this;
    }
    next() {
        // 刷出队列中的第一个任务,并执行:
        const fn = this.queue.shift();
        fn && fn();
    }
}
// 代码测试:
function lazyMan(name) {
    return new LazyManClass(name);
}
lazyMan('Tony').sleep(5).eat('lunch');

31. LRU 缓存淘汰算法

// LRU算法:获取数据和写入数据,写入数据时如果密钥存在则变更数据值,不存在则插入该组数据值,缓存到上线==上限时应该在写入新数据之前删除最开始写入的数据
class LRUCache {
    constructor(size) {
        this.size = size;            // 容量
        this.secretKey = new Map();  // 建立 key 值的字典
    }
    // 取值
    get(key) {
        if(this.secretKey.has(key)) {
            let templateValue = this.secretKey.get(key);
            // 删除了之后重新set 进去
            this.secretKey.delete(key);
            this.secretKey.set(key, templateValue);
            return templateValue;
        } else {
            return -1;
        }
    }
    // 更新
    put(key, value) {
        if(this.secretKey.has(key)) {
            this.secretKey.delete(key);
            this.secretKey.set(key, value);
        } else if(this.secretKey.size < this.size) {
            this.secretKey.set(key, value);
        } else {
            this.secretKey.set(key, value);
            this.secretKey.delete(this.secretKey.keys().next().value);
        }
    }
}

掘金链接:

  • https://juejin.cn/post/6977941904570712078
  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 实现一个数组去重的函数 思路:使用对象来存储数组中的元素,遍历数组,若元素在对象中不存在,则存储到对象中,并将其推入新数组中。 2. 实现一个函数,判断一个字符串是否是回文字符串 思路:将字符串翻转,与原字符串比较是否相等。 3. 实现一个函数,可以将多维数组转化为一维数组 思路:使用递归来遍历多维数组,将每个元素推入新数组中,直到遍历完所有元素。 4. 实现一个函数,统计一个字符串中出现次数最多的字符 思路:使用对象来存储每个字符出现的次数,遍历字符串,将每个字符存储到对象中,找到出现次数最多的字符。 5. 实现一个函数,实现数组的冒泡排序 思路:使用双重循环遍历数组,比较相邻两个元素的大小,如果前者大于后者,则交换两个元素的位置,直到遍历完数组。 6. 实现一个函数,实现数组的快速排序 思路:选择数组中的一个元素作为基准点,将数组分为两个部分,一部分大于基准点,一部分小于基准点,递归处理两个部分。 7. 实现一个函数,实现数组的深拷贝 思路:使用递归遍历数组中的每个元素,判断元素类型,如果是对象或数组,则进行深拷贝,如果是基本类型,则直接复制。 8. 实现一个函数,实现函数的柯里化 思路:使用闭包保存参数,当参数个数达到预设值时,执行函数。 9. 实现一个函数,实现函数的节流 思路:使用定时器来控制函数执行的频率,每次函数执行时,清除定时器并重新设置一个定时器。 10. 实现一个函数,实现函数的防抖 思路:使用定时器来延迟函数执行,每次函数执行时,清除定时器并重新设置一个定时器。如果在定时器延迟时间内再次触发函数,则重新计时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值