第一次面试,被面试官怼着简历框框问项目。。自我总结:要对自己反复拷打!

357 阅读10分钟

前言

先来说说自身成分,本人大三,某双非软件工程专业,从去年10月末学习前端到现在。春招早已开启多日,看着身边大佬逐渐拿到大厂office,自己也不能掉队,从3.14晚上认真(海)投简历到现在才终于拿到一个小厂的面试机会,毕竟人生第一次面试,准备了一晚上结果第二天面试完的时候面试官问我,你了解我们的公司吗?。。。

我:

image.png

自我介绍

万年不变的自我介绍:面试官您好,我叫xxx,就读于xxx,是一名25届软件工程专业的大三学生,想来贵公司参加前端实习生职位的面试。大一、大二的时候自学过一些其他编程语言的知识,例如python ...... 我个人比较喜欢前端,空闲时间里,喜欢在b站里跟着相关视频学习。近些年Chatgpt火了以后,又对AI非常感兴趣......此外,在掘金上写过多篇JS基础和底层相关系列文章。平时主要使用vue,熟悉全家桶开发,看过一点点源码,github上坚持着每日coding和日常学习,未来也会继续坚持并努力着。

1. 讲讲你项目中的账号密码登录的实现

好家伙一上来贴脸开大,画个大饼丢给我,不过这种情况下万变都离不开八股内容,对这问题进行分析不就是 JWT + token + Cookie嘛。

1.1 概念分析

1. JWT(JSON Web Token):JWT是一种用于身份验证和授权的开放标准。它由三部分组成:头部(Header)、负载(Payload)和签名(Signature)。在账号密码登录中,服务器会生成一个JWT并将其发送给客户端作为身份验证凭证。

2. Token:Token是一种用于身份验证的令牌。在账号密码登录中,服务器靠JWT生成一个Token。Token的生成过程通常包括将用户的身份信息(例如用户名、角色等)加密到JWT的负载中,并使用服务器的密钥对其进行签名以防篡改。客户端收到Token后,将其存储在本地,例如浏览器的本地存储或移动设备的Keychain中。

3. Cookie: Cookie是一种存储在客户端的小型文本文件,大小只有4kb左右。在账号密码登录中。客户端收到Token后,会将其存储在浏览器的Cookie中。每次客户端向服务器发送请求时,浏览器会自动将Cookie附加在请求中并发送给服务器,从而实现身份验证。

1.2 登录流程

  1. 客户端将账号密码发送给服务器进行验证。
  2. 服务器校验账号密码成功后,靠JWT来生成一个令牌Token,并返回给客户端。
  3. 客户端收到Token后,将其存储在本地例如 cookie 或 localStorage 里。
  4. 客户端在以后的请求中,会将Token附加在请求头中发送给服务器。
  5. 服务器接收到请求时,验证Token有效性,若验证通过,则返回相应的数据。

image.png

1.3 token特点

  • 无状态性:服务器无需记录用户的登录状态,因为Token本身包含了所有必要的信息。
  • 可扩展性:Token可以存储更多的用户信息,例如权限、角色等。
  • 安全性:Token通常使用密钥进行签名,防止被篡改和伪造。

2. 讲讲 LocalStorage、Cookie、SessionStorage

特性大小限制自动发送安全性使用场景存储有效期
Cookie通常限制为4KB每次请求自动发送给服务器可能受到XSS和CSRF攻击身份认证、持久登录可设置过期时间,可以是会话级别(浏览器关闭后自动删除)
LocalStorage通常为5MB - 10MB相对较安全持久性数据存储永久有效,除非手动删除
SessionStorage通常为5MB - 10MB相对较安全临时数据存储页面会话期间

3. 了解 XSS、CSRF 攻击吗

  1. XSS 攻击

    • 概念:XSS 是一种常见的网络安全漏洞,攻击者通过在网页中注入恶意脚本,从而使用户在浏览器端执行恶意代码,达到窃取用户信息、会话劫持等恶意目的。
    • 防范措施:对用户输入数据进行合适的过滤与转义,使用内容安全策略(CSP),避免直接使用 eval() 等不安全的函数等。
  2. CSRF 攻击

    • 概念:CSRF 是指攻击者利用用户已登录的身份,在用户不知情的情况下伪造请求,以用户的名义发送恶意请求,如更改账号信息、发起转账等。
    • 防范措施:使用 CSRF Token 防护机制,在关键操作中要求验证用户身份或采用双重提交 cookie 策略等来防止 CSRF 攻击。

4. Cookie 过期失效怎么办

  1. 前端处理:在前端可以监测Cookie的过期时间,一旦Cookie过期,可以清除过期的Cookie并提示用户重新登录或执行其他必要的操作。

  2. 后端处理:在服务器端验证Cookie的有效性,如果发现Cookie已经过期,可以要求用户重新登录或执行相关的身份验证流程。

  3. 刷新Token:对于身份验证相关的Cookie,可以考虑使用刷新Token的机制,即在Cookie快要过期时,通过特定的接口请求获取新的Token,并更新Cookie中的Token值,从而延长用户的登录状态。

  4. 提醒用户:在用户登录时或者Cookie快要过期时,可以向用户发送提醒消息,告知他们需要重新登录或者更新Cookie以维持登录状态。

5. 如何隐藏页面元素

样式文档流响应事件回流重绘
display: none脱离文档流无法响应事件回流重绘
visibility: hidden占据文档流无法响应事件重绘
opacity: 0占据文档流响应事件重绘或不重绘
position: absolute脱离文档流无法响应事件回流重绘
clip-path: circle(0%)占据文档流无法响应事件重绘

6. css选择器有哪些,优先级呢?

  1. id选择器
  2. 类名选择器
  3. 标签选择器
  4. 后代选择器
  5. 子级选择器
  6. 相邻兄弟选择器
  7. 群组选择器
  8. 属性选择器
  9. 伪元素选择器
  10. 伪类选择器

优先级:!important > 内联( style="color: red;" ) > id选择器 > 类名选择器 > 标签选择器

这个想详细了解的话可以看下本人以前文章:css选择器及优先级

7. 讲讲v-for的key

当使用 v-for 指令来渲染列表时,通常每个项提供一个唯一的 key 属性作为标识符,来追踪每个节点的身份,从而在进行 DOM diff 比较时能够更高效地更新虚拟 DOM。在列表发生变化时(例如增删元素),如果每个项有唯一的 key,Vue.js 就能够正确识别每个项的状态,并保留正确的状态信息。这对于表单输入、动画等场景特别重要。如果没有提供 key,Vue.js 可能会采取一种更低效的方式来重新渲染列表。尽量避免使用数组索引作为 key,因为当数组插入删除等操作变更数组下标时可能会导致一些错误。

8. 讲讲Map和forEach区别

forEach 主要用于遍历数组并执行操作,而 Map 则更适合用于对数组中的每个元素进行处理并返回一个新数组。

// 使用forEach遍历数组
const numbers = [1, 2, 3, 4];
numbers.forEach(num => {
    console.log(num * 2); // 输出: 2, 4, 6, 8
});

// 使用Map处理数组
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // 输出: [2, 4, 6, 8]

9. 防抖节流

  • 防抖: 在一定的时间内, 不管点击多少次, 只会触发一次
  • 节流: 例如每次点击间隔超过一秒钟只触发一次
<!DOCTYPE html>
<body>
    <button id="btn">提交</button>

    <script>
        let btn = document.getElementById('btn')
        
        btn.addEventListener('click',debounce(handle, 1000))
        //btn.addEventListener('click',throttle(handle, 1000))

        function handle(e){ 
            console.log('点击了按钮');
        }

        // 防抖: 在一定的时间内, 不管点击多少次, 只会触发一次
        function debounce(fn, wait){
            let timer = null
            return function(...arg){
                // 销毁上一次的定时器
                clearTimeout(timer)
                timer = setTimeout(() => {
                    fn.call(this, ...arg)
                }, wait)
            }
        }

        // 节流: 每次点击间隔超过一秒钟只触发一次
        function throttle(fn, wait){
            let lastTime = Date.now() // 最开始点击的一次
            return function(...arg){
                let nowTime = Date.now() // 当前点击的时间
                if(nowTime - lastTime > wait){
                    fn.call(this, ...arg)
                    lastTime = nowTime
                }
            }
        }
    </script>
</body>
</html>

10. 数组去重

这题当时问我的时候我还愣了一下,因为前天下午本人就正好做了一道字节的数组去重,我还问了面试官数组里面都是数字吗,面试官说是,那这题就是考察Set方法或者遍历数组。

let array = [1, 1, 2, 3, 1, 9, 10, 3, 2]
//Array.from()接收一个可迭代对象,返回一个新的数组实例,将得到的 Set 集合转换为一个新的数组。
let newArr = Array.from(new Set(array))  
// 解构方法
let newArr1 = [...new Set(array)]        
console.log(newArr)   // 输出:[1, 2, 3, 9, 10]
console.log(newArr1)  // 输出:[1, 2, 3, 9, 10]

// 循环方法
let newArr2 = []
array.forEach((num)=>{
    if(!newArr2.includes(num)){
        newArr2.push(num)
    }
})
console.log(newArr2) // [1, 2, 3, 9, 10]

如果有uu想要了解数组里面不只有数字的话可以来看看这篇,难度拉满: 这是来自字节俩道面试题。。。汗颜

11. 项目里的验证码如何实现

我简历里写的是一个电商的项目,因为是两个面试官问我,这时候换了另外一个面试官,拿着我的简历又框框问起了我简历里面的项目。。。

12. 讲讲如何实现添加购物车操作

我这里用的是pinia状态管理工具以及计算属性来实现,然后又被框框问。。。

13. 讲讲计算属性和watch

computed计算属性,通过对已有的属性值进行计算得到一个新值,是基于它们的依赖进行缓存的。计算属性值会被缓存,只有当依赖数据发生变化时才会重新计算,这样可以避免重复计算提高性能。

watch用于监听数据的变化,定义需要监视的数据,它可以监听单个数据或者数组,并指定回调函数来执行特定的操作。computed不同的是watch不会有缓存。

14. 讲讲你对pinia的认识

为什么要用 Pinia

  • Pinia 提供了一种更直观和简洁的方式来管理应用状态,相对于 Vuex,代码量更少,更易读和维护。
  • 使用 Composition API 可以使状态管理逻辑更加清晰,提高可读性和可维护性。
  • Pinia 支持插件系统,可以根据项目需求来引入插件扩展功能,例如异步状态、状态拦截等。
  • 开发者可以使用 Composition API 中提供的函数式编程风格来定义和操作状态。
  • 更好的支持TypeScript。

与Vuex相比,Pinia的优势

  • 基于 Composition API,对vue3开发者友好
  • 更友好的支持TypeScript
  • 不再需要mutation,因为action既支持同步也支持异步
  • 不再有modules
  • 不再有命名空间的概念,不需要记住复杂的关系

总结

感觉小公司对项目这方面能力很看重,怼着项目框框问,真汗流浃背了,反倒是八股问的很简单,虽然这是我第一次面试,自我感觉还行,但是我看到别人的发面腾讯的考题,觉得自己还是需要反复拷打......

9ae2f5151410289824ca4f1b72f459d0.jpg