import{_ as s,o as n,c as a,R as l}from"./chunks/framework.a304f0f7.js";const A=JSON.parse('{"title":"【快手】深入理解前端面试题","description":"","frontmatter":{},"headers":[],"relativePath":"article/【快手】深入理解前端面试题.md","lastUpdated":1682669214000}'),p={name:"article/【快手】深入理解前端面试题.md"},o=l(`

【快手】深入理解前端面试题

快手一面

Vue生命周期

beforeCreate created beforeMount mounted

beforeUpdate updated

beforeDestory destoryed

Vue3移除了beforeCreate created两个声明周期钩子,这是因为setup发生在开始创建组件之前,在beforeCreatecreated之前执行

可以在setup中使用的生命周期函数:onMounted onUpdated onUnmounted onBeforeUpdate这几个,

Vue 生命周期

网络请求一般在什么时候发起,为什么

越早越好,一般是放在createdonMounted或者setup

setup的执行时机相当于哪个生命周期

setup的执行要早于beforeCreatedcreated,可以认为相当于这两个生命周期

Vue2和Vue3的响应式原理

Vue2响应式原理

全部使用Object.defineProperty()中的set与get函数

Vue3响应式原理

ref使用的是Object.defineProperty(),而reactive使用的是Proxy

Proxy可以直接深度代理一个对象,通过设置handler中的捕获器可以对对象创建一个代理,将各种行为监听并且同步到对象本身上

js
const obj = {
  name: 'Ziu',
  age: 18
}
const proxy = new Proxy(obj, {
  set: function (target, key, newVal) {
    console.log(\`监听: \${key} 设置 \${newVal}\`)
    target[key] = newVal
  },
  get: function (target, key) {
    console.log(\`监听: \${key} 获取\`)
    return target[key]
  }
})

Proxy相比于defineProperty有何优势

defineProperty 和 Proxy区别

  1. 监听数据的角度

    1. defineproperty只能监听某个属性而不能监听整个对象。
    2. proxy不用设置具体属性,直接监听整个对象。
    3. defineproperty监听需要知道是哪个对象的哪个属性,而proxy只需要知道哪个对象就可以了。也就是会省去for in循环提高了效率。
  2. 监听对原对象的影响

    1. 因为defineproperty是通过在原对象身上新增或修改属性增加描述符的方式实现的监听效果,一定会修改原数据。
    2. proxy只是原对象的代理,proxy会返回一个代理对象不会在原对象上进行改动,对原数据无污染。
  3. 实现对数组的监听

    1. 因为数组 length 的特殊性 (length 的描述符configurable 和 enumerable 为 false,并且妄图修改 configurable 为 True 的话 js 会直接报错:VM305:1 Uncaught TypeError: Cannot redefine property: length)
    2. defineproperty无法监听数组长度变化, Vue只能通过重写数组方法的方式变现达成监听的效果,光重写数组方法还是不能解决修改数组下标时监听的问题,只能再使用自定义的$set的方式
    3. proxy因为自身特性,是创建新的代理对象而不是在原数据身上监听属性,对代理对象进行操作时,所有的操作都会被捕捉,包括数组的方法和length操作,再不需要重写数组方法和自定义set函数了。(代码示例在下方)

    4. 监听的范围

    1. defineproperty只能监听到valueget set 变化。
    2. proxy可以监听除 [[getOwnPropertyNames]] 以外所有JS的对象操作。监听的范围更大更全面。

Proxy优势

Object.defineProperty优势

兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平。

Object.defineProperty劣势

Vue3数据双向绑定原理

ref与reactive区别与适用场景

js
const obj1 = ref({ name: 'Ziu', age: 18 })
console.log(obj1) // RefImpl
console.log(obj1.value) // Proxy

const obj2 = reactive({
  name: 'Kobe',
  age: 19
})
console.log(obj2) // Proxy

Vue3功能上相比于Vue2有哪些优点

Vue3 对比 Vue2.x 差异性、注意点、整体梳理,与React hook比又如何?

Vue组件传参方法

Vuex异步操作如何同时修改多个state

ES6特性了解哪些

let & const的特性

不存在变量提升 暂时性死区

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

js
var tmp = 123;

if (true) {
  tmp = 'abc';
  let tmp;
}
console.log('tmp =', tmp);

Promise介绍一下

Promise.all .race .any功能及区别

传入的都是一个可迭代对象(iterable),迭代器,类似Array

Promise看代码写结果

js
function testPromise() {
    return new Promise((resolve, reject) => {
        console.log('1');
        resolve(2);
        reject(3);
        console.log('4');
    }).then(res => {
        console.log('res = ', res);
    }, err => {
        console.log('err =', err);
    });
}

testPromise();

输出结果:1 4 res = 2

执行resolve之后,当前Promise的状态变为fulfilled不再改变,即使后面继续调用了reject,后续代码继续执行输出'4',随后执行微任务中的.then,输出res = 2

手写Promise.all()

js
function selfPromiseAll(iterable) {
    return new Promise((resolve, reject) => {
      const promises = Array.from(iterable) // 将可迭代对象转为数组
      const result = [] // 保存结果
      let count = 0 // 记录是否所有promise都执行完毕
      // 并发执行每一个promise
      for (let i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i])
          .then((res) => {
            result[i] = res // 将结果按顺序存入result
            count++
            // 保证每一个Promise都执行完毕后再resolve
            if (count === promises.length) {
              resolve(result)
            }
          })
          .catch((err) => reject(err)) // 只要有reject 外部Promise直接reject
      }
    })
  }
cookielocalStoragesessionStorage
大小4Kb5MB5MB
兼容H4/H5H5H5
访问任何窗口任何窗口同一窗口
有效期手动设置窗口关闭
存储位置浏览器和服务器浏览器浏览器
与请求一起发送
语法复杂简单简单

localStorage常用方法

js
localStorage.setItem('key', value)
localStorage.getItem('key')
localStorage.removeItem('key')
localStorage.clear()

跨域解决方法

JSONP

根据同源策略的限制,在端口,域名,协议这三者一个或者多个不同的情况下,就会出现跨域限制,请求发送到了服务器并且服务器也响应了数据,但是浏览器不会为你展示出来。

但是,<script> 标签访问时,可以跨越这些同源策略限制,但只能使用 GET 方法:

html
<script>
  function jsonCallback(data) {
    console.log(data)
  }
</script>
<script src="https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg"></script>

<script>标签返回的是一段由函数jsonCallback包裹的数据,这样在页面中就可以拿到跨域的数据了

介绍一下事件循环

主线程 宏任务 微任务 EventTable EventQueue

队列检查 函数执行栈 优先级 常见的宏任务/微任务

事件循环代码运行结果

js
setTimeout(() => {
  console.log('time1')
  Promise.resolve()
    .then(() => {
      console.log('promise1')
      process.nextTick(() => {
        console.log('next tick1')
      })
    })
    .catch((err) => {
      console.log(err)
    })
})

setTimeout(() => {
  console.log('time2')
  new Promise((res) => {
    res()
    console.log('promise2')
    process.nextTick(() => {
      console.log('next tick2')
    })
  }).then(() => {
    console.log('promise3')
  })
})

输出顺序: time1 promise1 next tick1 time2 promise2 next tick2 promise3

介绍一下Flex布局

快手二面

CSS主题切换方案

html
<style>
  :root {
    --text-color: #1f1f1f;
    --bg-color: #f5f5f5;
    --primary-color: #1890ff;
  }
  :root.dark {
    --text-color: #f5f5f5;
    --bg-color: #1f1f1f;
    --primary-color: #1890ff;
  }
  .card {
    color: var(--text-color);
    background-color: var(--bg-color);

    padding: 10px;
    max-width: 300px;
    transition: all 0.2s;
  }
  .card h2 {
    color: var(--primary-color);
  }
</style>

<div>
  <button id="dark-mode">Toggle Dark Mode</button>
  <div class="card">
    <h2>跨站脚本攻击(XSS)</h2>
    <p>
      Cross-Site
      Scripting(跨站脚本攻击)简称XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如
      Cookie、SessionID 等,进而危害数据安全。 为了和 CSS 区分,这里把攻击的第一个字母改成了
      X,于是叫做 XSS。
    </p>
  </div>
</div>

<script>
  const root = document.querySelector('html')
  const btn = document.querySelector('#dark-mode')
  btn.addEventListener('click', () => {
    root.classList.toggle('dark')
  })
</script>

Proxy与defineProperty实现数据劫持

深入理解Proxy与Reflect

算法: 两数之和-修改版

从数组中找到两数之和为目标值的数字对数 不允许重复使用数字

js
/**
 * 从数组中找到两数之和为目标值的数字对数 不允许重复使用数字
 * @param {number[]} nums 数组
 * @param {number} target 目标值
 * @returns {number} 次数
 */

function twoSum(nums, target) {
  // 边界情况
  if (nums.length < 2) return 0

  let count = 0
  const map = new Map()

  for (let i = 0; i < nums.length; i++) {
    const num = nums[i]
    const diff = target - num
    const value = map.get(diff) // undefined | number

    // 如果找到了与diff相等的num
    if (value !== undefined && value > 0) {
      count++
      map.set(diff, value - 1) // 剩余数字个数-1
    } else {
      // 未找到 则将num设为键 值为出现次数
      const count = map.get(num) === undefined ? 1 : map.get(num) + 1
      map.set(num, count)
    }
  }

  return count
}

console.log(twoSum([1, 2, 3, 4, 4], 5)) // 2
console.log(twoSum([1, 1, 2, 3, 4, 4], 5)) // 3
`,87),e=[o];function r(t,c,y,F,i,D){return n(),a("div",null,e)}const d=s(p,[["render",r]]);export{A as __pageData,d as default};