原文地址

css

什么是盒模型

html元素由一个矩形框组成,即盒模型,

盒模型由这些部分组成:

  • content box
    • 显示内容的区域
    • 通过width/height设置大小
  • padding box
    • 内边框,padding
  • border box
    • 边框,border
  • margin box
    • 外边框,margin

介绍一下css的2种盒模型

  • box-sizing:content-box
    • 标准盒模型
    • 元素的宽度、高度只包括内容
  • box-sizing:border-box
    • IE盒模型
    • 元素内容包括内边距和边框

link和@import的区别

  • 导入方式不同
    • link使用标签的方式
    • @import是css的一种语法
  • 使用范围不同
    • link除了加载css样式,还能用于指定rel属性
      • rel属性指定当前文档和被链接文档/资源之间的关系
  • 加载方式不同
    • link方式:浏览器会一同加载html和css
    • @import:浏览器会先加载html,再加载css
  • 可以通过js操作dom,插入link
  • @import支持ie5以上,link标签不存在兼容性问题

常用的布局方式

  • flex布局
  • grid网格布局
  • 绝对定位布局
  • 浮动布局
  • 两栏布局
    • 左侧宽度固定,右侧自适应

中间有间距,两边没有间距,怎么设置

  • 使用flex横向布局,justify-content使用space-between
  • 使用flex横向布局,设置flex:1自适应宽度,设置gap
  • 左侧元素设置margin-right,右侧元素设置margin-left

position定位有哪些

  • static
    • top/right/bottom/left/z-index无效
  • relative
    • 相对于正常文档流的位置
  • absolute
    • 相对于最近的非static定位祖先元素
  • fixed
    • 相对于视口
  • sticky

js

什么是变量提升

  • 将所有var声明的变量和函数提升到代码的头部
  • 函数声明的优先级高于变量声明

原型和原型链

  • 什么是原型
    • 在js中,每定义一个对象,对象中都会包含一些预定义的属性
    • 每个函数对象上都有一个prototype属性,这个属性指向函数的原型对象
    • 使用原型对象的好处是所有对象实例共享它包含的属性和方法
  • 什么是原型链
    • 每个对象都有一个原型对象,通过proto指针指向原型对象,并从中继承方法和属性
    • 原型对象也可能拥有原型
    • 这样一层一层,最终指向null,这种关系就是原型链
    • 通过原型链一个对象可以拥有定义在其他对象中的属性和方法

防抖和节流

什么是节流防抖

  • 当多次执行某一动作,进行函数调用次数的限制,节省资源
  • 防抖
    • 在事件触发n秒后执行函数,若在n秒内再次触发,重新计时
    • 只有在最后一次事件之后才触发一次函数
  • 节流
    • 当多次执行某一动作,每隔一段时间,只执行一次函数
    • 不管事件触发有多频繁,都能保证在规定时间内一定会执行一次时间处理函数
    • 需要在用户触发页面滚动时,请求后台数据
  • 应用场景
    • 防抖
      • 登录、发短信等按钮,防止用户按得太快
      • 窗口大小resize事件,希望窗口调整结束后触发
      • 鼠标的mousemove、mouseover事件
    • 节流
      • 列表滚动
      • 搜索联想功能
      • 表单重复提交

如何实现

  • 防抖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var timer;
function debounce(fn, delay){
if(timer){
// 保证只开启一个定时器
clearTimeout(timer)
}
timer = setTimeout(function(){
// 延迟delay执行函数
fn()
},delay)
}
window.onscroll = function(){
debounce(test, 1000)
}
function test(){
console.log('滚动停止')
}
  • 节流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function  debounce(fn,delay){
let timer;
return function(){
let _this = this
let _args = arguments;
if(timer){
clearTimeout(timer)
}
timer = setTimeout(function(){
fn.apply(_this,_args)
},delay)
}
}
let testDebounceFn = debounce(test, 1000)
function test(a){
console.log('滚动停止'+a)
}
window.onscroll = function(){
testDebounceFn('aaaa')
}

什么是闭包

  • 内层函数访问外层函数作用域

结合闭包,说一下防抖是怎么实现的

  • debounce函数接受两个参数
    • 需要防抖的函数
    • 延迟时间
  • 使用闭包保存timer变量,确保每次调用返回的函数都能访问到同一个timer
  • 每次事件触发,如果timer存在,则清除之前的定时器,设置一个新的定时器
  • 延迟时间到达后,执行func函数

this的指向

  • 面试官说,谁调用就指向谁

  • 指向当前执行的上下文

  • 调用模式

    • 函数调用
    • 方法调用
    • 构造器调用
    • apply/bind/call

怎么手动改变this

apply、bind、call

call、bind、apply的区别

  • apply传参是数组,call是参数列表
  • bind返回绑定this之后的函数,apply和call是立即执行

手写call

  • 手写call
1
2
3
4
5
6
Function.prototype.myCall = function(context, ...arg){
const fn = Symbol('临时属性')
context[fn] = this
context[fn](...arg)
delete context[fn]
}
  • 手写apply
1
2
3
4
5
6
Function.prototype.apply = function(context,arg){
const fn = Symbol('占位元素')
context[fn] = context
context[fn](...arg)
delete context[fn]
}
  • 手写bind
1
2
3
4
5
6
7
8
Function.prototype.myBind = function(context, ...firstarg){
const that = this
const bindFn = function (...secoundarg){
return that.myCall(context, ...firstarg, ...secoundarg)
}
bindFn.prototype = Object.create(that.prototype)
return bindFn
}

箭头函数和普通函数区别

  • 写法不同
  • 箭头函数都是匿名函数
  • 箭头函数不能用于构造函数
  • 普通函数this指向调用对象,如果作为构造函数,this指向创建的实例
  • 箭头函数的this永远指向上下文的this,并且无法改变
  • 箭头函数没有arguments

react

react中性能优化有哪些方法

参考博客

  • React.memo
    • react在组件刷新的时候会深度遍历所有子组件,查找所有更新节点,即父组件更新,子组件必会更新
    • memo可以在某些情况下避免不必要的组件重新渲染,从而提高应用程序的性能
    • 有2种用法
      • 直接使用memo包裹组件
      • 需要更加精确的控制组件重新渲染,可以传递第二个参数给memo来自定义比较函数,函数接收2个值,分别是前一次的props和当前的props,返回一个布尔值表示是否需要重新渲染组件
    • 如果是class组件
      • 一般使用shouldComponentUpdate函数或则PureComponent实现
  • 列表使用key
    • 为了提高diff算法在渲染列表时候的性能
    • 有了它,react就能知道相比较上一个渲染周期,当前的渲染周期需要插入、移动或者删除哪些节点
    • 复用之前的dom,减少不必要的dom操作所产生的开销,从而提高界面更新的性能
  • 合理运用useCallback和useMemo
    • useMemo和useCallback只针对重新渲染有帮助
    • 需要结合父组件具体情况来看
  • 使用懒加载和代码分割
    • 使用React.lazy和Suspense,按需加载组件,可以减少初始化加载时间,提高性能
  • 使用虚拟化
    • 对长列表或大型数据集,使用虚拟化库,仅渲染可见部分
      • react-virtualized
  • 使用Profiler测量性能

useMemo和useEffect的区别

  • 执行时机不同
    • useMemo
      • 会在渲染期间执行,memo在dom更新前触发
    • useEffect
      • 只能在dom更新后,浏览器渲染完成后再触发

useMemo的原理,为什么要用React.memo包裹起来

  • react的渲染过程
    • 触发渲染:props或者state发生变化时,react会重新渲染
    • render方法:react调用组件的render方法,生成虚拟dom
    • 比较虚拟dom
    • 更新dom
  • useMemo
    • 作用:在渲染过程中缓存计算结果,以便在每次渲染时都重新计算
  • 实现原理
    • useMemo接收两个参数:callback和dependencies依赖数组
    • 存储计算结果,和上一次的依赖数组
    • 如果数组发生变化,重新计算并更新计算结果和依赖数组
    • 如果没有变化,则直接返回上一次计算的结果

React中函数组件如何模仿生命周期(用useEffect)

  • componentDidMount
    • useEffect传入一个空数组
  • componentDidUpdate
    • useEffect传入第二个参数,用于监听依赖项的变化
  • componentWillUnmount
    • useEffect返回的函数会在组件卸载时执行
  • shouldComponentUpdate
    • 可以使用React.memo对props进行比较

jsx和js的区别

  • 标签嵌套
    • jsx允许在js中嵌套html标签
  • 插值表达式
    • jsx支持通过花括号将js表达式插入到jsx中
  • 类名和属性命名不同,避免与js关键字冲突
    • 使用className代替class
    • 使用htmlFor代替for,

babel处理jsx的原理

  • 解析
    • 将jsx代码分解为标记,构建出一个对应的ast
    • ast能够表示源代码的结构和语法
  • 转换
    • 将jsx语法转换为普通的js代码
  • 将ast转换为js代码