年前的一些面经,悬着的心终于死了(7137字)

31,682 阅读24分钟

如果你也在准备春招,欢迎加微信shunwuyu。这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。

前言


微信图片_20240221204730.jpg 2024.1.20 ~ 2024.2.18

348(沟通数)/45(简历数)/7(面试数)

点击就看双非废物投递简历,悬着的心终于吊死了

6096b5cbda417kQj.gif

年前投的大多是小厂,目标城市也是比较散,这个时候还在想着找个远程实习,春招好找中大厂。这个月一共面了七次(有两个面完才知道是外包,两个远程),大概沟通到40多次的时候有了第一次面试。

其实,真实面试的时候比我自己想象的要好,面试之前以为面试会很紧张,答不上来气氛会很凝重,面完我都觉得面试官很温柔,大概都在30分钟到50分钟左右,比较重要的是自我介绍,很多问题都是面试官从你自己的介绍里问的,尤其是项目,因为一讲到项目面试官都开始唰唰做记录。第一次面试的时候也没准备,三言两语介绍了自己就过去了,当然也是理所当然的寄了。

这样面下来,还是有比较大的提升,一个是不紧张了,发挥越来越稳定;一个是隐隐感觉到了什么叫用简历和自我介绍引导面试官问什么问题。

总的感觉是:

面试结果 = 简历 + 个人介绍 + 八股文 + 控场。

七个面试,虽然都是很小的公司,还是有一两个过了,现在想想,当时的自我介绍是很拉跨的,项目也没啥亮点,可能年前临时缺人,所以二月初我就远程实习了,120一天,还是蛮不错的,主要是,同事都是很温柔的小姐姐,经常打电话跟我讲代码和业务逻辑。

R.gif

话不多说了哈哈哈,上点真实的面试题。

面试题1:浏览器中和node.js中的事件循环机制


当我们谈论浏览器中的事件循环和Node.js中的事件循环时,其实都在讨论一种处理异步任务的方式。这两者的核心思想都是在执行代码时,不必等待某些耗时的操作完成,而是继续执行其他任务,等待这些任务完成后再来处理结果。

介绍

  • 浏览器中的事件循环:

想象一下你在浏览器中点击一个按钮,触发了一个事件。浏览器会把这个事件放到一个叫做“事件队列”的地方。同时,浏览器也在做其他的事情,比如渲染页面,处理网络请求等等。当浏览器完成了当前的任务,它就会去“事件队列”里看看有没有新的事件需要处理。如果有,它就会把这个事件拿出来执行,然后再继续处理其他任务。这个循环过程就叫做事件循环。

在浏览器环境中,事件循环是处理用户交互、网络请求、渲染更新等异步操作的核心机制。

  • Node.js中的事件循环:

Node.js是用来构建服务器端应用程序的,它也有自己的事件循环机制。比如,当你在Node.js中发起一个网络请求时,Node.js会把这个请求放到一个叫做“事件队列”的地方。然后,Node.js会继续执行其他任务,比如处理数据库查询等等。当网络请求完成后,Node.js就会去“事件队列”里找到对应的请求,然后执行相应的回调函数。这个过程和浏览器中的事件循环很相似,都是一种处理异步任务的方式。

1. 浏览器中的事件循环

浏览器的事件循环机制遵循HTML5规范,主要由以下几个阶段组成:

  1. 宏任务队列(macrotask queue): 宏任务队列包含一些独立的任务,比如用户交互事件、setTimeout/setInterval定时器、网络请求等。这些任务会被依次添加到宏任务队列中等待执行。
  2. 微任务队列(microtask queue): 微任务队列包含一些相对较小的任务,比如Promise的回调函数、MutationObserver等。微任务会在宏任务执行完毕后立即执行,优先级高于宏任务。
  3. 渲染更新: 在每个事件循环的末尾,浏览器会执行渲染更新,更新页面的显示状态。

事件循环会不断地从宏任务队列中取出任务执行,直到宏任务队列为空。在执行完一个宏任务后,会依次执行微任务队列中的所有微任务,然后进行渲染更新。这个过程循环不断,构成了浏览器的事件循环机制。

2. Node.js中的事件循环

Node.js中的事件循环机制与浏览器中的有些许不同,但本质上也是为了处理异步操作。Node.js采用了类似于浏览器事件循环的模型,但是在实现上略有差异:

  1. 宏任务队列(macrotask queue): 宏任务队列中包含了一些独立的任务,比如I/O操作、定时器等。这些任务会被依次添加到宏任务队列中等待执行。
  2. 微任务队列(microtask queue): 与浏览器环境相同,Node.js也有微任务队列,用于存放Promise的回调函数等任务。
  3. 事件触发和回调执行: Node.js中的事件循环主要通过触发事件和执行回调函数来驱动。当有事件发生时,会触发对应的事件回调函数执行。这些回调函数可能是同步的,也可能是异步的,取决于事件的类型和注册方式。

两者的异同:

虽然浏览器中的事件循环和Node.js中的事件循环很相似,但它们也有一些不同之处。比如,在浏览器中,事件循环除了处理网络请求等异步任务外,还要负责渲染页面等任务;而在Node.js中,事件循环主要用于处理I/O操作,比如网络请求、文件读写等。

面试题2:vue里的生命周期和钩子函数


生命周期函数和钩子函数概念

生命周期函数和钩子函数在 Vue.js 中通常被用来描述相同的概念,但是它们并不完全是同一个东西。让我来解释一下:

  1. 生命周期函数: Vue.js 组件的生命周期函数是指在组件生命周期中自动执行的一系列方法,用于控制组件的行为。这些生命周期函数包括 beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestroydestroyed。它们按照组件的创建、更新和销毁阶段被调用。
  2. 钩子函数: 在 Vue.js 中,钩子函数通常指的是在组件生命周期的不同阶段执行的回调函数。这些回调函数与生命周期函数是一一对应的,例如在 created 阶段执行的回调函数就被称为 created 钩子函数,而在 mounted 阶段执行的回调函数就被称为 mounted 钩子函数。这些钩子函数允许开发者在组件的不同生命周期中执行自定义的逻辑。

因此,虽然生命周期函数和钩子函数在描述上有些交叉,但从概念上来说,生命周期函数是组件的生命周期阶段,而钩子函数是在这些阶段中执行的回调函数。

生命周期函数

1. Vue.js 生命周期概述

Vue.js 组件的生命周期可以分为三个阶段:创建阶段、更新阶段和销毁阶段。在每个阶段,Vue.js 提供了一系列钩子函数,允许开发者在组件的不同生命周期中执行相关逻辑。

2. 创建阶段

在组件的创建阶段,Vue.js 主要执行组件的初始化工作,包括实例化、数据观测、编译模板等。

  • beforeCreate: 在实例初始化之后,数据观测 (data observation) 和 event/watcher 事件配置之前被调用。
  • created: 实例已经创建完成之后被调用。在这一步,实例已经完成了数据观测等配置,但是尚未挂载到页面上。

3. 更新阶段

在组件的更新阶段,Vue.js 会根据数据的变化重新渲染组件,更新视图。

  • beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。
  • mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
  • beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  • updated: 数据更新导致虚拟 DOM 重新渲染和打补丁后调用。

4. 销毁阶段

在组件销毁阶段,Vue.js 会执行清理工作,释放相关资源。

  • beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
  • destroyed: 实例销毁之后调用。在这一步,Vue 实例的所有指令和事件监听器都已被移除,所有子实例也已被销毁。

5. 钩子函数应用场景

  • beforeCreate 和 created: 适合用于初始化数据、配置事件等操作。
  • mounted: 适合用于发起网络请求、操作 DOM 元素等任务。
  • beforeDestroy 和 destroyed: 适合用于清理定时器、取消网络请求等收尾工作。

面试题3:vue里的组件传值


当在Vue.js中进行组件传值时,通常会经历以下步骤:

1. 父子组件传值:

  1. 在父组件中定义数据: 在父组件中定义需要传递给子组件的数据,并将其通过props属性传递给子组件。

  2. 在子组件中接收数据: 在子组件中通过props属性接收父组件传递过来的数据,即定义props选项并在模板中使用。

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      parentMessage: 'Hello from parent component'
    };
  },
  components: {
    ChildComponent
  }
}
</script>

<!-- 子组件 -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: ['message']
}
</script>

2. 子父组件传值:

  1. 子组件触发事件: 子组件通过$emit方法触发自定义事件,并传递需要传递的数据作为参数。

  2. 父组件监听事件: 在父组件中使用v-on指令监听子组件触发的事件,当事件被触发时,执行相应的方法。

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent @sendData="handleData" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  methods: {
    handleData(data) {
      console.log('Data received from child:', data);
    }
  },
  components: {
    ChildComponent
  }
}
</script>

<!-- 子组件 -->
<template>
  <div>
    <button @click="sendDataToParent">Send Data to Parent</button>
  </div>
</template>

<script>
export default {
  methods: {
    sendDataToParent() {
      this.$emit('sendData', 'Data from child component');
    }
  }
}
</script>

3. 兄弟组件传值:

  1. 使用中央事件总线或者Vuex: 在Vue.js应用中可以使用中央事件总线(EventBus)或者Vuex等全局状态管理工具来实现兄弟组件之间的数据传递。

中央事件总线(Central Event Bus)

它实际上是一个 Vue 实例,组件可以通过它来发送和接收事件。

工作原理:

  1. 创建一个全局的 Vue 实例作为事件总线。
  2. 组件可以通过该事件总线实例的 $emit() 方法触发事件,并传递数据。
  3. 其他组件可以通过 $on() 方法监听这些事件,并在事件发生时执行相应的操作。

优点:

  • 简单易用,适用于简单的应用场景。
  • 无需安装额外的库或依赖,直接使用 Vue 的特性。

缺点:

  • 全局事件总线可能导致事件命名冲突和不可预测性。
  • 不适用于大型应用程序或需要严格状态管理的场景。

Vuex、pinia

优点:

  • 提供了一种集中式的状态管理方案,适用于复杂的应用场景。
  • 严格的状态管理机制确保了状态的可预测性和可维护性。
  • 支持插件和开发者工具,方便调试和扩展。

缺点:

  • 对于小型应用来说可能会显得繁琐,增加了一些额外的复杂度。
  • 需要额外学习和理解 Vuex 的概念和工作原理。

如何在组件中使用这些数据

1. 中央事件总线

使用中央事件总线时,你可以通过在组件中访问全局的事件总线实例来获取 Vue 的数据。

// 在组件中获取 Vue 数据
const data = this.$data;
const message = this.$root.message;

2. Vuex

使用 Vuex 管理状态时,你可以通过在组件中使用 mapState 辅助函数或直接访问 Vuex store 实例来获取 Vue 的数据。

// 使用 mapState 辅助函数
import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState(['message'])
  }
}
// 或者直接访问 store 实例
const message = this.$store.state.message;

3. Pinia

使用 Pinia 管理状态时,你可以通过在组件中使用 useStore 钩子来获取整个 store 实例,并从中获取数据。

import { useStore } from 'pinia';

export default {
  setup() {
    const store = useStore();
    const message = store.message;
    return {
      message
    };
  }
}

总的来说,在Vue.js中实现组件传值的步骤可以概括为:定义数据、传递数据、接收数据、触发事件、监听事件等。根据具体的场景和需求,选择合适的传值方式,并按照以上步骤进行相应的操作,即可完成组件间的数据传递。

面试题4:createWebhistory 和 createwebhashhistory 的区别


在Vue.js中,Vue Router是非常重要的路由管理工具,它提供了多种路由模式来满足不同的需求。其中,createWebHistory和createWebHashHistory是两种常用的路由模式,它们在URL的处理方式上有着显著的区别。

1. createWebHistory

原理: createWebHistory使用HTML5 History API来管理路由,它通过浏览器的History API来改变URL,实现路由的跳转和管理。在使用createWebHistory时,URL中的路由信息是以正常的路径形式呈现,不带有#号。

应用场景:

  • 适用于支持HTML5 History API的现代浏览器,如Chrome、Firefox、Safari等。
  • 适用于需要更加友好的URL形式,不带有#号,更符合用户的预期和习惯。
  • 适用于需要利用浏览器的前进和后退按钮进行导航的场景。

优点:

  • URL更加美观,不带有#号,提升了用户体验。
  • 支持HTML5 History API,能够利用浏览器的前进和后退按钮进行导航。

缺点:

  • 不兼容低版本的浏览器,需要特殊处理。
  • 在部署时需要服务器端的配置支持,以避免刷新页面时出现404错误。

2. createWebHashHistory

原理: createWebHashHistory使用浏览器的URL的哈希(#)部分来管理路由,它通过监听浏览器的hashchange事件来实现路由的跳转和管理。在使用createWebHashHistory时,URL中的路由信息是以哈希(#)的形式呈现。

应用场景:

  • 适用于兼容性要求较高的场景,哈希模式在大多数浏览器中都能正常工作。
  • 适用于不支持HTML5 History API的浏览器,如IE9及以下版本。

优点:

  • 兼容性较好,适用于大多数现代浏览器以及不支持HTML5 History API的旧版本浏览器。
  • 不需要服务器端的特殊配置,可以直接部署上线。

缺点:

  • URL带有#号,不够美观,可能会影响用户体验。
  • 无法利用浏览器的前进和后退按钮进行导航,需要自行实现路由的导航逻辑。

结论

createWebHistory和createWebHashHistory是Vue Router提供的两种常用的路由模式,它们在URL的处理方式上有着显著的区别。createWebHistory使用HTML5 History API来管理路由,URL中不带有#号,适用于现代浏览器;而createWebHashHistory使用URL的哈希部分来管理路由,URL中带有#号,兼容性较好,适用于不支持HTML5 History API的浏览器。

在实际开发中,根据项目的需求和目标浏览器的兼容性要求,合理选择适当的路由模式非常重要。如果项目不需要考虑兼容性问题,并且希望URL更加友好美观,可以选择createWebHistory;如果项目需要兼容性较好,并且不介意URL中带有#号,可以选择createWebHashHistory。

深入理解createWebHistory和createWebHashHistory的原理和应用场景,可以帮助我们更好地选择合适的路由模式,提升Vue.js应用的开发效率和用户体验。

面试题5:标准盒模型和怪异盒模型


1. 标准盒模型(content-box)

  • 概念: 标准盒模型是W3C规定的盒模型标准,它包括内容区域、内边距、边框和外边距。元素的宽度和高度不包括内边距和边框。
  • 在标准盒模型中,元素的宽度和高度不包括内边距和边框。换句话说,元素的实际宽度/高度等于CSS中定义的width/height属性值加上内边距和边框的宽度。因此,内边距和边框不会影响元素的宽度和高度,只会影响元素内容的排列和显示。

2. 怪异盒模型(border-box)

  • 概念: 怪异盒模型是IE5及以下版本的浏览器采用的盒模型,它的计算方式与标准盒模型有所不同在怪异盒模型中,元素的宽度和高度包括内边距和边框。
  • 换句话说,元素的实际宽度/高度等于CSS中定义的width/height属性值,包括内边距和边框的宽度。因此,内边距和边框会影响元素的宽度和高度,可能会导致元素在页面布局时出现意外的效果。

综上所述,标准盒模型和怪异盒模型都包括外边距,但在处理内边距上存在差异。

3. 应用场景和解决方案

标准盒模型的应用场景:

  • 现代的大多数浏览器都遵循标准盒模型,因此在开发中一般都采用标准盒模型。
  • 通过设置CSS的box-sizing属性为content-box来明确使用标准盒模型。

怪异盒模型的应用场景:

  • 一些古老的网站可能会在遗留系统中使用怪异盒模型,需要做一些兼容性处理。
  • 通过设置CSS的box-sizing属性为border-box来模拟怪异盒模型,以便在现代浏览器中实现相同的效果。

面试题6:跨域的解决办法


跨域是指在浏览器端,当前页面的协议、域名或端口与目标URL不一致时,浏览器会阻止页面发起跨域请求,以保障用户数据安全。

1. 跨域问题的原因

跨域问题的根源在于浏览器的同源策略(Same-Origin Policy),该策略限制了一个源(origin)的文档或脚本如何能与另一个源的资源进行交互。同源策略包括以下几个方面:

  • 协议不同:比如从http协议的页面请求https协议的资源。
  • 域名不同:比如从example.com的页面请求api.example.com的资源。
  • 端口不同:比如从example.com:8080的页面请求example.com:3000的资源。

当浏览器检测到当前请求与目标URL不符合同源策略时,就会阻止跨域请求的发送,从而导致跨域问题的产生。

2. 跨域解决方案

为了解决跨域问题,我们可以采用以下几种常见的解决方案:

1. CORS(Cross-Origin Resource Sharing): CORS是一种跨域资源共享的标准,通过服务端设置响应头中的Access-Control-Allow-Origin字段来允许跨域请求。服务端在收到跨域请求时,检查Origin字段,如果请求的源在白名单内,则在响应头中添加Access-Control-Allow-Origin字段,并设置为允许的源,从而允许跨域请求。

2. JSONP(JSON with Padding): JSONP是一种利用script标签的src属性没有跨域限制的特性来实现跨域请求的技术。通过动态创建script标签,将跨域请求的数据封装在一个回调函数中,然后由服务端返回,并执行回调函数,从而实现跨域数据的获取。

3. 代理服务器: 在开发环境中,可以通过配置代理服务器来实现跨域请求。代理服务器接收前端请求,然后在后端发起真正的请求,获取数据后再返回给前端,由于请求是由后端发起的,所以不存在跨域问题。

4. iframe跨域通信: 使用iframe标签可以实现跨域通信。父页面和iframe页面属于不同的源,但是它们之间可以通过postMessage方法来进行跨域通信,实现数据的传递和交互。

5. WebSocket协议: WebSocket是一种全双工通信协议,能够在不受同源策略限制的情况下实现跨域通信。通过WebSocket协议,客户端和服务端可以建立持久的连接,实现实时数据的传输和交互。

3. 注意事项

  • 在使用跨域解决方案时,需要根据具体的业务需求和安全考虑,选择合适的解决方案,并进行相应的配置和调整。
  • 在配置CORS时,应该谨慎设置Access-Control-Allow-Origin字段,避免将所有域都设置为允许跨域访问,造成安全风险。
  • 在使用代理服务器或其他跨域方案时,需要注意性能和稳定性等方面的问题,确保跨域请求的稳定和可靠性。

面试题7:上中下布局,你会怎么做


1. 使用Flex布局

实现方式: 使用CSS的Flex布局可以轻松实现上中下布局。通过设置容器的display: flex; flex-direction: column;,然后分别设置上、中、下三个部分的高度或者flex属性,即可实现上中下布局。

优点:

  • 简单易用,代码量少。
  • 灵活性强,可以轻松调整布局结构。

缺点:

  • 不兼容低版本浏览器,需要做兼容性处理。
  • 需要理解Flex布局的一些概念和属性。

2. 使用Grid布局

实现方式: 使用CSS的Grid布局同样可以实现上中下布局。通过设置容器的display: grid; grid-template-rows: auto 1fr auto;,然后分别设置上、中、下三个部分的高度,即可实现上中下布局。

优点:

  • 灵活性高,支持复杂的布局结构。
  • 兼容性较好,适用于大多数现代浏览器。

缺点:

  • 兼容性较差,在IE等低版本浏览器中不支持。

3. 使用绝对定位

实现方式: 使用CSS的绝对定位可以实现上中下布局。分别设置上、中、下三个部分的位置和高度,然后通过position: absolute;将它们定位到相应的位置。

优点:

  • 兼容性较好,适用于大多数现代浏览器。
  • 可以实现复杂的布局结构,如侧边栏布局等。

缺点:

  • 需要手动设置位置和高度,不够灵活。
  • 容易出现布局混乱的情况,需要谨慎调整。

4. 使用CSS网格系统

实现方式: 使用现成的CSS网格系统,如Bootstrap、Tailwind CSS等,可以快速实现上中下布局。这些网格系统提供了预定义的栅格结构,只需要按照规定的方式使用即可实现布局。

优点:

  • 快速方便,无需手动编写复杂的CSS。
  • 兼容性较好,适用于大多数现代浏览器。

缺点:

  • 可能会增加项目的体积,需要额外引入网格系统的CSS文件。
  • 需要学习和理解网格系统的使用方式。

面试题8:实现水平垂直居中的方式


标题:实现水平垂直居中的多种方式及比较


在前端开发中,实现元素的水平垂直居中是非常常见的需求,特别是在构建页面布局时。本文将介绍几种常见的实现水平垂直居中的方式,并比较它们的优缺点,以及适用场景。

1. 使用Flex布局

实现方式: 使用CSS的Flex布局可以轻松实现水平垂直居中。通过设置容器的display: flex; justify-content: center; align-items: center;,即可实现容器内元素的水平垂直居中。

优点:

  • 简单易用,代码量少。
  • 支持动态调整布局,适用于响应式设计。

缺点:

  • 不兼容低版本浏览器,需要做兼容性处理。

2. 使用绝对定位和transform属性

实现方式: 使用CSS的绝对定位和transform属性也可以实现水平垂直居中。通过设置元素的position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);,即可实现元素的水平垂直居中。

优点:

  • 兼容性较好,适用于大多数现代浏览器。
  • 可以实现复杂的居中效果,如元素大小未知时的居中等。

缺点:

  • 需要手动计算位置,不够灵活。
  • 容易受到父元素大小的影响,需要谨慎调整。

3. 使用表格布局

实现方式: 使用CSS的表格布局也可以实现水平垂直居中。通过设置容器和元素的display: table; display: table-cell; vertical-align: middle; text-align: center;,即可实现元素的水平垂直居中。

优点:

  • 兼容性较好,适用于大多数现代浏览器。
  • 可以实现多个元素的居中效果,适用于多元素的情况。

缺点:

  • 语义化较差,不推荐在布局中过多使用表格布局。

4. 使用Flex布局的margin:auto方法

实现方式: 使用Flex布局的margin:auto方法也可以实现水平垂直居中。通过设置容器的display: flex;,然后在需要居中的元素上添加margin: auto;,即可实现元素的水平垂直居中。

优点:

  • 简单易用,代码量少。
  • 支持动态调整布局,适用于响应式设计。

缺点:

  • 不支持在两个方向同时居中。

结论

上述介绍了几种常见的实现水平垂直居中的方式,每种方式都有其优缺点。在选择合适的居中方式时,可以根据项目需求、兼容性要求、开发经验等因素进行综合考虑。灵活运用各种居中方式,可以更快速、高效地实现页面布局中元素的水平垂直居中效果。


本文详细介绍了实现水平垂直居中的几种常见方式,并对它们的优缺点进行了比较。通过了解这些居中方式,可以帮助前端开发者根据具体情况选择合适的居中方式,提高开发效率和代码质量。

面试题9:怎么做移动端适配


移动端适配是指将网页内容适应不同尺寸和分辨率的移动设备屏幕,以提供更好的用户体验。下面是实现移动端适配的一般步骤:

1. 使用Viewport

Viewport是移动设备上的可视区域,通过设置Viewport可以控制网页在移动设备上的显示方式。在HTML文件的head标签中添加以下meta标签:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

这个meta标签告诉浏览器,网页的宽度应该等于设备的宽度,并且初始缩放比例为1.0,即不进行缩放。

2. 使用CSS媒体查询

CSS媒体查询可以根据设备的特性和特定的条件来应用不同的样式。通过媒体查询可以根据设备的屏幕尺寸、分辨率、方向等来为不同的设备提供不同的样式。

/* 小屏幕设备(手机、平板)样式 */
@media only screen and (max-width: 768px) {
    /* 样式设置 */
}

/* 中屏幕设备(笔记本、台式机)样式 */
@media only screen and (min-width: 769px) and (max-width: 1024px) {
    /* 样式设置 */
}

/* 大屏幕设备(大型显示器)样式 */
@media only screen and (min-width: 1025px) {
    /* 样式设置 */
}

3. 使用REM或者相对单位

使用相对单位(如rem、em、%)来设置元素的尺寸和间距,而不是使用固定的像素值。这样可以根据设备的屏幕大小和分辨率自动调整元素的大小,使得页面在不同设备上显示更为合适。

4. 使用Flexbox和Grid布局

Flexbox和Grid布局是CSS3提供的强大的布局方式,可以更加灵活地实现页面布局。使用Flexbox和Grid布局可以根据设备的屏幕大小和方向来动态调整页面的布局结构,从而适应不同的移动设备。

面试题10:JS的数据类型?如何判断js的数据类型?


1. JavaScript的数据类型

原始数据类型:

  • Number(数字):表示数字,可以是整数或浮点数。
  • String(字符串):表示文本数据,使用单引号或双引号括起来。
  • Boolean(布尔值):表示逻辑值,只有true和false两个值。
  • Null(空值):表示空值或者不存在的值。
  • Undefined(未定义):表示未定义的值。
  • Symbol(符号,ES6新增):表示唯一的标识符。

引用数据类型:

  • Object(对象):表示复杂数据类型,可以是对象、数组、函数等。

2. 如何判断JavaScript的数据类型

在JavaScript中,可以使用typeof运算符来判断变量的数据类型。typeof运算符返回一个字符串,表示变量的数据类型。

typeof 42;         // "number"
typeof "hello";    // "string"
typeof true;       // "boolean"
typeof undefined;  // "undefined"
typeof null;       // "object"
typeof {};         // "object"
typeof [];         // "object"
typeof function() {}; // "function"

需要注意的是,typeof null返回的是"object",这是JavaScript的一个历史遗留问题,不代表null是对象类型。

另外,可以使用instanceof运算符来判断一个对象是否属于某个类的实例。

var obj = {};
obj instanceof Object;  // true

var arr = [];
arr instanceof Array;   // true

function fn() {}
fn instanceof Function; // true

3. 注意事项

  • 在判断JavaScript的数据类型时,需要注意typeof运算符的一些特殊情况,如typeof null返回的是"object"。
  • 在判断一个对象的具体类型时,可以使用instanceof运算符,但需要注意它不能准确判断一个对象的原始类型。
  • 在开发中,根据实际情况选择合适的数据类型判断方法,确保代码的正确性和可靠性。

面试题11:Evenbus是什么东西?


EventBus(事件总线)是一种在软件架构中用于组件间通信的模式或工具。它通常被用于解耦组件之间的直接依赖关系,使得组件之间可以更灵活地进行通信和交互。

在前端开发中,特别是在Vue.js等现代JavaScript框架中,EventBus通常指的是一个全局事件总线实例,用于在不同组件之间进行通信。它可以帮助组件之间进行解耦,使得组件的通信更加简单和灵活。

EventBus通常具有以下特点:

  1. 全局单例: EventBus通常是一个全局单例对象,可以在应用的任何地方被访问和使用。

  2. 发布订阅模式: EventBus基于发布-订阅模式,它允许组件订阅特定类型的事件,并在其他组件发布该类型的事件时接收到通知。

  3. 事件类型: EventBus通常支持多种事件类型,开发者可以自定义事件类型来满足不同的需求。

  4. 异步通信: EventBus通常支持同步和异步两种通信方式,使得组件之间的通信更加灵活。

在Vue.js中,可以使用Vue实例作为EventBus,通过$emit方法触发事件,通过$on方法监听事件,从而实现组件之间的通信。例如:

// 创建一个全局的EventBus实例
const EventBus = new Vue();

// 在组件A中发布事件
EventBus.$emit('event-name', eventData);

// 在组件B中订阅事件
EventBus.$on('event-name', eventData => {
  // 处理事件数据
});

总之,EventBus是一种用于在组件间进行解耦的通信机制,它可以帮助开发者构建更灵活和可维护的应用程序。