前端面试题目(答案)

基础题目

问题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来简化流程,使得代码逻辑清晰,如果可以跟着注释思路走一遍,逻辑可以走通都有高分

  1. 功能正常,即打印结果和预想一样,及格,得60分 使用setTimeout嵌套

  2. 使用promise,加10分

  3. 使用async/await,加10分

  4. 代码有合适的注释,加10分

  5. 代码逻辑清晰,每个函数功能对应分开,没有挤在一个地方,加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)