回答:
回答:
回答:
是的,在开发过程中,我有时需要修改hosts文件来映射域名到特定的IP地址,以便在本地环境进行调试或访问特定的服务器。
回答:
回答:
回答:
回答:
回流(Reflow):元素位置、大小、布局变化,浏览器重新计算并绘制页面。
重绘(Repaint):元素样式变化,不涉及布局,浏览器重新绘制元素外观。
回答:
.rectangle {
height: 50vw; /* vw表示视口宽度的百分比 */
}
回答:
.container {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.item {
flex: 0 0 33.33%; /* 每个元素占容器的1/3宽度 */
}
回答:
clear:both;
。content:''; display:block; clear:both;
。overflow:hidden;
或overflow:auto;
。回答:
在flex布局中设置盒子之间的间距,可以使用以下几种方法:
.item {
margin-right: 10px; /* 最后一个元素可能需要清除右边距 */
}
.item:last-child {
margin-right: 0;
}
.container {
justify-content: space-between; /* 平均分配剩余空间 */
}
.container {
gap: 10px; /* 设置子元素之间的间距 */
}
margin直接作用于子元素,适用于个别元素需要特别间距的情况。
justify-content作用于整个flex容器,用于分配所有子元素之间的空间。
gap是较新的CSS属性,可以更简洁地设置所有子元素之间的间距。
回答:
var声明的变量拥有函数作用域或全局作用域,存在变量提升。
let声明的变量拥有块作用域,不存在变量提升,但可以重新赋值。
const声明的变量拥有块作用域,不存在变量提升,且声明时必须初始化,且不能重新赋值。
回答:
在JavaScript中,const声明的变量本身是不可重新赋值的,但是如果是对象或数组,其属性或元素是可以被修改的。要实现一个完全不可更改的对象,可以使用Object.freeze()方法:
const obj = Object.freeze({ key: 'value' });
回答:
回答:
回答:
回答:
JavaScript的事件循环机制是基于事件队列的。当执行栈为空时,事件循环会从任务队列中取出一个任务并执行。任务分为宏任务(如setTimeout, setInterval)和微任务(如Promise)。每个宏任务执行后,会执行所有的微任务队列中的任务,然后继续下一个宏任务。
回答:
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
执行顺序:1 -> 4 -> 3 -> 2
解释:首先执行同步代码,打印1和4。然后执行微任务,打印3。最后执行宏任务,打印2。
回答:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
async function demo() {
console.log('等待前');
await sleep(2000);
console.log('等待后');
}
demo();
回答:
map会返回一个新数组,其结果是对原始数组每个元素调用提供的一个函数后返回的结果组成的数组。
forEach不会返回新数组,它返回undefined。它直接对原始数组进行操作,通常用于执行一些操作而不需要返回值。
具体区别如下:
🎃返回值:map返回新数组,forEach不返回值。
🎄可链式调用:由于map返回新数组,因此可以继续链式调用其他数组方法,而forEach不可以。
🎍用途:map通常用于需要新数组的情况,比如转换数据结构;forEach用于执行副作用,比如直接修改外部变量或执行DOM操作。
示例代码:
// 使用 map
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2); // [2, 4, 6]
// 使用 forEach
numbers.forEach(n => console.log(n)); // 打印 1, 2, 3,但不返回新数组
function customFlat(array, depth = 1) {
if (depth === 0) return array.slice();
return array.reduce((acc, val) => {
return acc.concat(Array.isArray(val) ? customFlat(val, depth - 1) : val);
}, []);
}
// 使用示例
const nestedArray = [1, [2, [3, [4]], 5]];
console.log(customFlat(nestedArray, 1)); // [1, 2, [3, [4]], 5]
console.log(customFlat(nestedArray, 2)); // [1, 2, 3, [4], 5]
console.log(customFlat(nestedArray, Infinity)); // [1, 2, 3, 4, 5]
Vue的双向绑定原理主要依赖于Object.defineProperty()函数,它通过以下步骤实现:
$set是Vue提供的一个实例方法,用于解决对象新增属性不是响应式的问题。其实现原理如下:
Vue.prototype.$set = function (target, key, val) {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key);
target.splice(key, 1, val);
return val;
}
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
const ob = target.__ob__;
if (!ob) {
target[key] = val;
return val;
}
defineReactive(ob.value, key, val);
ob.dep.notify();
return val;
};
$set解决了以下问题:
当向对象添加新属性时,新属性不会触发视图更新,因为Observer没有为该属性设置getter和setter。
通过$set,Vue可以手动触发依赖收集和派发更新,使得新属性也是响应式的。
Vue通过以下步骤实现派发更新和收集依赖:
当组件渲染时,Watcher实例会在读取数据对象的属性时被创建。
每个属性都有一个Dependency实例,当属性被读取时,Dependency会记录当前的Watcher。
这样,每个属性都维护了一个Watcher列表,这些Watcher依赖于该属性。
当数据对象的属性被修改时,Observer会触发该属性的setter。
setter会通知Dependency,Dependency则会遍历其维护的Watcher列表,并调用每个Watcher的update方法。
Watcher的update方法会触发视图的重新渲染或执行用户定义的回调函数。
这个过程确保了当数据变化时,依赖于这些数据的视图或逻辑能够得到相应的更新。