10个常考的前端手写题

1. 实现一个简单的 JavaScript 函数,用于判断一个对象是否为空:

判断对象是否为空的函数 这个函数通过遍历对象的所有属性来检查是否有任何实际定义的键。如果在循环中找到了一个键,则立即返回false,表示对象不为空。如果没有找到任何键,则在循环结束后返回true,表示对象为空。

function isEmptyObject(obj) {
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            return false;
        }
    }
    return true;
}

2. 手写数组去重:

数组去重 第一个实现是使用传统的方法,创建一个新的数组,并利用indexOf方法检查当前元素是否已存在于新数组中,不存在则添加进去。 第二个实现利用了ES6中的Set数据结构,它不允许重复值,所以可以直接将数组转换为Set再转回数组达到去重效果。

function unique(arr) {
    let res = [];
    for(let i = 0; i < arr.length; i++) {
        if(res.indexOf(arr[i]) === -1) {
            res.push(arr[i]);
        }
    }
    return res;
}
// 或者使用ES6的新特性Set
function uniqueES6(arr) {
    return [...new Set(arr)];
}

3. 实现bind函数:

实现bind函数 JavaScript中原生的bind函数可以创建一个新的函数,在调用时设置其this上下文并传递预设参数。这里的实现同样创建了一个新的函数,并在其内部调用了原函数,同时保证了this指向和传参的正确性。

Function.prototype.myBind = function(context, ...args) {
    const self = this;
    return function(...newArgs) {
        return self.apply(context, [...args, ...newArgs]);
    };
};

4. 实现数组的map方法:

实现map方法 Array.prototype.map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。这里我们模拟了这个行为,对原数组进行遍历,并将回调函数应用于每个元素,然后将结果推入新数组。

Array.prototype.myMap = function(callback, thisArg) {
    const newArray = [];
    for (let i = 0; i < this.length; i++) {
        newArray.push(callback.call(thisArg, this[i], i, this));
    }
    return newArray;
};

5. 实现简易版的深拷贝:

简易版深拷贝 实现了一个递归函数,用于复制给定对象的所有属性和嵌套对象。当遇到非对象或null类型的值时直接返回,否则创建一个新的对象并递归地复制原对象的所有属性。

function deepClone(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return obj;
    }
    let cloneObj = Array.isArray(obj) ? [] : {};
    for(let key in obj) {
        if (obj.hasOwnProperty(key)) {
            cloneObj[key] = deepClone(obj[key]);
        }
    }
    return cloneObj;
}

6. 实现防抖函数(debounce):

防抖函数(debounce) 防抖函数用于限制某个函数在一定时间内只能执行一次。例如在窗口 resize 或输入框连续输入事件中,防止短时间内多次触发。这里的实现是在每次调用时清除上一次的延时任务,然后重新设置一个延时任务,只有在指定时间间隔内没有再次调用时,才会执行原函数。

function debounce(func, wait) {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(this, args);
        }, wait);
    };
}

7. 实现节流函数(throttle):

节流函数(throttle) 节流函数确保在一定时间内,只允许函数执行一次。与防抖不同的是,节流保证了在持续触发的情况下,至少每隔一定时间会执行一次函数。这里的实现是在触发函数时记录上一次执行的时间,如果当前时间与上次执行时间差大于设定的时间间隔,则执行函数

function throttle(func, delay) {
    let prev = Date.now();
    return function(...args) {
        const now = Date.now();
        if (now - prev >= delay) {
            func.apply(this, args);
            prev = now;
        }
    };
}

8. 实现 Promise 的 then 方法:

实现Promise的then方法 Promise的then方法接受两个回调函数作为参数,分别处理成功和失败的情况。这里模拟Promise的状态机,根据Promise当前状态异步执行相应的回调函数,并处理回调返回的新Promise。

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    let self = this;
    return new MyPromise((resolve, reject) => {
        if (self.status === 'fulfilled') {
            setTimeout(() => { // 异步执行
                try {
                    let x = onFulfilled(self.value);
                    resolvePromise(x, resolve, reject);
                } catch(e) {
                    reject(e);
                }
            }, 0);
        } else if (self.status === 'rejected') {
            setTimeout(() => {
                try {
                    let x = onRejected(self.reason);
                    resolvePromise(x, resolve, reject);
                } catch(e) {
                    reject(e);
                }
            }, 0);
        } else {
            self.onResolvedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(x, resolve, reject);
                    } catch(e) {
                        reject(e);
                    }
                }, 0);
            });
            self.onRejectedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        let x = onRejected(self.reason);
                        resolvePromise(x, resolve, reject);
                    } catch(e) {
                        reject(e);
                    }
                }, 0);
            });
        }
    });
};

function resolvePromise(value, resolve, reject) {
    if (value instanceof MyPromise) {
        value.then(resolve, reject);
    } else {
        resolve(value);
    }
}

9. 实现简易版 Ajax 请求:

简易版Ajax请求 实现了一个基于XMLHttpRequest的简易Ajax请求函数,返回一个Promise对象。当请求完成且状态码正常时解析响应内容并resolve,否则reject。

function ajax(url, method, data) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open(method, url, true);
        xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(JSON.parse(xhr.responseText));
                } else {
                    reject(xhr.statusText);
                }
            }
        };
        xhr.onerror = function() {
            reject(xhr.statusText);
        };
        xhr.send(JSON.stringify(data));
    });
}

10. 实现一个简易版的事件委托:

实现事件委托 事件委托是一种优化事件处理的方式,通过监听父级元素的事件,然后通过事件对象判断触发事件的具体子元素,从而减少绑定事件的数量。在这个实现中,当父元素接收到事件时,会向上遍历事件传播链,查找是否匹配特定选择器的目标元素,如果匹配就执行处理器函数。

function delegateEvent(element, selector, eventType, handler) {
    element.addEventListener(eventType, function(event) {
        let target = event.target;
        while (target && target !== this) {
            if (target.matches(selector)) {
                handler.call(target, event);
                break;
            }
            target = target.parentNode;
        }
    });
}
  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一些可能会在2023前端面试中常见的手写: 1. 实现一个事件订阅/发布模式 ```javascript class EventEmitter { constructor() { this.events = {}; } on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); } emit(eventName, ...args) { const callbacks = this.events[eventName]; if (callbacks) { callbacks.forEach((callback) => { callback(...args); }); } } off(eventName, callback) { const callbacks = this.events[eventName]; if (callbacks) { const index = callbacks.indexOf(callback); if (index !== -1) { callbacks.splice(index, 1); } } } } ``` 2. 实现一个 Promise ```javascript class MyPromise { constructor(executor) { this.state = "pending"; this.value = undefined; this.reason = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === "pending") { this.state = "fulfilled"; this.value = value; this.onFulfilledCallbacks.forEach((callback) => callback()); } }; const reject = (reason) => { if (this.state === "pending") { this.state = "rejected"; this.reason = reason; this.onRejectedCallbacks.forEach((callback) => callback()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { const promise2 = new MyPromise((resolve, reject) => { const onFulfilledCallback = () => { try { const x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }; const onRejectedCallback = () => { try { const x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }; if (this.state === "fulfilled") { onFulfilledCallback(); } else if (this.state === "rejected") { onRejectedCallback(); } else { this.onFulfilledCallbacks.push(onFulfilledCallback); this.onRejectedCallbacks.push(onRejectedCallback); } }); return promise2; } catch(onRejected) { return this.then(null, onRejected); } } function resolvePromise(promise, x, resolve, reject) { if (promise === x) { reject(new TypeError("Chaining cycle detected")); } else if (x instanceof MyPromise) { x.then( (value) => resolve(value), (reason) => reject(reason) ); } else { resolve(x); } } ``` 3. 实现一个防抖函数 ```javascript function debounce(func, delay) { let timer; return function (...args) { if (timer) { clearTimeout(timer); } timer = setTimeout(() => { func.apply(this, args); }, delay); }; } ``` 4. 实现一个节流函数 ```javascript function throttle(func, delay) { let timer; return function (...args) { if (!timer) { timer = setTimeout(() => { func.apply(this, args); timer = null; }, delay); } }; } ``` 5. 实现一个深拷贝函数 ```javascript function deepClone(obj) { if (typeof obj !== "object" || obj === null) { return obj; } let result; if (Array.isArray(obj)) { result = []; } else { result = {}; } for (let key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { result[key] = deepClone(obj[key]); } } return result; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一花一world

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值