前端面试宝典总结4-手搓代码JavaScript(场景篇)

前端面试宝典总结4之手写代码JavaScript(场景篇)

本文章 对各大学习技术论坛知识点,进行总结、归纳自用学习,共勉🙏

上一篇👉: 前端面试宝典总结4-手搓代码JavaScript(基础篇)

1.深拷贝: 当你需要完全复制一个对象,包括它的嵌套对象时,避免引用造成的数据篡改。

function deepClone(obj, hash = new WeakMap()) {
    if (obj == null) return obj; // 处理 null 和 undefined
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    
    if (hash.has(obj)) return hash.get(obj); // 处理循环引用
    
    let Constructor = obj.constructor;
    let newObj = new Constructor();
    
    hash.set(obj, newObj);
    
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) { // 只遍历实例上的属性
            newObj[key] = deepClone(obj[key], hash);
        }
    }
    return newObj;
}

2.用Promise实现图片的异步加载

let imageAsync = (url) => {
    return new Promise((resolve, reject) => {
        let img = new Image();
        img.src = url;
        img.onload = () => {
            console.log(`图片请求成功,此处进行通用操作`);
            resolve(img);
        }
        img.onerror = (err) => {
            console.log(`失败,此处进行失败的通用操作`);
            reject(err);
        }
    });
};

imageAsync("url").then((img) => {
    console.log("加载成功");
}).catch((error) => {
    console.log("加载失败");
});

3.实现发布-订阅模式

class PubSub {
    constructor() {
        this.events = {};
    }

    subscribe(event, handler) {
        if (!this.events[event]) this.events[event] = [];
        this.events[event].push(handler);
    }

    publish(event, data) {
        if (this.events[event]) {
            this.events[event].forEach(handler => handler(data));
        }
    }

    unsubscribe(event, handler) {
        if (this.events[event]) {
            this.events[event] = this.events[event].filter(h => h !== handler);
        }
    }
}

// 使用示例
const pubsub = new PubSub();
pubsub.subscribe('news', data => console.log('Breaking News:', data));
pubsub.publish('news', 'New Article Published!');

4. 实现一个简单的事件监听与触发系统

class EventBus {
    constructor() {
        this.events = {};
    }

    on(eventName, listener) {
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        this.events[eventName].push(listener);
    }

    emit(eventName, data) {
        const listeners = this.events[eventName];
        if (listeners) {
            listeners.forEach(listener => listener(data));
        }
    }

    off(eventName, listener) {
        if (this.events[eventName]) {
            this.events[eventName] = this.events[eventName].filter(l => l !== listener);
        }
    }
}

// 使用示例
const bus = new EventBus();
bus.on('login', data => console.log('User logged in:', data));
bus.emit('login', { username: 'John Doe' });

5.实现一个简单的节流(Throttle)函数

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

// 使用示例
const logMessage = throttle(console.log, 1000);
logMessage('Hello');
setTimeout(() => logMessage('World'), 500);
setTimeout(() => logMessage('Again'), 1500);

6.实现一个简单的深合并函数(Deep Merge)

function isObject(item) {
    return (item && typeof item === 'object' && !Array.isArray(item));
}

function deepMerge(target, source) {
    Object.keys(source).forEach(key => {
        const targetValue = target[key];
        const sourceValue = source[key];

        if (isObject(targetValue) {
            target[key] = deepMerge(Object.assign({}, targetValue), sourceValue);
        } else {
            target[key] = sourceValue;
        }
    });
    return target;
}

// 使用示例
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { b: { d: 3 }, e: 4 };
const merged = deepMerge(obj1, obj2);
console.log(merged); // 输出: { a: 1, b: { c: 2, d: 3 }, e: 4 }

7.实现一个简单的计时器(倒计时器)

用户需要一个简单的倒计时器,从特定秒数开始倒数,每秒更新一次直到0。

function countdown(seconds, onUpdate, onFinish) {
    let remaining = seconds;
    const intervalId = setInterval(() => {
        if (remaining <= 0) {
            clearInterval(intervalId);
            if (typeof onFinish === 'function') onFinish();
            return;
        }
        onUpdate(remaining--);
    }, 1000);
}

// 使用示例
countdown(10, time => console.log(`Time Remaining: ${time}s`), () => console.log('Countdown Finished!'));

8.实现一个简单的轮询请求,直到满足条件

场景描述:在某些场景中,比如等待远程资源变为可用,需要不断地发起请求直到某个条件满足或达到最大尝试次数。

function pollUntil(conditionFn, pollFn, interval = 1000, maxAttempts = -1, attempt = 0) {
    return new Promise((resolve, reject) => {
        const checkCondition = () => {
            if (conditionFn()) {
                resolve();
            } else if (maxAttempts !== -1 && attempt >= maxAttempts) {
                reject(new Error('Polling stopped after maximum attempts reached'));
            } else {
                attempt++;
                setTimeout(checkCondition, interval);
            }
        };
        checkCondition();
    });
}

// 使用示例
// 假设有一个检查资源是否准备好的函数 checkResourceReady
const checkResource = () => /* 返回 true/false 表示资源是否准备好 */;
pollUntil(checkResource, () => console.log('Checking...'), 2000, 10)
    .then(() => console.log('Resource is ready!'))
    .catch(err => console.error('Polling ended with error:', err));

9. 实现一个简单的缓存机制(LRU Cache)

对于昂贵的计算或频繁查询的API调用,实现一个简单的缓存策略,使得最近使用的数据能在短时间内被快速获取。

class LRUCache {
    constructor(capacity = 5) {
        this.capacity = capacity;
        this.cache = new Map();
        this.keysOrder = [];
    }

    get(key) {
        if (this.cache.has(key)) {
            // 更新访问顺序
            this.keysOrder.splice(this.keysOrder.indexOf(key), 1);
            this.keysOrder.push(key);
            return this.cache.get(key);
        }
        return null;
    }

    put(key, value) {
        if (this.cache.has(key)) {
            this.cache.delete(key);
            this.keysOrder.splice(this.keysOrder.indexOf(key), 1);
        }
        if (this.cache.size >= this.capacity) {
            const leastRecentlyUsedKey = this.keysOrder.shift();
            this.cache.delete(leastRecentlyUsedKey);
        }
        this.cache.set(key, value);
        this.keysOrder.push(key);
    }
}

// 使用示例
const cache = new LRUCache(2);
cache.put('A', 'Apple');
cache.put('B', 'Banana');
cache.get('A'); // 返回 'Apple'
cache.put('C', 'Cherry'); // 自动移除最久未使用的项,这里是 'A'
cache.get('A'); // 返回 null,因为'A'已经被移除

10.实现每隔一秒打印 1,2,3,4

// 使用闭包实现
for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
}
// 使用 let 块级作用域
for (let i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}


let i = 1;
setInterval(() => {
    console.log(i++);
    if (i > 4) {
        i = 1; // 重置计数器
    }
}, 1000);
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值