面试题

75 阅读6分钟

盒子模型

CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。

image.png

不同部分的说明:

  • Margin(外边距) - 清除边框外的区域,外边距是透明的。
  • Border(边框) - 围绕在内边距和内容外的边框。
  • Padding(内边距) - 清除内容周围的区域,内边距

深拷贝

  • 浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象
  • 深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

深拷贝方法

1、JSON.parse(JSON.stringify(obj1))

2、loadsh cloneDeep

scoped实现原理

通过给组件中DOM元素和CSS各自都添加一个相同且唯一的属性选择器,让当前的css文件的样式只对当前组件生效

编译后的代码

<template>
   <div class="container" data-v-mlxsojjm></div>
 </template>
.container[data-v-mlxsojjm] {      
    width: 100px;      
    height: 100px;      
    background-color: red;  
}

rgb转为16进制

/**
 * 16进制颜色值转RGB
 * @param  {String} hex 16进制颜色字符串
 * @return {String}     RGB颜色字符串
 */
  function hexToRGB(hex) {
    var hexx = hex.replace('#', '0x')
    var r = hexx >> 16
    var g = hexx >> 8 & 0xff
    var b = hexx & 0xff
    return `rgb(${r}, ${g}, ${b})`
}

/**
 * RGB颜色转16进制颜色
 * @param  {String} rgb RGB进制颜色字符串
 * @return {String}     16进制颜色字符串
 */
function RGBToHex(rgb) {
    var rgbArr = rgb.split(/[^\d]+/)
    var color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3]
    return '#'+ color.toString(16)
}
// -------------------------------------------------
hexToRGB('#ffffff')               // 'rgb(255,255,255)'
RGBToHex('rgb(255,255,255)')      // '#ffffff'

设计模式

观察者模式

发布-订阅模式

vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调

image-20210814222804385.1cd869f8.png

image.png

事件循环

事件循环的事件阶段主要包括:宏任务(Macro Task)/主任务队列、微任务(Micro Task)队列、UI渲染、下一个宏任务。

事件循环的过程概括为:执行一个宏任务 -> 执行所有微任务 -> UI渲染 -> 执行下一个宏任务

image.png

任务队列的执行流程可概括为:

  1. 同步任务在主线程排队执行,异步任务在事件队列排队等待进入主线程执行。
  2. 遇到宏任务则推进宏任务队列,遇到微任务则推进微任务队列。
  3. 执行宏任务,执行完毕后检查当前层的微任务并执行。
  4. 继续执行下一个宏任务,执行对应层次的微任务,直至全部执行完毕。

**这个流程确保了异步任务能够在适当的时机插入执行,保持程序的高效性和响应性。

javascript
 代码解读
复制代码
console.log(1);

setTimeout(() => {
    console.log(2);
}, 0);

console.log(3);

new Promise((resolve) => {
    console.log(4);
    resolve();
    console.log(5);
}).then(() => {
    console.log(6);
});

console.log(7);

执行顺序解析:1 => 3 => 4 => 5 => 7 => 6 => 2。

  1. 创建Promise实例是同步的,所以1、3、4、5、7是同步执行的。
  2. then方法是微任务,放入微任务队列中,在当前脚本执行完毕后立即发生。
  3. 同步任务执行完毕后,执行微任务队列中的微任务。
  4. 最后,setTimeout放入宏任务队列,按照先进先出的原则执行。

注意:出现asyncawait,等价于promisethen

image.png

异步渲染 nexttick

  • nextTick 是为了确保在 DOM 更新完成之后执行回调,用于访问最新的 DOM 状态。

  • 它的底层原理是利用事件循环机制,将回调函数推入微任务(或宏任务)队列中延迟执行。、

  • queueWatcher 通过去重与调度合并机制,避免重复更新,提升性能。

  • 本质上,Vue 利用 nextTick 实现了异步更新策略与高效的视图渲染调度。

事件流

当一个事件在页面中的某个元素上被触发时,比如用户点击了一个按钮或者按下了一个键盘按键,这个事件不会仅仅局限于被触发的元素本身,而是会按照一定的顺序在 DOM 树中流动,这个流动的过程就是事件流。

事件冒泡: 事件开始时有具体的元素接收,然后逐级向上传播到DOM最顶层结点过程

目标阶段: 到达的具体元素

事件捕获: 由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程

image.png

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #a {
      width: 400px;
      height: 400px;
      background-color: rgb(245, 56, 13);
    }

    #b {
      width: 200px;
      height: 200px;
      background-color: rgb(27, 140, 238);
    }

    #c {
      width: 100px;
      height: 100px;
      background: pink;
    }
  </style>
</head>

<body>
  <div id="a">a
    <div id="b">b
      <div id="c">
        c
      </div>
    </div>
  </div>

  <script>
    let a = document.getElementById('a')
    let b = document.getElementById('b')
    let c = document.getElementById('c')

    a.addEventListener('click', () => {
      console.log('a被点击');
    })

    b.addEventListener('click', () => {
      console.log('b被点击');
    },)

    c.addEventListener('click', () => {
      console.log('c被点击');
    })
    
  </script>
</body>

</html>

作者:Kousi  
链接:https://juejin.cn/post/7450293472983482422  

是由于三个点击事件都在冒泡阶段触发,addEventListener方法是能够接受三个参数的,分别为事件类型、回调函数、冒泡(false)or捕获(true)。当我们没有对addEventListener传递第三个参数时,默认是false,也就是事件默认在冒泡阶段触发。

捕获阶段

当我们将第三个参数填入true时,会将该事件改造为在捕获阶段才执行

a.addEventListener('click', () => {
      console.log('a被点击', true);
    })

    b.addEventListener('click', () => {
      console.log('b被点击');
    },)

    c.addEventListener('click', () => {
      console.log('c被点击');
    })

当我们依旧点击c盒子时,此时打印结果是首先打印了a盒子,同样的由上图的事件流过程可知,首先进入捕获阶段,此时a盒子已经被捕获到了,因此是第一个被打印的。

首先捕获阶段,然后冒泡阶段

事件委托

事件委托也称为事件代理。就是利用事件冒泡,把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托就无法实现。

vue2数据双向绑定原理,和Vue3有啥区别