likes
comments
collection
share

字节跳动面试经历,这一篇缓解你的紧张

作者站长头像
站长
· 阅读数 9

最近试着投了一下字节,真是被自己惊到了,通知面试后就开始睡不着了,赶紧拿上我的项目开始复盘,时间过得久了点,都忘了。也试着搜了一些字节的面试文章,不过我面的实习生,面试相对于简单一些。 还是挂了。

字节跳动面试经历,这一篇缓解你的紧张

老规矩,面试官上来就是介绍了面试流程,自我介绍放第一,下一步就是面试官拿着我的简历提问了,最先问的就是简历里面对项目的介绍了。

为什么要用jwt建立token

我项目里面是把token放在了localstorage,所以问我这个,后续我还会写一篇关于token的文章好好介绍一下。

JSON Web Token(jwt)是一种开放标准,用于在网络应用环境间安全的传递声明。他定义了一种紧凑且自包含的方式,用于作为JSON对象,在各方之间安全的传输信息。这些信息可以被验证和信任,因为他们是经过数字签名的。jwt通常用于身份认证和信息交换。 一般来说答到这些就OK了,下面这些优点是你自己可以扩展给面试官听的。

优点

紧凑和自包含

  1. 紧凑性:jwt是一个紧凑的URL安全字符串。它由头部、载荷和签名组成。这使得它非常适合通过HTTP头或URL参数传递。
  2. 自包含性:jwt内部包含了所有必要的信息,验证方可以直接从jwt本身获取声明信息,无需额外查询数据库,从而提高了效率。

支持跨语言

jwt标准被广泛支持,几乎所有流行的编程语言都有jwt的实现库,这使得jwt非常适合构建跨平台,跨语言的认证和数据交换系统。

安全性

  1. 数字签名:jwt可以使用对称加密(密钥)或非对称加密(公钥/私钥)进行签名,确保了传输过程中信息的完整性和防篡改。
  2. 加密:还可以进一步加密保护数据的机密性。

易于使用

无状态和可扩展性:jwt设置为无状态,服务器不需要保存任何会话信息即可完成认证,这意味着jwt非常适合微服务、分布式系统和单页面应用,可以轻松扩展。

高效的权限控制

携带信息:jwt可以在负载中携带足够的信息,如用户角色、权限等。这使得实现细粒度的访问控制变得简单有效。

值得一提的是:尽管jwt有很多优点,但是也要注意一下安全问题,比如保护好密钥,避免泄露敏感信息,以及合理设置token的过期时间等,以确保token的过期时间等,以确保系统安全性。

token过期时间

jwt的过期时间可以通过exp(Expiration Time)声明来控制。exp是一个时间戳,表示Token的过期时间。当Token被验证时,如果当前时间超过了exp声明的时间,则认为Token已经过期。在Token被创建的那一刻起的一段时间。

回答上来这些面试官绝对还会深入地了解,比如:你会把token存在哪里,这个token可以是前端存,后端也可以规定存哪里。我是存在localstorage,接下来就是面试官开始问了。

localstorage存储的有效期?localstorage存储的上限?

有效期

一般localstorage的存储时间是永久的,需要通过代码或者用户手动清除,可以设置token过期时间。

用户手动清除可以在浏览器的控制台输入localStorage.removeItem('key');key为键名,或者直接localStorage.clear();清除所有数据。

存储上限

这每个电脑的浏览器一般会有差异,一般在5MB~10MB左右,可以检查浏览器的API来查看当前网站的存储空间。

你答出来了localStorage这些问题,好,那该继续往下了。不问倒你面试官面子上挂不住。所以不要害怕面试官会问的你差点去世。

你了解CSRF攻击吗?

问道我这个我是真的会谢,面试官你看我像csrf吗?我一个前端实习生我怎么会知道网络攻击,没办法,谁让他是面试官呢。查了资料才发现这个网络攻击在浏览器存储方面还是蛮出名的,特别是对于token存储在cookies里面的。

介绍

CSRF攻击会利用用户已经登陆的身份,在用户不知情的情况下执行非法操作,就比如:用户在A网站登陆后,他访问了B网站,B里面有针对A的CSRF网络攻击,那B就利用用户的登陆状态去发送伪造请求访问A,B就可以篡改用户的身份信息甚至是进行转账操作。

CSRF攻击之所以有效,是因为浏览器在发送跨站请求时会自动携带用户在目标网站的认证信息(比如cookie),而用户在未登出的情况下访问恶意网站时,这些认证信息就会被滥用。

防范操作

为了防范CSRF攻击,网站可以采取以下措施:

  1. 使用CSRF Token:在表单提交或者请求参数中加入CSRF Token,该Token由服务器生成,每次请求时需要携带,恶意网站无法获取到合法的Token,从而无法进行伪造请求。
  2. 同源策略:通过同源策略限制网站对其他来源的请求访问,防止恶意网站利用用户的身份进行跨站请求伪造。
  3. 验证Referer字段:检查请求的Referer字段,确保请求是从合法的来源发起的。

cookies,sessionstorage和localstorage存储token的区别?

我都没有用过其他的存储方式,现在算是了解了,我是真没想到面试官问我这个

  1. cookies
  • 特点:可以设置token过期时间,客户端和服务端都可以修改。
  • 安全性:容易受到CSRF攻击。
  • 用途:主要用于跟踪用户会话,存储用户偏好设置以及实现永久登陆等功能。
  1. sessionstorage
  • 特点:只要关闭网站页面标签或关闭浏览器就需要重新登陆,因为数据会被清除,刷新不会导致重新登陆。
  • 安全性:安全性较高,不容易受CSRF攻击。
  • 用途:适合临时存储会话数据,比如临时保存表单数据等。
  1. localstorage
  • 特点:LocalStorage 是持久化存储机制,数据在浏览器关闭后仍然保留,除非显式删除。数据在同源的所有窗口、标签页中均可共享。
  • 安全性:不容易受到CSRF攻击,但可能受到XXS(跨站脚本攻击)影响
  • 用途:主要用于跟踪用户会话,存储用户偏好设置以及记住登陆状态等功能。

原生js进行开发和vue的区别

这个问题我相信大家都能答出来,因为只需要简单描述一下就可以了

首先就说:使用原生 JavaScript 进行开发更加灵活,适合小型项目或者对基础知识要求较高的开发者;而使用 Vue.js 可以提高开发效率,降低代码量,适合构建中大型应用和团队协作开发。

然后就是为什么了:

  1. 原生 JavaScript

    • 手动管理 DOM:使用原生 JavaScript 需要手动管理 DOM 元素的创建、更新和删除,包括事件处理、数据绑定等,编写的代码相对较多。
    • 复杂性:在大型应用中,使用原生 JavaScript 编写会变得繁琐和难以维护。
    • 灵活性:原生 JavaScript 提供了更大的灵活性和自由度,可以根据需求选择合适的解决方案和实现方式。
  2. Vue.js

    • 数据驱动:vue采用了响应式数据绑定和虚拟 DOM 技术,使得开发者可以更轻松地实现数据驱动的页面更新。
    • 组件化:将页面拆分成多个可复用的组件,提高了代码复用性和开发效率。
    • 声明式编程:通过简单的模板语法即可描述页面的结构和交互,使得代码更易读、易维护。
    • 生态系统:Vue.js 拥有丰富的生态系统,包括路由、状态管理、UI 组件库等,为开发者提供了丰富的工具和插件支持。

原生js更加复杂,要实现vue那种响应式数据绑定更新DOM和实现路由很复杂,当有重复的DOM结构无法和vue一样封装组件,也用不了vue的UI组件来简化代码。但是写简单页面更加灵活,一个简单的页面也使用vue那简直就是杀鸡用牛刀了。

vue中的生命周期有哪些?

面试官只问我有哪些。这个文章我也没写,大家可以到官方文档去看,也可以看其他人的文章,可能我后续也会写一篇。

vue组件父子组件当中的通讯方式? vuex传值的底层原理

这里我总结的方法不多,面试官告诉我蛮多方式实现父子组件通信,多了解几个多一份机会。

vue父子组件通信

  1. Props:父组件中通过 props 将数据传递给子组件,子组件用props接收。defineProps是为了得到完整的类型推导支持。但是也有个缺点就是没有给props默认值,所以提供了一个default方式。

  2. Emit:用于在子组件中触发并发送自定义事件给父组件的函数。在组合式可以使用defineEmit实现。

  3. $attrs$listeners:v-bind="attrs"v−on="attrs" v-on="attrs"von="listeners"写入子组件的标签,子组件

<!-- ChildComponent.vue -->
<template>
  <div>
    <h3>{{ $attrs.title }}</h3>
    <button @click="$listeners.customEvent">触发自定义事件</button>
  </div>
</template>

<script>
export default {
  mounted() {
    console.log('Parent method:', this.$attrs.parentMethod);
  }
};
</script>

  1. Provide / Inject:祖先组件可以使用provide提供数据,provide使用键值对的方式传入,可以使用对象传多个数据。子组件使用inject接收数据。
  2. Vuex: 使用 Vuex 进行状态管理,可以方便地实现父子组件之间的通讯。
  3. 插槽(Slots): 父组件可以通过插槽将内容传递给子组件,实现灵活的组件内容分发。
  4. Refs:通过在子组件标签创建 ref 对象,在父组件中通过this.$refs.对象...调用子组件方法。(vue3弃用)
  5. Custom Event:在子组件中通过创建自定义事件,然后在父组件中监听这些事件来实现父子组件的通信。 既然说到了vuex父子组件传值,那么该涉及到vuex传值的底层原理

vuex底层原理

  1. state:类似于vue的data,state是响应式的。
  2. getters:类似于computed,可以从store获取数据,对state进行计算和筛选。
  3. mutations:类似于methods,唯一可以修改state的地方,每个 Mutation 都有一个字符串的事件类型(type)和一个回调函数,这个回调函数即是实际修改 State 的地方。
  4. actions:用dispatch触发,其实和mutations功能差不多,就是用来处理异步,就是需要提交给mutation。
  5. modules:Modules 允许将 Store 分割成模块,每个模块拥有自己的 State、Getters、Mutations 和 Actions。这样可以更好地组织和管理大型应用的 State。

防抖节流的区别 ?手写防抖节流

图片懒加载 怎么判断图片进入可视区

图片加载失败如何补救

还真是逮住一直问,面试官说alt非常没用的,用这个影响用户体验

监听图片的error事件,图片加载不出来就将默认图片加载出来

const lazyImages = document.querySelectorAll('.image');

const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const lazyImage = entry.target;
        lazyImage.style.backgroundImage = `url(${lazyImage.getAttribute('data-src')})`;
  
        // 停止观察已经进入可视区域的图片
        observer.unobserve(lazyImage);
      }
    });
  }, { rootMargin: '0px 0px 50px 0px' });//上右下左,提前50px加载图片。

lazyImages.forEach(image => {
    observer.observe(image);
  
  // 监听图片加载失败事件
    image.addEventListener('error', () => {
      // 图片加载失败时显示默认图片或者错误信息
      image.style.backgroundImage = `url('default-image.jpg')`;
      // 或者显示错误信息
      // image.textContent = 'Failed to load image';
    });
  });

如何做水平垂直居中,如何设置1:2:1的布局?

原生js无序列表只绑定一个点击事件

原生js我了解确实不多,特别是这种方法

太多表单项都绑定点击事件会大大的降低性能,所以我们得考虑只绑定一个,然后监听到点击的那个li。

event事件是js自带的事件对象,可以获取触发事件的目标元素、事件类型、鼠标位置等信息,还可以阻止事件默认行为、停止事件传播等。

<body>
    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <!-- 更多的 <li> 元素 -->
      </ul>
      
      <script>
      // 获取父级元素
      const list = document.getElementById('myList');
      
      // 绑定点击事件到父级元素
      list.addEventListener('click', function(event) {
        // 检查点击的目标元素是否是 <li> 元素
        if (event.target.tagName === 'LI') {
          // 在控制台输出被点击的文本内容
          console.log(event.target.textContent);
          
          // 执行其他的点击事件处理逻辑
          // ...
        }
      });
      </script>
      
</body>


算法题

第一个规定使用深度优先搜索,我麻了,我这个算法都不会用。

深度优先搜索

字节跳动面试经历,这一篇缓解你的紧张

function dfs(node) {
    // 输出当前节点的值
    console.log(node.value);
    
    // 遍历当前节点的子节点
    for (let child of node.children) {
      // 对每个子节点递归执行深度优先搜索
      dfs(child);
    }
  }
  
  // 调用深度优先搜索函数,从根节点开始
  dfs(rootNode);

不知道什么算法

这个纯纯硬输出 字节跳动面试经历,这一篇缓解你的紧张

function formatNumber(number) {
    // 判断是否为负数
    const isNegative = number < 0;
    
    // 将数字转换成字符串并去掉负号
    let numStr = Math.abs(number).toString();
    
    // 分割整数部分和小数部分
    let parts = numStr.split('.');
    let intPart = parts[0];
    let decimalPart = parts[1] || '';
    
    // 对整数部分添加千分位分隔符
    let formattedIntPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    
    // 组合整数部分和小数部分
    let result = formattedIntPart;
    if (decimalPart.length > 0) {
        result += '.' + decimalPart;
    }
    
    // 添加负号(如果是负数)
    if (isNegative) {
        result = '-' + result;
    }
    
    return result;
}

总结

这次面试真的收获蛮多的,试一下大厂面试后面真的不会紧张,多多面试提升一下心理素质,虽然我前面紧张,但是面试的时候很放松,面试官脾气都是很好的,就是可能会问的你头皮发麻。

加我微信可以好好交流一番:w1812952400。

转载自:https://juejin.cn/post/7344274333889953819
评论
请登录