再说一遍!前端开发面试之后,不要不当回事,一定要复盘。
我一个朋友面试了好多家,逐渐找到感觉之后,最后一次的面试直冲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;
}
未完待续..... 你还知道哪些经典面试题目呢?
我是阿慧,勇闯大前端,不服输。
每天学习一点点,千里之行,始于脚下!