08-07 面经
2024年8月7日大约 4 分钟面经面经
JavaScript 数据类型
原始数据类型
string
number
bigint
boolean
undefined
symbol
null
复杂数据类型
object
array
function
- 复杂数据类型均为
object
的子类
数据类型转换
tostring()
转换为字符串Number()
转换为数字Boolean()
转换为布尔值parseInt()
转换为整数String()
转换为字符串
typeof
结果
- 其他值返回正常结果,只有以下三条特殊:
typeof null
返回object
typeof Function
返回function
typeof Array
返回object
复杂内容的判断需要 instanceof
来判断:[] instanceof Array
原型链
每个构造函数(例如 Array
)都有自己的原型对象 Prototype
。当 Array
实例化时,通过 __proto__
找到原型对象的属性。例如:
array.__proto__ === Array.prototype
Array.prototype.__proto__ === Object.prototype
Object.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) {
// 组件卸载后
}
});