面试前端测试题,有更好的答案吗大佬们?

250 阅读8分钟

1、写出以下程序输出什么,为什么?

const people = {
  name:"",
  hello() {
    console.log(this.name)
  },
  hey:() => {
    console.log(this.name)
  }
}
people.hello() // 输出 " "。// 解释:people.hello() 通过people调用,因此hello内部this指向people,所以打印" "
people.hey()  // 输出 ' ' // 解释:hey()是箭头函,箭头函数声明时候所在的作用域是全局,因此指向window。而window自身就带有name这个属性,属性值为' '

2、请写出以下报错的 原因 和 详细的解决方案

ppL5n77SkP90iTviYSDSYQ.jpeg

解答: 原因:本域名、端口号和请求接口的域名、端口号不一致,导致了跨域。浏览器为了安全限制跨站资源访问,阻止恶意跨站站点攻击的一个保护行为

解决方案:

方案一:通过服务器代理。也就是可以让后台处理第三方接口代理成自己的接口,在调用即可

方案二:如果是在vue项目中可以在config.js文件中的proxyTable属性中配置跨域代理

image.png

方案三:用jsonp。引用script标签不受同源策略的影响动态创建一个script标签,声明一个callback回调函数,在设置scr为请求url,在url后面回调函数作为参数传参。

缺点:只能支持get请求

image.png

3、按题目要求编写代码

使用es新语法,定义一个列表类List,该类必需包含至少以下两个成员:

- 属性length(表示列表中的元素个数)

- 方法add(向列表添加元素)

其中要求构造函数和add方法可以接收任意个数的参数。

解答:

class List(){

    constructor(...items){

    // ...items 为es6的语法剩余参数(rest)相当于普通函数的arguments

    // constructor内定义的方法和属性是实例对象自己(即this)

    // 而constructor外定义的方法和属性则是所有实例对象可以共享

        this.items = items

        this.length = items.length

    }

    add(...items){

        this.items.push(...items)

        this.length = items.length

    }

}

var arr = List('123','1234','12')

console.log(arr.items// ['123','1234','12']

console.log(arr.length// 3

4、按题目要求编写代码

背景:

通过qq号码,调用getUid接口获取用户uid,再依赖uid去分别获取用户基本信息和支付信息。

以下是实习生小明根据需求写的代码。

要求:

请你使用es新语法重写代码,使代码逻辑更加健壮,更加规范,更加清晰,减少嵌套。

function request(methodName, paramObj, cb){
    var params = '?'
    for (var key in paramObj) {
        params += key+'='+paramObj[key] + '&'
    }
    var url = 'http://test.com/'+methodName+params
    var xhr = new XMLHttpRequest();
    xhr.onload = function(e){ cb(e.target.response) };
    xhr.open('GET',url);
    xhr.send();
}

// 1、getInfo方法
function getInfo(qq, cb) {
  // 获取用户ID
  request('getUid',{qq:qq}, function(data){
    if(data.ret === 0){
      var uid= data.uid;

      // 获取用户基本信息
      request('getBaseInfo',{uid:uid}, function(data){
        if(data.ret === 0){
          var baseInfo = data.info;
        }else {
          var baseInfo = {};
        }

        // 获取用户支付信息
        request('getPayInfo',{uid:uid}, function(data){
          if(data.ret === 0){
            var payInfo = data.info;
          }else {
            var payInfo = {};
          }

          // 返回
          cbObejct.assign({},baseInfo, payInfo) );

        })

      })

    }else{
      throw new Error("获取用户ID失败");
    }
  })
}

// 2、开始调用getInfo
getInfo(123456,function(data){ console.log(data) })

解答:

function request(methodName, paramObj, cb){
    let params = '?'
    let url = 'http://test.com/'+methodName+params
    let xhr = new XMLHttpRequest();
    for (var key in paramObj) {
        params +=  key + '=' + paramObj[key] + '&'
    }
    xhr.onload = function(e){ cb(e.target.response) };
    xhr.open('GET',url);
    xhr.send();
}
// 1、getInfo方法
function getInfo(qq, cb) {
    new Promise((resolve, reject) => {
    // 获取用户ID
        request('getUid',{qq:qq}, function(data){
            resolve(data);
        })
    }).then(res=> {
        let uid = res.uid
        let baseInfo = {}
        let payInfo = {}
        // 获取用户基本信息
        request('getBaseInfo',{uid:uid}, function(data){
            baseInfo = data.ret === 0? data.info :{}
        }
     // 获取用户支付信息
        request('getPayInfo',{uid:uid}, function(data){
            payInfo = data.ret === 0? data.info :{}
        })
       // 返回
    cbObejct.assign({},baseInfo, payInfo) );
}).catch(error)=>{
          reject(error)
    }
}
// 2、开始调用getInfo
let fn = function(data){console.log(data) })
getInfo(123456,fn}

5、按题目要求编写代码

写一个JS函数,判断数字是否为对称数(比如121从左到右读,和从右到左读都是一样的)

function isSymmetryNumber(num){

}
isSymmetryNumber(121)
isSymmetryNumber(123321)
isSymmetryNumber(1234

解答:

思路:先把num转换为字符串后在转换为数组,在用reverse反转数组,然后转换回字符串,最后在两者进行比较,相同则返回ture

function isSymmetryNumber(num){
    let numSt = num.toSting()
    let numArr = []
    for(let arr of numSt){
    numArr.push(arr)
}
let reNumSt = numArr.reverse().join('')
console.log(numSt ==reNumSt) // 相等为true
isSymmetryNumber(121)
isSymmetryNumber(123321)
isSymmetryNumber(1234

6、请完成以下环境搭建

● 要求:

1、  选择一个HTTPS的网站(没具体要求,任意非敏感的、公开的网站即可);

2、  浏览器访问该网站,并抓取其随意1条XHR的HTTPS请求包,并保存为SAZ格式文件;

3、  请抓取与个人信息无关的且是公开的请求,并将请求包的 Cookie 和 敏感信息(如个人隐私、登录态)删除;

4、  请在请求头里添加一个自定义头部,x-cuz-flag,值为请求时的时间戳,如1641052799

解答: 抓取m.hao.123.com

image.png

image.png

image.png

image.png

image.png

image.png 在控制台输入下列代码:

var xhr = new XMLHttpRequest();
let url = 'https://m.hao123.com/hao123_api/page/getRootData?vit=h123&from=3w123&sample=1'
xhr.open('GET',url)
xhr.setRequestHeader('x-cuz-flag''202405071524') // 设置请求头
xhr.send()

image.png

7、  按题目要求编写Vue3项目

创建一个 Vue3 项目,并按要求使用 TypeScript 完成项目:

创建1个List.vue组件:

HTML/CSS:

1、  组件由N个div组成,每个div要求:

● width: 100%; height: 500px;

● 背景颜色随机

● 内容为div序号(从0开始)

2、  若处于数据加载请求中时,则底部显示Loading样式(样式不限)

Typescript:

1、  使用 <script setup lang="ts"> 语法标签

2、  初始化基础变量名为 list,初始值为 [ { background: "rgb(233,32,38)" } ],

该变量表示页面上div的渲染个数

3、写一个返回模拟数据的方法 getList(10)

● 该方法接受1个参数:num,表示每次返回的数组长度。 例如传入10,则返回10个随机颜色长度的数组, 例如 [ { background: "rgb(233,32,38)" }, ....其余9个随机颜色.... ]

● 该方法每次执行时,随机模拟 [0,5) 秒的延迟再返回数据

4、组件初始化后,调用 getList(10) 获取新的数据后渲染到页面上;

并且监听滚动条事件,但滚动超过一半时,继续调用 getList(10) 获取新的数据渲染,直到渲染超过50个则停止;

说明:

在完成基础要求的基础上,可以尝试做一些性能优化;

解答:

<template>
  <div class="list" ref="scrollRef">
    <div
      class="listItem"
      :style="item.bgClass"
      v-for="(item, index) in datas"
      :key="index"
    >
      {{ index }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted, watch } from 'vue';

//  随机生成的颜色
function randomColor(): void {
  let bgColor = '#';
  var str = '0123456789abcdef';
  let bgArr = [];
  for (var i = 0; i < 6; i++) {
    let idx = parseInt(Math.random() * str.length);
    bgColor += str[idx];
  }
  return bgColor;
}

// 获取数据
function getList(num): void {
  let data = [];
  for (var i = 0; i < num; i++) {
    data.push({ id: i });
  }
  return data;
}
let datas = ref();

// 延迟2秒展示数据
setTimeout((): void => {
  datas.value = getList(10);
  // 根据数据的条数随机展示不同颜色n个div
  datas.value.forEach((item, index) => {
    item.bgClass = `background-color:${randomColor()}`;
    datas.value[0].bgClass = 'background-color:rgb(233, 32, 38)'; // 默认颜色
  });
}, 2000);
let scrollRef = ref(null);

onMounted(() => {
  scrollRef.value.addEventListener('scroll', (event): void => {
    console.log('@@@scrollRef', scrollRef.value.scrollTop, scrollRef.value);
  });
});
// 滚动事件
</script>

<style scoped>
.list {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  overflow: hidden;
  overflow-y: scroll;
}
.listItem {
  width: 100%;
  height: 500px;
}
</style>

注意:最后两题后台的不会老铁们!!!

8、按题目要求编写NestJS项目

请使用如:

codesandbox.io/s/nest-jjo9…

stackblitz.com/edit/nestjs…

等在线运行环境,完成项目的创建和编写,并分享编写后的项目地址做为答案

创建一个 Nest JS 项目,并按要求使用 TypeScript 完成项目:

1、  创建1个service\utils服务,提供一个double方法:接收一个数字num,返回num*2;

2、  app提供1个路径为 '/api/test' 的 POST请求方法,接收的请求体参数为 {num: 任意数字},其内部调用1的 utilsService.double(num) 方法进行运算后返回

3、  使用NestJS的ValidationPipe,在调用 '/api/test' 时对请求体参数进行自动校验,不符合的请求则返回错误

9、  按题目要求编写SQL代码

请使用如:sqlfiddle.com/postgresql/…等在线运行环境,完成项目的创建和编写,并分享编写后的项目地址做为答案。

请你在 MYSQL 的 test 数据库里,创建一张 广告表(table_name=ad):

id (自增ID)game_code (游戏)expose (曝光度)channel (渠道)spend (渠道花费)
1lol500A5
2cf300A10
3wzry1000B6
4pubgm800B11
5pubgm900A1
6lolm700A2

● 可自己本地搭建MYSQL服务,或者使用在线SQL引擎(如 sqlfiddle.com/)

● 要求使用 MYSQL 语法:

1、  写出 创建表 和 插入上述模拟数据 的SQL Build Schema语句

注意:业务中存在大量按指定game_code进行查询的需求,请考虑该场景进行设计

2、  写出 每个【channel】里最高【spend】的【game_code】SQL查询语句,最终呈现的结果如下:

game_codechannelspend
lolA11
wzryB6

3、写出 按【game_code】、【channel】聚合,将【spend】和【expose】分别累加起来,并先按【spend】降序,再按【expose】升序排序,且分页查询(查询首页,一页2行记录)的SQL查询语句,最终呈现的结果如下:

game_codechannelspendexpose
pubgmA121700
cfA10300

4、在3的基础上,写出不分游戏,不分渠道,将【spend】的【game_code】分别做全量合计的SQL查询语句,最终呈现的结果如下:

game_codechannelspendexpose
--354200

5、在3的基础上,写出查询总页数的SQL语句,最终呈现的结果如下:

total_page_num
3