复盘最近面试经常被问到的概念题
前言
这个礼拜一直在面试,从周一一直面到周五,面了也有7-8家,也拿了一个中厂offer不过因为某些原因给拒了,整理出来了这份面经希望对各位有所帮助。
什么是html和css
html
HTML 是一种标记语言
,用于创建网页结构
。它通过使用一系列预定义的标签来描述文档的内容和结构
。这些标签告诉浏览器如何显示文本、图片、链接等元素
。就像是建造房子时候的钢筋水泥筑成的架子。
css
CSS 是一种样式表语言
,用于描述 HTML 或 XML 文档的外观和格式
。它可以控制页面布局、颜色、字体、大小等视觉样式
。就像是对一个房子的装修
说一下什么是盒子模型
在 CSS 中有两种主要的盒子模型类型:
W3C 盒子模型 (谷歌标准盒模型
): 在这种模型中,width 和 height 指的是内容区域的尺寸,不包括边框、内边距和外边距。 (width = content)
IE 盒子模型 (怪异盒模型
): 在这种模型中,width 和 height 包括了内容、内边距和边框的尺寸,但不包括外边距。 (width = content + padding + border)
如何实现响应式设计
使用 Flexbox 或 Grid 布局
Flexbox 和 Grid 布局是现代 CSS 提供的强大工具,可以更容易地创建响应式布局。
Flexbox:
.container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1 0 200px; /* 使项目根据可用空间扩展,最小宽度为 200px */
}
Grid:
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
使用视口单位
视口单位 (vw, vh, vmin, vmax) 可以基于视口的尺寸来设置元素的尺寸。例如,1vw 等于视口宽度的 1%。
使用百分比单位
可以使用百分比单位(如 %)来代替固定单位(如 px)。这使得元素可以根据其父元素的大小进行调整。
介绍一下css中选择器类型和优先级
类型
内联样式(如 style 属性) - 特异性值为 1000。
ID 选择器(如 #uniqueId) - 特异性值为 0100。
类选择器(如 .className)、属性选择器(如 [type="text"])和伪类(如 :hover) - 特异性值为 0010。
标签名(如 div)和伪元素(如 ::before) - 特异性值为 0001。
通用选择器(如 *)、子代选择器、相邻兄弟选择器(如 +)、普通兄弟选择器(如 ~) - 特异性值为 0000
优先级
important > 行内样式 > id > class > (后代选择器,子集选择器,兄弟选择器) > 标签
什么是浮动float会导致什么问题
在 CSS 中,float 属性用于指定元素应该向哪一侧浮动,即该元素会被移动到其容器的边缘,而其他内容会围绕它流动。float 属性常用于创建多列布局、侧边栏或让图像环绕文本等场景。
虽然 float 很有用,但它也带来了一些常见的问题:
-
父级元素的高度塌陷: 当一个包含浮动元素的父级元素没有被明确设置高度时,父级的高度可能会“塌陷”,即它的高度不足以包含所有的浮动元素。这是因为浮动元素脱离了正常的文档流,不再影响其父元素的高度。
-
水平布局中的重叠:如果浮动元素的宽度超过了容器的宽度,它们可能会重叠。
-
内容溢出:如果非浮动的内容位于浮动元素之后,它可能会覆盖到浮动元素后面,导致布局混乱。
解决方案可以将父容器设置为BFC容器,使用overflow:hidden或auton,使其包含所有的浮动元素。
css的预处理器的优点
CSS 预处理器是一种脚本语言,它允许开发者使用类似于编程的语言特性来编写 CSS,从而提高 CSS 的可维护性和可扩展性。最常用的 CSS 预处理器包括 Sass、Less 和 Stylus。
优点
- 预处理器允许你定义变量来存储颜色、字体大小、边距等常用值。
// Sass 示例
$primary-color: #ff0000;
body {
color: $primary-color;
}
.button {
background-color: $primary-color;
}
- 嵌套选择器 预处理器允许你使用嵌套语法来组织选择器,这使得 CSS 代码更易于阅读和理解。
// Sass 示例
.nav {
ul {
list-style: none;
padding: 0;
li {
display: inline-block;
}
}
}
- 函数
预处理器支持函数,可以执行一些计算任务,比如数学运算、颜色操作等。
// Sass 示例
$font-size-base: 16px;
@function calculate-font-size($multiplier) {
@return $font-size-base * $multiplier;
}
h1 {
font-size: calculate-font-size(1.5);
}
CSS 预处理器极大地提高了编写 CSS 的效率和质量,尤其是在大型项目中。它们提供的高级功能可以使 CSS 更加灵活、易于维护,并且能够更好地管理样式。
什么是js作用域和闭包
作用域
作用域定义了变量的可访问范围。JavaScript 中有两种基本的作用域类型:
- 全局作用域:在任何函数外部声明的变量属于全局作用域,可以在整个程序中被访问。
- 局部作用域:在函数内部声明的变量只在其所在的函数内部可见,即函数作用域。
ES6 引入了块级作用域的概念,通过使用 let 和 const 关键字声明的变量仅在其定义的代码块内可见。
闭包
闭包是一种特殊的函数,它可以访问并操作其定义时所在作用域内的变量,即使该作用域已经不在执行栈的顶部。换句话说,闭包可以让一个函数记住并访问其创建时的环境变量。
js原型链
JavaScript 中的原型链是一种对象查找机制,用于实现继承和属性查找。每个 JavaScript 对象都有一个内部属性,称为 [[Prototype]],它指向另一个对象。当我们尝试访问一个对象的属性时,如果该属性不存在于对象本身,则会沿着原型链向上查找,直到找到该属性或者到达原型链的末端。如图:
js如何实现继承
原型链继承
原型链继承是最基本的继承方式,它通过将一个构造函数的原型对象设置为另一个构造函数的实例来实现继承。
function Parent() {
this.name = 'parent';
}
Parent.prototype.sayName = function () {
console.log(this.name);
};
function Child() {
// ...
}
// 继承 Parent
Child.prototype = new Parent();
const child = new Child();
child.sayName(); // 输出: parent
构造函数继承
构造函数继承通过在子类构造函数内部调用父类构造函数来实现属性继承。
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function () {
console.log(this.name);
};
function Child(name) {
Parent.call(this, name); // 构造函数继承
}
const child = new Child('child');
console.log(child.name); // 输出: child
ES6 类继承
ES6 引入了类的概念,使得继承更加简洁和清晰。
class Parent {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // 调用父类构造器
this.age = age;
}
sayAge() {
console.log(this.age);
}
}
const child = new Child('child', 10);
child.sayName(); // 输出: child
child.sayAge(); // 输出: 10
什么是js的异步编程
JavaScript 的异步编程是指在不阻塞主线程的情况下执行耗时操作
,比如网络请求、文件读写或定时任务等。JavaScript 本质上是单线程
的,这意味着它一次只能执行一个任务。为了确保用户界面的响应性
,JavaScript 开发者需要使用异步编程模式
来处理
那些可能需要较长时间
才能完成的任务。
异步编程的主要方法
回调函数(Callback)
回调函数是最原始的异步编程方式之一,通常在一个异步操作完成后调用。 例如,在一个异步函数中注册一个回调函数来处理数据加载完成后的逻辑。 缺点是当多个异步操作嵌套时,会导致代码难以阅读和维护,通常称为“回调地狱”。
事件监听器(Event Listeners)
事件监听器用于处理用户交互或其他事件。 当某个事件发生时,指定的回调函数会被调用。 例如,监听按钮点击事件并在点击时执行某些操作。
Promises
Promises 是 JavaScript 中处理异步操作的一种更现代的方式。 Promise 对象代表一个尚未完成但最终会产生结果的操作。 它有三种状态:pending(待定)、fulfilled(已成功)和rejected(已失败)。 使用 .then() 和 .catch() 方法来处理成功和失败的情况。
Async/Await
Async/Await 是基于 Promises 的语法糖,使异步代码看起来更像同步代码。 async 关键字用于定义一个异步函数,await 关键字用于等待一个 Promise 结果。 异步函数总是返回一个 Promise。 使用 async/await 可以让异步代码更加简洁易读。
什么是vue
Vue 是一个用于构建用户界面的轻量级、灵活且高效的JavaScript框架。它采用数据驱动的视图和组件化的架构,使得开发者能够轻松创建可重用的UI组件,并实现数据与视图之间的自动同步。Vue 提供了简洁的API和模板语法,利用虚拟DOM技术提升性能,并拥有强大的生态系统支持,包括官方提供的路由管理器 Vue Router 和状态管理库 Vuex。Vue 的设计易于上手,同时适用于构建从小型到大型的Web应用。
说一下vue的生命周期
Vue 3 的生命周期与 Vue 2 有所不同,Vue 3 引入了一组新的生命周期钩子,这些钩子更加简洁并且与 Composition API 更加兼容。Vue 3 的生命周期分为两个主要阶段:setup 阶段
和 渲染和更新阶段
Setup 阶段
-
beforeCreate 和 created:在 Vue 3 中,这两个钩子已经被移除。它们的功能现在由 setup() 函数替代。
-
setup:这是 Vue 3 中的一个关键钩子,它在组件实例被创建之后立即执行,但在此之前还没有挂载到 DOM。setup() 函数是 Composition API 的核心,它用于初始化组件的状态和逻辑。你可以在 setup() 中定义响应式状态、计算属性、侦听器等,并返回一个对象来暴露公共属性和方法给模板使用。
渲染和更新阶段
-
beforeMount:在组件挂载到 DOM 之前被调用。
-
mounted:在组件被挂载到 DOM 并完成渲染之后被调用。
-
beforeUpdate:在组件即将更新之前被调用,此阶段组件的 DOM 还未更新。
-
updated:在组件完成更新并重新渲染到 DOM 之后被调用。
5.beforeUnmount:在组件即将被卸载之前被调用。
- unmounted:在组件从 DOM 中卸载之后被调用。
错误捕获
errorCaptured:当一个子组件抛出错误时被调用,可以用来处理错误。
服务器端渲染
ssrPrefetch:仅在服务器端渲染时被调用,用于预取数据。
激活和停用
activated:仅在 组件中使用,当组件被激活时被调用。 deactivated:仅在 组件中使用,当组件被停用时被调用。
vuex是什么东西
Vuex 是 Vue.js 官方的状态管理模式与库
。它用于集中管理应用的所有组件状态(state),并以一种可预测的方式决定状态如何改变。Vuex 通过提供一种全局的 store(存储)来替代每个组件各自维护状态的方式,使得状态管理更加清晰和统一。
什么是vue的route和router
Route (路由)
在 Vue Router 中,Route 是一个对象,它代表了应用中的一个路径和相应的配置。一个 Route 包含了与 URL 相关的信息,比如路径、参数、查询字符串等。当你在浏览器地址栏输入一个 URL 或者点击链接时,Vue Router 会根据配置好的 Route 对象来匹配当前的 URL,并决定要渲染哪个组件。
Router (路由器)
Router 是 Vue Router 的核心对象,它管理着应用的路由。Router 对象负责如下工作:
-
注册路由规则。
-
匹配当前 URL 到相应的路由配置。
-
导航和管理路由变化。
-
提供 API 来控制导航行为。
怎么定义组件通讯
在 Vue 中,组件通信是指在一个应用程序的不同组件之间共享数据或者触发事件的能力。
父子组件通信
父组件可以通过 props 向子组件传递数据:
<!-- 父组件 -->
<template>
<ChildComponent :message="parentMessage" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: 'Hello from parent!'
};
}
};
</script>
<!-- 子组件 -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
};
</script>
子传父
子组件可以通过 emit 方法触发事件,然后父组件监听这些事件并做出响应:
<!-- 子组件 -->
<template>
<button @click="sendToParent">Send Message</button>
</template>
<script>
export default {
methods: {
sendToParent() {
this.emit('child-event', 'Hello from child!');
}
}
};
</script>
<!-- 父组件 -->
<template>
<ChildComponent @child-event="handleChildEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleChildEvent(message) {
console.log(message);
}
}
};
</script>
兄弟组件通信
当需要兄弟组件之间通信时,通常会使用以下方法:
-
通过父组件作为中介
可以利用父组件作为中间人,通过 props 和 emit 来实现兄弟组件之间的通信。
-
使用 Vuex或者Pinia
对于更复杂的应用程序,推荐使用 Vuex或者Pinia 这个状态管理模式来集中管理组件的状态,这样就可以在任何组件中访问和修改状态。
遇到很多图片的页面你能想到怎么去优化?
懒加载
使用懒加载技术来延迟加载不在视口内的图像,直到用户滚动到它们所在的位置。这可以显著减少初始加载时间。 可以使用 JavaScript 库(如 lozad.js, LazyLoad)或原生的 loading="lazy" 属性来实现。
图片压缩
使用图像压缩工具(如 TinyPNG, ImageOptim, 或在线服务)来减少文件大小,而不显著降低图像质量。
总结
这个星期大大小小的公司面了不少,给我的感觉是都非常注重基础,喜欢问一下基础的概念,还有最近这段时间是属于提前批boos上的反馈率还蛮高的。
如果觉得文章对您的学习有帮助,还请点赞+评论+收藏支持一下,谢谢大家,祝大家早日找到心仪的工作。
转载自:https://juejin.cn/post/7398932653870989352