一份保熟的前端面筋

317 阅读8分钟

一、自我介绍

HR你好,我叫Harry,现就读于XXXX大学大四,是一名软件工程专业的学生。本人是在大二的时候通过一本名为《HTML&CSS设计与构建网站》的书接触到前端开发的,当时主要以兴趣为主,学习了一些基本的HTML、CSS,写了一些简单的页面来玩。到了大三,因为觉得前端比后端更有趣,所以选择了前端的职业路线。在此期间,开始系统学习如JavaScript、ES6、Nodejs、Vue2、小程序等。最近刚学完Typescript,打算接着学习Vue3、Vite等技术;近期也做了几个练手项目,但是个人觉得自己的项目还没达到实际企业要求,所以希望通过实习了解企业级前端项目开发,从中提升自己的专业技能。

二、栈内存和堆内存的区别

相关问题:

  1. 内存泄漏的理解

  2. 内存泄漏产生原因(讲了全局变量,闭包,未关闭的定时器延时器,但面试官好像想听到更多的答案)

  3. 如何应对内存泄漏问题

  4. 如何检测内存泄漏问题(真没想过)

参考文章:

三、深浅拷贝的区别、实现方法有哪些

前端面试 第三篇 js之路 深拷贝与浅拷贝

jsliang 求职系列 - 09 - 手写浅拷贝和深拷贝

千万不要用JSON.stringify()去实现深拷贝!有巨坑!!

四、深拷贝的循环引用如何解决

深拷贝如何解决循环引用?

五、递归和尾递归的区别

【愣锤笔记】一篇小短文彻底搞明白js的递归和尾递归

JS-图解尾递归优化-秒懂

六、开发中递归的场景

在云办公项目中,由于存在权限,不同登录者的导航栏是不同的,我们是通过接口到后端查询该登陆者的导航栏数据,根据返回的JSON路由数据进行格式化,这其中就运用到了递归。因为导航栏中每个导航都可能包含子导航,当存在子导航时,就会递归格式化子导航路由对象;这其中没有进行尾递归优化,主要是因为导航栏数量不会超过浏览器的最大递归次数;

import { getRequest } from "./api";

export const initMenu = (router, store)=>{
  // 判断store.routes是否有值
  if(store.state.routes.length > 0){
    return;
  }
  // 发送请求并处理
  getRequest('/system/cfg/menu').then(data=>{
    if(data){
      // 格式化路由
      let fmtRoutes = formatRoutes(data.obj);
      // 添加路由
      router.addRoutes(fmtRoutes);
      // 将数据存入vuex
      store.commit('initRoutes', fmtRoutes);
      // 连接Socket
      store.dispatch('connect')
    }
  })
}

// 格式化路由的函数
export const formatRoutes = (routes)=>{
  let fmtRoutes = [];
  routes.forEach(router=>{
    if(router.name != '所有'){
      let {
        path,
        component,
        name,
        iconCls,
        children
      } = router;
      if(children && children instanceof Array){
        children = formatRoutes(children)
      }
      // 格式化好后的对象
      let fmRouter = {
        path: path,
        name: name,
        iconCls: iconCls,
        children: children,
        // 路由组件懒加载ES5
        component(resolve){
          if(component.startsWith('Home')){
            require(['../views/'+component+'.vue'], resolve)
          }else if(component.startsWith('Emp')){
            require(['../views/emp/'+component+'.vue'], resolve)
          }else if(component.startsWith('Per')){
            require(['../views/per/'+component+'.vue'], resolve)
          }else if(component.startsWith('Sal')){
            require(['../views/sal/'+component+'.vue'], resolve)
          }else if(component.startsWith('Sta')){
            require(['../views/sta/'+component+'.vue'], resolve)
          }else if(component.startsWith('Sys')){
            require(['../views/sys/'+component+'.vue'], resolve)
          }
        }
        // ES6
        // component: () => import ('../views/'+component+'.vue')
      }
      // 存入数组并返回
      fmtRoutes.push(fmRouter)
    }
  });
  // console.log(fmtRoutes);
  return fmtRoutes;
}

七、浏览器多标签页之间通信的方式

实现多个标签页之间通信的几种方法

面试官:你是如何实现浏览器多标签页之间通信的?

# 学习笔记-浏览器内多个标签页之间的通讯

八、类选择器和标签选择器的性能差异

标签选择器、类选择器和ID选择器的区别_一纸传说

看这一篇就够了,css选择器知识汇总_w3cschool

CSS的选择器权重

九、scpoed原理

vue中scoped的原理及慎用原因 - 简书

十、css module和scoped的区别

深入理解vue的scoped和module原理

十一、如何写高质量的css代码

如何写一份不错的CSS代码?

十二、常见的行内元素和块级元素有哪些?

一次性搞懂行内元素和块级元素的区别

CSS中 块级元素、行内元素、行内块元素区别

十三、如何转换行内元素和块级元素,如何设置他们的宽高属性?

  • display:block ,定义元素为块级元素

    • 每个块级元素都是独自占一行;
    • 高度,行高,外边距(margin)以及内边距(padding)都可以控制;
    • 元素的宽度如果不设置的话,默认为父元素的宽度(父元素宽度100%;
    • 多个块状元素标签写在一起,默认排列方式为从上至下;
  • display : inline ,定义元素为行内元素

    • 不会独占一行,相邻的行内元素会排列在同一行里,直到一行排不下才会自动换行,其宽度随元素的内容而变化;
    • 高宽无效,对外边距(margin)和内边距(padding)仅设置左右方向有效 上下无效;
    • 设置行高有效,等同于给父级元素设置行高;
    • 元素的宽度就是它包含的文字或图片的宽度,不可改变;
    • 行内元素中不能放块级元素,a 链接里面不能再放链接;
  • display:inline-block,定义元素为行内块级元素

    • 高度、行高、外边距以及内边距都可以控制;
    • 默认宽度就是它本身内容的宽度,不独占一行,但是之间会有空白缝隙,设置它上一级的 font-size 为 0,才会消除间隙;

十四、css实现隐藏元素的方式有哪些?

css中,有哪些方式可以隐藏页面元素?区别?

十五、如何实现元素垂直居中,有哪些方式?

实现元素水平垂直居中的方式有哪些?

十六、什么是重排和重绘,怎么减少?

浏览器渲染原理(性能优化之如何减少重排和重绘

什么是重绘和重排/回流? 如何去避免?

十七、meta是什么原理,什么作用?

meta标签到底是做什么的|我竟一无所知

十八、跨域解决方法

七大跨域解决方法原理

十九、nginx反向代理如何配置

面试题:nginx有配置过吗?反向代理知道吗?

二十、防抖和节流原理,具体如何实现用代码表示

防抖和节流的实现原理

function debounce(fn, delay=300){
  let timer = 0;
  return function(){
    if(timer){
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = 0;
    }, delay);
  }
};
function throttle(fn, delay=300){
  let timer = 0;
  return function(){
    if(timer){
      return;
    }
    timer = setTimeout(function(){
      fn.apply(this, arguments);
      timer = 0;
    }, delay)
  }
}

二十一、如何交换两个变量的值,不用第三方变量

面试官在“逗”你系列:不借助第三变量交换两个变量值的方案你有几种?

二十二、从输入url到显示网页,整个流程发生了什么

史上最详细的经典面试题 从输入URL到看到页面发生了什么?

二十三、三个promise实例对象,怎么做才能按照一定顺序输出

有3个异步函数A/B/C,请使用Promise实现ABC的顺序执行

二十四、关于axios和前后端交互的一些问题

前后端数据交互(五)——什么是 axios?

二十五、怎么实现懒加载

实现懒加载的几种方式(一)

如何实现图片懒加载?

二十六、Https优缺点

# 十分钟搞懂HTTP和HTTPS协议?

二十七、Http2.0

面试官问:你了解HTTP2.0吗?

二十八、js动画怎么实现

  • 获取DOM元素,根据动画需求修改CSS样式,并使用transition作过渡

二十九、nodejs原生模块用过哪些

相关问题:用过fs模块的哪些api?readFileSync的参数是什么?

Nodejs常用模块

三十、vue生命周期,介绍生命周期中钩子函数等流程

Vue都使用那么久了,还不了解它的生命周期吗✨

三十一、vuex的一些细节问题

这次彻底搞懂Vuex!(小白级别教程)

三十二、Vue组件间的通信方式

Vue 组件间通信六种方式(完整版)

三十三、v-model原理

  • 数据劫持+发布者-订阅者模式
    • 通过Object.defineProperty()进行数据劫持(包含getter和setter)
    • Observer 给属性加了个监听器,属性值变化的时候,监听器会监听到,从而触发数据劫持中的setter,发出通知
    • 订阅器Dep接收到通知后,通知Watcher属性发生变化,之后Watcher触发视图更新函数 image.png

三十四、为什么 v-for + key

为什么使用v-for时必须添加唯一的key?

三十五、常用的git命令

版本控制——深入浅出git

  • git add .
  • git commit -m ''
  • git remote add git@harrylee13/cloud-office
  • git push - u origin master
  • git pull
  • git log

三十六、开发中,同事把你写的代码扒下来然后弄出错了,你怎么解决?

  • 进行版本回退

三十七、你还有什么问题?

  • 公司项目?
  • 技术栈?