logo
blog
readme
Back to Blog
Back to Blog
Back to Blog

‌

‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌
‌

© 2025 linzhe. All rights reserved.

TODO:编辑

面试八股文

性能优化

  • 前端缓存(强缓存和协商缓存)

  • webpack gzip压缩(compression-webpack-plugin),gzip有着比zip更优秀的压缩算法,可以有效的减少文件的大小。

  • 减少重排和重绘

    • 假设初始布局发生在返回图像之前。由于我们没有声明图像的尺寸,因此一旦知道图像的尺寸,就会出现重排,所以要给图片的width和height
  • script的async和defer

    html
    <script>
      // 为什么要在最后添加script标签
      // 避免js操作dom失效
      const x = document.getElementById('x')
      console.log(x) // null
    </script>
    <div id="x" style="background: #f00; width: 100px; height: 100px"></div>
    <script>
      // 在执行完js之前,整个页面都不会渲染,是“空白”的
      let startTime = Date.now()
      let endTime = startTime + 3000 // 3秒后结束
    
      while (Date.now() < endTime) {
        // 模拟一些操作
      }
    
      console.log('3秒已到,循环停止。')
      // 就会渲染页面了
    </script>
    

    如果这个js内容的执行时机不重要,可以把这个耗时的操作<script defer src="./foo.js"></script>,用defer修饰下,让他不阻塞渲染和解析

    js
    foo.js
    let startTime = Date.now()
    let endTime = startTime + 3000 // 3秒后结束
    
    while (Date.now() < endTime) {
      // 模拟一些操作
    }
    
    console.log('3秒已到,循环停止。')
    
  • 懒加载

  • 代码拆分,动态import

webpack打包优化

详情

声明提升

function 关键字的声明和赋值都提升函数写在后面也能调用,var 关键字声明提升,赋值不提升。 let, const, class 标识符提升,形成死区,声明和赋值都不提升。

js
console.log('xxxx', x) // undefined
var x = 1
// 即var x会声明提升,就是下面的效果,先var x,在打印,在对x赋值所以是undefined
var x
console.log('xxxx', x) // undefined
x = 1

say()
// 声明和赋值都提升
function say() {
  console.log('hi~')
}

浏览器工作原理

详情

  • 在渲染到屏幕上面之前,HTML、CSS、JavaScript 必须被解析完成。
  • 当解析器发现非阻塞资源,例如一张图片,浏览器会请求这些资源并且继续解析。当遇到一个 CSS 文件时,解析也可以继续进行, 但是对于 <script> 标签(特别是没有 async 或者 defer 属性的)会阻塞渲染并停止 HTML 的解析。
  • 等待获取 CSS 不会阻塞 HTML 的解析或者下载,但是它确实会阻塞 JavaScript,因为 JavaScript 经常用于查询元素的 CSS 属性

项目亮点/展开聊聊

  • 封装了业务组件库(vue + setup + private npm),主要提供基于elementui二次封装和vue的v-bind、v-on指令并且属性配置就是类json schemaform、dialog、table、layout、scss 变量的theme主题基于element官方的nodejs库。

  • 通过脚手架的cli,提供业务通用(crud)模板的最佳实践,用于快速创建一致性的页面。

  • 由于业务原因,使用vue的install注册全局组件,所以需要对组件名称进行检测,防止重名,所以我们提供了一个eslint的插件。

  • 对于破坏性的组件库升级,提供babel的脚本,用于快速migration,更加方便,减少业务开发人员的工作量,也减少出错。

    就是利用babel parse对应的js文件的到ast,然后traverse这个ast对于的各个节点,进行rewrite。 比如一个简单的例子,一些替换函数名称,新增函数参数(这只是个思路,具体业务具体分析)

    js
    // => old
    import { oldFunc } from 'your-lib'
    
    const result = oldFunc('a', 'b')
    // => to new
    import { newFunc } from 'your-lib'
    
    const result = newFunc('a', 'b', true)
    
    js
    const fs = require('fs')
    const path = require('path')
    const parser = require('@babel/parser')
    const traverse = require('@babel/traverse').default
    const generate = require('@babel/generator').default
    const t = require('@babel/types')
    
    const sourceCode = fs.readFileSync('./example.js', 'utf-8')
    
    const ast = parser.parse(sourceCode, {
      sourceType: 'module',
      plugins: ['jsx', 'typescript'],
    })
    
    traverse(ast, {
      ImportDeclaration(path) {
        if (path.node.source.value === 'your-lib') {
          path.node.specifiers.forEach((spec) => {
            if (t.isImportSpecifier(spec) && spec.imported.name === 'oldFunc') {
              spec.imported.name = 'newFunc'
              spec.local.name = 'newFunc'
            }
          })
        }
      },
    
      CallExpression(path) {
        const callee = path.node.callee
        if (
          t.isIdentifier(callee, { name: 'oldFunc' }) ||
          t.isIdentifier(callee, { name: 'newFunc' }) // 已替换也处理
        ) {
          // 替换函数名
          callee.name = 'newFunc'
    
          // 添加一个布尔类型参数 true(如果没有)
          if (path.node.arguments.length === 2) {
            path.node.arguments.push(t.booleanLiteral(true))
          }
        }
      },
    })
    
    const output = generate(ast, {}, sourceCode)
    fs.writeFileSync('./example.migrated.js', output.code)
    
    console.log('✅ Migration complete.')
    

为什么离职

我上一份工作的内容是 XXX,在那段时间里我收获了很多,也积累了扎实的 YYY 经验。 不过在后期我也发现,这份工作在技术成长和挑战性方面已经相对稳定,而我本身是一个比较喜欢学习和探索的人, 所以希望能寻找一个更有发展空间、能够接触新技术并参与到关键项目的团队。我觉得贵公司在这方面非常契合我的预期。

你为什么值这份薪资

我的上一份薪资是??,当时是基于我当时的经验和岗位要求定的。而在这段时间里,我不仅独立承担了多个完整的模块开发,也逐步参与了系统架构优化、性能调优和一些跨团队协作的工作,整体的技术深度和广度都有明显提升。 比如在某个项目中,我通过 XXX 的优化手段,把首页加载时间从 3.2s 优化到 1.8s,用户留存率提升了明显,这类工作也让我意识到,我的输出是可以给业务带来实在价值的。 结合市场行情和我对岗位的理解,我认为 ?? 是一个比较合理的匹配,当然我也更看重的是未来的成长空间和团队氛围。

我看你提交了一些VUE相关的pr,你能说说在这个过程中,你学到了什么吗?并落地到实际项目

就那vue3.5来说,vue提供了一个新的hook:useTemplateRef,但公司有些项目还是vue2.7,所以我根据vue3.5的源码,实现了 一个类似的功能,主要是为了方便在vue2.7中使用ref来获取组件实例或DOM元素。

js
import { getCurrentInstance, shallowRef } from 'vue'

export function useTemplateRef(key) {
  const vm = getCurrentInstance().proxy
  if (!vm) {
    throw new Error(
      `useTemplateRef() is called when there is no active component ` +
        `instance to be associated with.`
    )
  }
  const refs = vm.$refs
  const r = shallowRef(null)
  Object.defineProperty(refs, key, {
    get() {
      return r.value
    },
    set(newValue) {
      r.value = newValue
    },
  })
  return r
}

我看你提交了一些VUE相关的pr,能说说解决了什么问题吗?

详情: