vue前端面试题——记录一次面试当中遇到的题(8)
目录
1.元素居中的方法
1. 水平居中
2.垂直居中
3.水平垂直居中
2.元素显示与隐藏方式?隐藏后还会触发函数吗?
1. display: none - 完全隐藏
3. opacity: 0 - 透明度隐藏
4. 尺寸归零法
5. 定位移出屏幕
6. clip-path 裁剪
3.箭头函数和普通函数的区别?
4.怎么获取对象当中的某一个值
5.作用域和作用域链
6.怎么判断数组是不是数组?
8.computed和watch和method的区别
9.组件通讯
10.父组件访问子组件的方法?
1.元素居中的方法
元素居中可以分为水平居中、垂直居中和水平垂直居中。
1. 水平居中
行内/行内块元素
.parent {text-align: center;
}.child {display: inline; /* 或 inline-block */
}
块级元素(固定宽度)
.child {width: 200px;margin: 0 auto;
}
任意元素 - Flexbox
.parent {display: flex;justify-content: center;
}
任意元素 - Grid
.parent {display: grid;justify-content: center;
}
2.垂直居中
单行文本
.parent {height: 100px;line-height: 100px; /* 与高度相同 */
}
行内/行内块元素
.parent {height: 200px;line-height: 200px; /* 方法一 */
}.child {display: inline-block;vertical-align: middle; /* 方法二 */
}
任意元素 - Flexbox
.parent {display: flex;align-items: center;height: 300px; /* 需要指定高度 */
}
任意元素 - Grid
.parent {display: grid;align-items: center;height: 300px;
}
绝对定位 + transform
.parent {position: relative;height: 300px;
}.child {position: absolute;top: 50%;transform: translateY(-50%);
}
3.水平垂直居中
Flexbox(推荐⭐)
.parent {display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */height: 100vh; /* 需要高度 */
}/* 或者使用 margin: auto */
.parent {display: flex;height: 100vh;
}.child {margin: auto;
}
Grid(现代推荐)
.parent {display: grid;place-items: center; /* 同时设置水平和垂直居中 */height: 100vh;
}/* 或者分别设置 */
.parent {display: grid;justify-content: center;align-content: center;height: 100vh;
}
绝对定位 + transform(经典万能)
.parent {position: relative;height: 100vh;
}.child {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
}
绝对定位 + margin(已知尺寸)
.parent {position: relative;height: 100vh;
}.child {position: absolute;top: 50%;left: 50%;width: 200px;height: 100px;margin-top: -50px; /* height/2 */margin-left: -100px; /* width/2 */
}
表格布局(传统方法)
.parent {display: table;width: 100%;height: 100vh;
}.child {display: table-cell;text-align: center;vertical-align: middle;
}
2.元素显示与隐藏方式?隐藏后还会触发函数吗?
1. display: none
- 完全隐藏
特点:
-
元素完全不渲染,不占据任何空间
-
无法触发任何事件(点击、悬停等)
-
会导致浏览器重排和重绘
-
屏幕阅读器无法访问
2. visibility: hidden
- 视觉隐藏
特点:
-
元素不可见,但仍占据布局空间
-
无法触发鼠标事件(点击、悬停等)
-
但可以触发键盘事件和焦点事件
-
会导致浏览器重绘(但不重排)
3. opacity: 0
- 透明度隐藏
特点:
-
元素完全透明,但仍占据布局空间
-
可以触发所有事件
-
元素仍然可交互(可点击、可聚焦)
-
支持 CSS 过渡动画
4. 尺寸归零法
.hidden {width: 0;height: 0;overflow: hidden;
}
-
元素不占据可见空间
-
通常无法触发鼠标事件(因为没有尺寸)
-
但元素仍然在 DOM 中
5. 定位移出屏幕
.hidden {position: absolute;left: -9999px;top: -9999px;
}
特点:
-
元素在视觉上看不到
-
可以触发所有事件
-
屏幕阅读器可以访问
-
常用于隐藏但需要保持可访问性的元素
6. clip-path
裁剪
.hidden {clip-path: circle(0);/* 或者 */clip-path: inset(100%);
}
特点:
-
元素被裁剪到不可见
-
可以触发事件(在原始位置)
-
支持动画效果
3.箭头函数和普通函数的区别?
this
继承自定义时的外层作用域,且无法被修改:- 不能作为构造函数,使用
new
会报错 - 没有
arguments
对象,需通过剩余参数(...args
) 获取参数 - 没有
prototype
属性,也不能使用super
(因无原型链关联)
4.怎么获取对象当中的某一个值
(1)点符号(Dot Notation):当你知道属性的名称,并且属性名是一个有效的标识符(不包含空格、不以数字开头、不是保留字等)时,可以使用点符号。
let obj = { name: "Alice", age: 30 };
let name = obj.name; // "Alice"
(2)方括号符号(Bracket Notation):当属性名包含空格、特殊字符,或者是一个变量时,可以使用方括号符号。
let obj = { "first name": "Alice", age: 30 };
let firstName = obj["first name"]; // "Alice"let property = "age";
let age = obj[property]; // 30
(3)解构赋值(Destructuring Assignment):如果你想要从对象中提取多个属性,可以使用解构赋值。
let obj = { name: "Alice", age: 30 };
let { name, age } = obj;
console.log(name); // "Alice"
console.log(age); // 30
(4)使用默认值:如果属性可能不存在,你可以使用解构赋值时设置默认值,或者使用逻辑运算符。
// 解构赋值设置默认值
let { name, age, gender = "unknown" } = obj;// 使用逻辑运算符
let gender = obj.gender || "unknown";
(5)可选链操作符(Optional Chaining):如果你不确定对象是否存在,或者属性是否存在,可以使用可选链操作符(?.)来安全地访问嵌套属性。
let obj = { person: { name: "Alice" } };
let name = obj.person?.name; // "Alice"
let city = obj.person?.address?.city; // undefined,不会报错
(6)使用in
运算符检查属性是否存在:如果你需要检查对象中是否存在某个属性,可以使用in
运算符。
if ("name" in obj) {console.log(obj.name);
}
(7)使用hasOwnProperty
方法:检查对象自身(非继承)是否具有指定属性。
if (obj.hasOwnProperty("name")) {console.log(obj.name);
}
(8)使用Object.values()
和Object.entries()
:如果你需要获取对象的所有值或键值对,可以使用这些方法。
let obj = { a: 1, b: 2, c: 3 };
let values = Object.values(obj); // [1, 2, 3]
let entries = Object.entries(obj); // [['a', 1], ['b', 2], ['c', 3]]
(9)使用Object.getOwnPropertyDescriptor()
:获取对象某个属性的描述符(可配置、可枚举、可写等)。
let descriptor = Object.getOwnPropertyDescriptor(obj, "name");
5.作用域和作用域链
作用域指的是变量的可访问范围,分为全局作用域、函数作用域和块级作用域。
全局作用域在任何地方都可以访问,函数作用域只能在函数内部访问,块级作用域是ES6引入的,用let和const声明的变量在{}内有效。
作用域链是JavaScript查找变量的规则:从当前作用域开始,逐级向上查找,直到全局作用域。JavaScript采用词法作用域,意味着作用域在代码书写阶段就确定了,这形成了闭包的基础。比如内层函数可以访问外层函数的变量,就是因为作用域链的存在。
6.怎么判断数组是不是数组?
(1)Array.isArray()
这是ES5引入的方法,专门用于判断一个值是否为数组。它是最可靠和标准的方法。
const arr = [1, 2, 3];
console.log(Array.isArray(arr)); // trueconst notArr = {0: 1, 1: 2, length: 2};
console.log(Array.isArray(notArr)); // false
(2) instanceof运算符
检查对象是否为Array构造函数的实例。但这种方法在多个iframe或window环境中可能失败,因为不同环境的Array构造函数可能不同。
const arr = [1, 2, 3];
console.log(arr instanceof Array); // trueconst notArr = {};;
console.log(notArr instanceof Array); // false
(3)Object.prototype.toString.call()
这是一种通用的方法,可以判断任何对象的类型。对于数组,它会返回[object Array]
。
const arr = [1, 2, 3];
console.log(Object.prototype.toString.call(arr) === '[object Array]'); // trueconst notArr = {};
console.log(Object.prototype.toString.call(notArr) === '[object Array]'); // false
(4)constructor属性
检查对象的constructor属性是否指向Array。但是,对象的constructor属性可以被修改,所以不可靠。
const arr = [1, 2, 3];
console.log(arr.constructor === Array); // true// 但是,如果修改了constructor属性,就不准确了
arr.constructor = Object;
console.log(arr.constructor === Array); // false
7.闭包
闭包是指能够访问自由变量的函数。自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。
形成条件:函数嵌套,内部函数引用外部函数变量,内部函数被返回或引用。
作用:可以读取函数内部的变量,并让这些变量始终保持在内存中。
应用场景:封装私有变量、模块化、循环中保存变量等。
优缺点:优点是可以实现封装和数据持久化;缺点是可能引起内存泄露,需要及时释放。
8.computed和watch和method的区别
计算属性(computed)
定义:计算属性是基于它们的响应式依赖进行缓存的。只有在相关响应式依赖发生改变时它们才会重新求值。
使用场景:适用于需要根据现有数据计算得到新数据的场景,且计算过程可能比较耗时或需要复用。
特点:
-
缓存:只要依赖的数据没有发生变化,多次访问计算属性会立即返回之前的计算结果,而不会重新执行函数。
-
响应式:只有当依赖的响应式数据发生变化时,才会重新计算。
-
必须返回一个值,并且通常不应该有副作用(如异步操作或改变外部状态)。
侦听器(watch)
定义:watch用于监听特定数据的变化,并在数据变化时执行异步或开销较大的操作。
使用场景:适用于在数据变化后需要执行异步操作或复杂逻辑的场景。
特点:
-
监听数据的变化,执行回调函数。
-
可以执行异步操作。
-
不需要返回值,通常用于执行副作用。
方法(methods)
定义:methods是挂载在Vue实例上的函数,可以在模板中调用,也可以在其他方法中调用。
使用场景:适用于需要响应用户事件、执行任意逻辑(包括异步操作)的场景。
特点:
-
不会缓存,每次调用都会执行函数。
-
可以接受参数。
-
可以在模板中通过事件绑定调用,也可以在计算属性、侦听器或其他方法中调用。
总结:
computed 是计算属性,有缓存,依赖不变不会重新计算,适合模板中的复杂逻辑。
watch 是侦听器,观察数据变化执行副作用,支持异步,适合搜索、验证等场景。
methods 是方法,无缓存,适合事件处理和通用函数。
简单说:需要缓存的计算用 computed,响应数据变化用 watch,处理事件用 methods
9.组件通讯
Props / Events | 父子组件双向 | 直接父子关系 | Vue 2/3 |
v-model | 父子组件双向 | 表单输入、组件双向绑定 | Vue 2/3 |
$emit / v-on | 子向父 | 子组件通知父组件 | Vue 2/3 |
$parent / $children | 父子组件访问 | 直接访问父子实例(不推荐) | Vue 2/3 |
$refs | 父访问子 | 调用子组件方法、访问DOM | Vue 2/3 |
Event Bus | 任意组件 | 简单项目、兄弟组件通讯 | Vue 2 |
Provide / Inject | 跨层级 | 祖先向后代传递数据 | Vue 2.2+/3 |
Vuex / Pinia | 全局状态 | 复杂应用、多组件共享状态 | Vue 2/3 |
Local Storage | 数据持久化 | 页面刷新后保持状态 | 所有 |
10.父组件访问子组件的方法?
方法一:使用 ref
和 $refs
(最推荐⭐)
方法二:使用 $children
(不推荐)
方法三:Vue 3 + <script setup>
使用 defineExpose
暴露方法,父组件才能访问。