前端面试CODING篇-请实现一个类似 Promise.all的功能

103 阅读3分钟

再说一遍!前端开发面试之后,不要不当回事,一定要复盘。

我一个朋友面试了好多家,逐渐找到感觉之后,最后一次的面试直冲26k。

最近在参加前端开发的面试,有一些手写代码的题目当场发挥的不太好,拍大腿!所以还是要回顾一下,加深一下理解!有需要面试的朋友可以参考一下,如有更好的方法,还请指教~
1.请用代码实现JS原形链
// 定义一个基类(父类-动物是一个大类)
function Animal(name) {
  this.name = name;
}
// 给基类的原型添加方法(动物这个大类都有哪些特点,比如动物能发声音,能吃,能睡)
Animal.prototype.speak = function() {
  console.log(`${this.name}发出声音`);
};
// 定义一个子类- 动物这个大类别下有哪些动物呢?动物园有哪些动物呢? 比如说狗子 
function Dog(name, breed) {
  // 继承父类属性- 狗子属于动物,所以它拥有动物的特点,比如 会叫,吃,睡
  Animal.call(this, name); //这句就表示 狗会叫了! 因为继承了动物这个父类
  this.breed = breed;  // 这句表示狗狗这个动物,品种是什么比如牧羊犬,雪橇犬,藏獒
}
// 上面是一个例子,那动物有太多特点,我们怎么能让狗狗继承动物的全部特点?往下看
// 设置子类的原型为Animal的实例,实现继承
Dog.prototype = Object.create(Animal.prototype);//创建一个新对象,
//其原型指向 `Animal.prototype`。这意味着 `Dog` 的原型对象将继
// 承 `Animal` 原型上的所有属性和方法
// 恢复构造函数引用
Dog.prototype.constructor = Dog;
// 原型链的本质:当访问 `Dog` 实例的属性或方法时,若实例自身没有该属性,
// 会沿着原型链向上查找 `Animal.prototype`,实现继承。
// 给子类添加特定方法- 该方法是 `Dog` 类特有的行为,不会出现在 `Animal` 类中,体现了子类对父类的扩展
Dog.prototype.bark = function() {
  console.log(`${this.name}汪汪叫`);
};
// 创建实例
const animal = new Animal('动物');
const dog = new Dog('小白', '哈士奇');

// 测试原型链
console.log('动物实例:');
animal.speak(); // 动物发出声音
console.log('狗实例:');
dog.speak();    // 小白发出声音
dog.bark();     // 小白汪汪叫
console.log('原型链验证:');
console.log(dog instanceof Dog);    // true
console.log(dog instanceof Animal); // true
console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true 

方法2- ES6 语法 - 推荐,简洁

class Animal {
  constructor(name, age) {
    this.name = name;
  }
  eat() { console.log(`${this.name}在吃东西`); }
}
class Dog extends Animal {
  constructor(name, age, breed) {
    super(name, age); // 调用父类构造函数
    this.breed = breed;
  }
  bark() { console.log(`${this.name}汪汪叫`); }
2.一串数字比如1234567实现千分位(考查数组字符串的属性与方法)
function formatNumberWithCommas(str) {
    // 检查输入是否为字符串
    if (typeof str !== 'string') {
        throw new Error('输入必须是字符串');
    }
    // 处理可能存在的符号
    let sign = '';
    if (str.startsWith('-')) {
        sign = '-';
        str = str.slice(1);
    } else if (str.startsWith('+')) {
        str = str.slice(1);
    }
    // 分离整数和小数部分
    let parts = str.split('.');
    let integerPart = parts[0];
    let decimalPart = parts.length > 1 ? '.' + parts[1] : '';

    // 格式化整数部分 
    let formattedInteger = '';
    let count = 0;
    for (let i = integerPart.length - 1; i >= 0; i--) {
        formattedInteger = integerPart[i] + formattedInteger;
        count++;
        if (count % 3 === 0 && i > 0) {
            formattedInteger = ',' + formattedInteger;
        }
    }

    // 组合结果
    return sign + formattedInteger + decimalPart;
}

// 示例用法
console.log(formatNumberWithCommas('1234567890'));      // 输出: "1,234,567,890"
console.log(formatNumberWithCommas('-1234567890.123')); // 输出: "-1,234,567,890.123"
console.log(formatNumberWithCommas('+1234.567890'));    // 输出: "1,234.567890"
console.log(formatNumberWithCommas('0.1234'));          // 输出: "0.1234"
console.log(formatNumberWithCommas('123'));             // 输出: "123"
3.请手动实现一个类似Promise.all的功能
function myPromiseAll(promises) {
    return new Promise((resolve, reject) => {
       //判断是不是数组
        if (!Array.isArray(promises)) {
            return reject(new TypeError('The first argument must be an array'));
        }
        
        const results = []; // 执行结果
        let completedCount = 0; // 成功的次数
        if (promises.length === 0) {
            return resolve(results);
        }
        // 依次返回结果存储到results数组中
        promises.forEach((promise, index) => {
            Promise.resolve(promise)
               .then(value => {
                   // 如果成功了把结果放在result中,成功的次数+1
                    results[index] = value;
                    completedCount++;
                    // 如果成功的数和传进的数组的长度相等了,说明循环结束了,把结果丢出去
                    if (completedCount === promises.length) {
                        resolve(results);
                    }
                })
               .catch(error => {
               // 依次执行的时候如果抛出错,就返回这个错误,直接结束foreach
                    reject(error);
                });
        });
    });
}

// 测试代码 这是3个promise, 实际案例可能是3个执行的数据请求,他们有依赖关系,就依次执行,只有全部请求成功才会返回结果,否则抛出错误。页面终端渲染。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
// 这个把 Promise.all替换成我们手写的myPromiseAll
myPromiseAll([promise1, promise2, promise3])
   .then(values => {
        console.log(values); 
    })
   .catch(error => {
        console.error(error);
    });
4.请手动实现一个Promise的功能
function MyPromise(fn) {
    // 有三个状态 pending  fulfilled rejected 初始化一个
    let state = 'pending';
    let value = null;
    let callbacks = [];
    function resolve(newValue) {
        if (state === 'pending') {
            state = 'fulfilled';
            value = newValue;
            callbacks.forEach(callback => callback.onFulfilled(value));
        }
    }
    function reject(newValue) {
        if (state === 'pending') {
            state = 'rejected';
            value = newValue;
            callbacks.forEach(callback => callback.onRejected(value));
        }
    }
    try {
        fn(resolve, reject);
    } catch (e) {
        reject(e);
    }
    this.then = function (onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            callbacks.push({
                onFulfilled: function () {
                    try {
                        let newValue = onFulfilled(value);
                        resolve(newValue);
                    } catch (e) {
                        reject(e);
                    }
                },
                onRejected: function () {
                    try {
                        let newValue = onRejected(value);
                        resolve(newValue);
                    } catch (e) {
                        reject(e);
                    }
                }
            });
        });
    };
}
5.函数防抖与节流的实现
//防抖- 闭包的案例 
function debounce(func, delay) {
    let timer = null;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, arguments);
        }, delay);
    };
}
//节流
function throttle(func, wait) {
    let timer = null;
    let previous = 0;
    return function () {
        let now = Date.now();
        let remaining = wait - (now - previous);
        if (remaining <= 0) {
            func.apply(this, arguments);
            previous = now;
        } else if (!timer) {
            timer = setTimeout(() => {
                func.apply(this, arguments);
                previous = Date.now();
                clearTimeout(timer);
                timer = null;
            }, remaining);
        }
    };
}
6.实现一个对象深拷贝
function deepClone(obj) {
    if (typeof obj!== 'object' || obj === null) {
        return obj;
    }
    let clone = Array.isArray(obj)? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            clone[key] = deepClone(obj[key]);
        }
    }
    return clone;
}

未完待续..... 你还知道哪些经典面试题目呢?

我是阿慧,勇闯大前端,不服输。

每天学习一点点,千里之行,始于脚下!