前端面试题目(答案)
基础题目
问题1:打印结果?
const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)
答案:1 2 4 3
解释:Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。
Promise.then 属于微任务,执行宏任务完成后,检测微任务队列中是否含有微任务,执行微任务。
答案:
3 3 3
0 1 2
javascript
场景1:console.log(a)打印的内容是什么?
let a ='javascript';
let b = a;
b='html';
console.log(a); // ?
答案:console.log(a); // javascript
解释: 浅拷贝和深拷贝都只针对于引用数据类型,基本数据类型只有直接赋值
场景2:console.log(a.x)打印的内容是什么?
let a = {x:'html', y:'javascript'};
let b = a;
b.x = 'linkkap';
console.log(a.x); // ?
答案:console.log(a.x); // linkkap
解释:引用数据类型直接赋值,传递的值为内存地址,2者都指向堆内存中的同一内存地址
场景3:console.log(a)和console.log(b)打印的内容是什么?
let a = {x:'html', y:['javascript','css']};
let b = {};
Object.assign(b, a);
b.x = 'linkkap';
b.y[0] = 'linkkap';
console.log(a); // ?
console.log(b); // ?
答案:
console.log(a); // {x: "html", y: ["linkkap", "css"]}
console.log(b); // {x: "linkkap", y: ["linkkap", "css"]}
解释:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制
场景4:console.log(a)和console.log(b)打印的内容是什么?
let a = {x:'html', y:['javascript','css']};
let b = JSON.parse(JSON.stringify(a));
b.x = 'linkkap';
b.y[0] = 'linkkap';
console.log(a); // ?
console.log(b); // ?
答案
console.log(a); // {x: "html", y: ["javascript", "css"]}
console.log(b); // {x: "linkkap", y: ["linkkap", "css"]}
解释:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制
数据统计题
题目1:现有一组不同企业的人员成本数据,需要实现一个统计所有企业总成本的方法。
// 人员成本数据
const list = [
{ id: '1', userName: '张三', companyName: '链股', amount: '1000' },
{ id: '2', userName: '李四', companyName: '链股', amount: null },
{ id: '3', userName: '王五', companyName: '链股', amount: '800' },
{ id: '4', userName: '小明', companyName: '名创优品', amount: null },
{ id: '5', userName: '小麦', companyName: '名创优品', amount: '1200' },
{ id: '6', userName: '小叶', companyName: '测试企业', amount: '1700' },
]
// 控制台打印:4700
console.log(countTotal(list))
/**
* 题目:现有一组不同企业的人员成本数据,需要实现一个统计所有企业总成本的方法。
* 要求用JavaScript实现,不限ES6/ES5。
* 输出对象格式:纯数字
*/
const countTotal = (data) => {
}
const countTotal = (data) => {
// 容错处理
if(!Array.isArray(data)) throw new Error('参数必须为数组类型')
// 对象初始化
let total = 0
// 分别统计各个企业对应的总成本
data.forEach(item => {
if(isNaN(item.amount)) throw new Error('参数存在非法字符')
total += Number(item.amount)
})
return total
}
题目2:现有一组不同企业的人员成本数据,需要实现一个统计各个企业总成本的方法。
要求用JavaScript实现,不限ES6/ES5。
/**
* 题目:现有一组不同企业的人员成本数据,需要实现一个统计各个企业总成本的方法。
* 要求用JavaScript实现,不限ES6/ES5。
* 输出对象格式:{企业名称1: 总成本1, 企业名称2: 总成本2,企业名称3: 总成本3,...}
*/
const countFn = (data) => {
}
测试数据如下所示:
// 人员成本数据
const list = [
{ id: '1', userName: '张三', companyName: '链股', amount: '1000' },
{ id: '2', userName: '李四', companyName: '链股', amount: null },
{ id: '3', userName: '王五', companyName: '链股', amount: '800' },
{ id: '4', userName: '小明', companyName: '名创优品', amount: null },
{ id: '5', userName: '小麦', companyName: '名创优品', amount: '1200' },
{ id: '6', userName: '小叶', companyName: '测试企业', amount: '1700' },
]
// 控制台打印:{链股: 1800, 名创优品: 1200, 测试企业: 1700}
console.log(countFn(list))
评分标准:
1.功能正常,即打印结果和预想一样,及格,得60分。
2.countFn方法内有容错处理,加10分,70分,中等。
3.countFn方法内有初始化操作,加10分,80分,良好。
4.countFn方法内有reduce操作,有追求,加10分,90分,优秀。
5.countFn方法内forEach循环内有容错处理,且代码有合适的注释,加10分,100分,满分。
答案参考:
const countFn = (data) => {
// 容错处理
if(!Array.isArray(data)) throw new Error('参数必须为数组类型')
// 对象初始化(可使用for循环或reduce)
const obj = data.reduce((total, person) => {
return {...total, [person.companyName]: 0};
}, {});
// 分别统计各个企业对应的总成本
data.forEach(item => {
if(isNaN(item.amount)) throw new Error('参数存在非法字符')
obj[item.companyName] += Number(item.amount)
})
return obj
}
题目3:现在有红、黄、绿3种颜色的信号灯,红灯1秒闪一次,黄灯2秒闪一次,绿灯3秒闪一次,红灯闪完后到黄灯闪,黄灯闪完后到绿灯闪,绿灯闪完为一次循环,写一个函数来实现以下功能,调用函数后,信号灯进行3次循环
结果: 1秒后打印红、再2秒后打印黄、再3秒后打印绿、再1秒后打印红...
/**
* 现在有红、黄、绿3种颜色的信号灯,红灯1秒闪一次,黄灯2秒闪一次,绿灯3秒闪一次
* 红灯闪完后到黄灯闪,黄灯闪完后到绿灯闪,绿灯闪完为一次循环
* 写一个函数来实现以下功能,调用函数后,信号灯进行3次循环
* 结果 1秒后打印红、再2秒后打印黄、再3秒后打印绿、再1秒后打印红...
*/
loopControl(3)
评分标准:
这道题目有很多种写法,主要考察涉及定时器时的逻辑流程处理是否合适,有没有合理使用promise或者async/await来简化流程,使得代码逻辑清晰,如果可以跟着注释思路走一遍,逻辑可以走通都有高分
功能正常,即打印结果和预想一样,及格,得60分 使用setTimeout嵌套
使用promise,加10分
使用async/await,加10分
代码有合适的注释,加10分
代码逻辑清晰,每个函数功能对应分开,没有挤在一个地方,加10分
参考答案:
// 创建信号灯
const lightFactory = function (color) {
return function (resolve) {
// 这里接收到的resolve是promise的resolve
// 是定时器计算后才会进行这里
console.log(color)
resolve()
}
}
const redHandle = lightFactory('红')
const yellowHandle = lightFactory('黄')
const greenHandle = lightFactory('绿')
// 创建promise
const promiseHandle = function (callback) {
return new Promise(callback)
}
// 创建定时器
const setTimeoutHandle = function (callback, time) {
// 通过这个返回的函数接收promise的resolve
// 在setTimeout执行后把promise的resolve传个信号灯函数
return function (resolve) {
setTimeout(function () {
callback(resolve)
}, time)
}
}
// 给每个信号灯创建定时器
const redSetTimer = setTimeoutHandle(redHandle, 1000)
const yellowSetTimer = setTimeoutHandle(yellowHandle, 2000)
const greenSetTimer = setTimeoutHandle(greenHandle, 3000)
// promise的写法
// promise信号灯控制
function lightControl() {
// promise写法 一个接一个 返回一个promise
return promiseHandle(redSetTimer)
.then(() => promiseHandle(yellowSetTimer))
.then(() => promiseHandle(greenSetTimer))
.then(() => console.log('执行完一次'))
}
// promise控制循环
function loopControl(count) {
const promiseList = []
if (count < 0) {
return
}
// 第一次循环
const firstPromise = lightControl()
promiseList.push(firstPromise)
// 从第二次开始循环
for (let index = 1; index < count; index++) {
// 每一个循环都在前一个循环之后执行
const promise = promiseList[index - 1].then(() => lightControl())
promiseList.push(promise)
}
Promise.all(promiseList).then(() => {
console.log('执行完了')
})
}
// async/await的写法
// async/await信号灯控制
async function asyncLightControl() {
await promiseHandle(redSetTimer)
await promiseHandle(yellowSetTimer)
await promiseHandle(greenSetTimer)
console.log('执行完一次')
}
// async/await信号灯控制
async function asyncLoopControl(count) {
for (let index = 0; index < count; index++) {
await asyncLightControl()
}
console.log('执行完了')
}
// promise入口
// loopControl(3)
// async/await入口
asyncLoopControl(3)