08-07 面经
大约 4 分钟面经面经
JavaScript 数据类型
原始数据类型
stringnumberbigintbooleanundefinedsymbolnull
复杂数据类型
objectarrayfunction- 复杂数据类型均为
object的子类
数据类型转换
tostring()转换为字符串Number()转换为数字Boolean()转换为布尔值parseInt()转换为整数String()转换为字符串
typeof 结果
- 其他值返回正常结果,只有以下三条特殊:
typeof null返回objecttypeof Function返回functiontypeof Array返回object
复杂内容的判断需要 instanceof 来判断:[] instanceof Array
原型链
每个构造函数(例如 Array)都有自己的原型对象 Prototype。当 Array 实例化时,通过 __proto__ 找到原型对象的属性。例如:
array.__proto__ === Array.prototypeArray.prototype.__proto__ === Object.prototypeObject.prototype.__proto__ === null
这种通过 __proto__ 查找原型对象属性的链式结构称为原型链。
作用域和作用域链
- 作用域:代码的执行环境。全局执行环境是全局作用域。
- 作用域链:一系列作用域,当需要查找某个变量或函数时,会按作用域链的顺序查找,直到找到为止。
浏览器全局对象是 window,Node.js 中是 global。全局属性 globalThis 在浏览器和 Node.js 环境下都指向全局对象。
深拷贝和浅拷贝的方法
深拷贝
- 推荐方法:
JSON.parse(JSON.stringify(obj)) - 复杂数据结构:建议使用
lodash的深拷贝方法_.cloneDeep(obj) - 结构化克隆方法:
structuredClone(obj)性能更佳 - 手动实现深拷贝:
function deepClone(obj) { if (obj === null || typeof obj !== "object") { return obj; // 返回非对象的值(包括 null) } const objClone = Array.isArray(obj) ? [] : {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepClone(obj[key]); // 递归深拷贝 } else { objClone[key] = obj[key]; } } } return objClone; }
浅拷贝
Object.assign({}, obj){...obj}- 循环取出键值,赋值给新对象
闭包
闭包使一个函数能够记住并访问其定义时的作用域,即使函数在其作用域外部被调用。闭包用于私有数据的封装和数据的缓存。例如:
function createCounter() {
let count = 0;
return function() {
return ++count;
}
}
let counter = createCounter();
counter(); // 1
counter(); // 2
counter = null; // 释放闭包
call、apply、bind 的区别
call和apply都用于改变函数执行的上下文,区别是接收参数的方式不同:apply(this, [args]):第一个参数是this,第二个参数是数组call(this, arg1, arg2, ...):第一个参数是this,其余参数按顺序传入
bind也用于改变函数执行的上下文,但返回一个新的函数,该函数可以接收参数,并在调用时绑定给定的this值。
DOM 事件
onmouseover:鼠标指针移入时执行事件onmouseout:鼠标指针移出时执行事件onmousedown:鼠标按下时执行事件onmouseup:鼠标松开时执行事件
宏任务与微任务
- 宏任务:
setTimeout、setInterval、I/O、UI 渲染、requestAnimationFrame - 微任务:
Promise、MutationObserver
宏任务在当前任务执行完之前执行,如 setTimeout、setInterval、I/O、UI 渲染。微任务在当前任务执行完之后执行,如 Promise、MutationObserver。
0.5 毫米的线
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div></div>
<style>
div {
left: 0;
top: 0;
margin-top: 20px;
width: 100%;
height: 1px;
background-color: red;
transform: scaleY(0.5);
transform-origin: center center;
}
</style>
</body>
</html>
在 Vue 中,自定义指令允许你在 DOM 元素上应用特殊行为。Vue 2 和 Vue 3 的自定义指令有些细微差别。以下是两者的基本用法:
Vue 2
在 Vue 2 中,自定义指令使用 Vue.directive 方法来注册。指令对象包含多个钩子函数,如 bind、inserted、update 和 unbind。
// 全局注册
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus();
}
});
// 局部注册
new Vue({
el: '#app',
directives: {
focus: {
inserted: function (el) {
el.focus();
}
}
}
});
使用自定义指令:
<input v-focus>
Vue 3
在 Vue 3 中,自定义指令的注册方式有所变化。我们使用 app.directive 方法来注册指令。
import { createApp } from 'vue';
const app = createApp({});
// 全局注册
app.directive('focus', {
mounted(el) {
el.focus();
}
});
// 局部注册
const MyComponent = {
template: '<input v-focus>',
directives: {
focus: {
mounted(el) {
el.focus();
}
}
}
};
app.mount('#app');
使用自定义指令:
<input v-focus>
钩子函数
在 Vue 2 和 Vue 3 中,自定义指令可以定义以下钩子函数:
- bind (Vue 2) / created (Vue 3): 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted (Vue 2) / mounted (Vue 3): 被绑定元素插入父节点时调用。
- update (Vue 2) / updated (Vue 3): 所在组件的 VNode 更新时调用。
- unbind (Vue 2) / beforeUnmount (Vue 3): 只调用一次,指令与元素解绑时调用。
- componentUpdated (Vue 2) / unmounted (Vue 3): 指令所在组件的 VNode 及其子 VNode 全部更新后调用。
例子:
// Vue 2
Vue.directive('example', {
bind(el, binding, vnode) {
// 初始化
},
inserted(el, binding, vnode) {
// 元素插入 DOM
},
update(el, binding, vnode, oldVnode) {
// VNode 更新
},
unbind(el, binding, vnode) {
// 元素解绑
}
});
// Vue 3
app.directive('example', {
created(el, binding, vnode, prevVnode) {
// 初始化
},
mounted(el, binding, vnode, prevVnode) {
// 元素插入 DOM
},
updated(el, binding, vnode, prevVnode) {
// VNode 更新
},
beforeUnmount(el, binding, vnode, prevVnode) {
// 元素解绑
},
unmounted(el, binding, vnode, prevVnode) {
// 组件卸载后
}
});
