回答: 盒模型是 CSS 布局的核心概念,每个元素都被视为一个矩形盒子,包含以下部分:
width
和 height
控制。padding
属性设置。border
属性设置样式、颜色和宽度。margin
属性控制。盒模型类型:
width
和 height
仅定义内容区域大小(默认)。 box-sizing: content-box; /* 默认值 */
width
和 height
包含内容、内边距和边框。 box-sizing: border-box; /* 推荐使用,更符合直观布局 */
示例:
<div style="width: 300px; padding: 20px; border: 5px solid black; margin: 10px;"></div>
300px + 20px*2 + 5px*2 = 350px
300px
(包含内边距和边框)回答: BFC(Block Formatting Context,块级格式化上下文)是页面上的一个独立渲染区域,内部元素的布局不受外部影响。
触发条件:
float: left/right
position: absolute/fixed
display: inline-block/table-cell/flex/grid
overflow: hidden/auto/scroll
(非 visible
)
contain: layout/content/paint
BFC 的特性与作用:
<div class="parent" style="overflow: hidden;">
<div style="margin: 20px;">A</div>
<div style="margin: 30px;">B</div>
</div>
在 BFC 中,相邻元素的外边距不会折叠。
实际应用场景:
回答: 以下是多种垂直居中方案的代码实现及适用场景:
.parent {
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
}
适用场景:现代浏览器,简单且强大的布局方案。
.parent {
display: grid;
place-items: center; /* 同时垂直和水平居中 */
}
适用场景:复杂布局需求,支持二维对齐。
.parent { position: relative; }
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
适用场景:未知子元素尺寸时的居中。
.parent { display: table; }
.child {
display: table-cell;
vertical-align: middle; /* 垂直居中 */
text-align: center; /* 水平居中 */
}
适用场景:兼容旧版浏览器(如 IE8+)。
.parent {
height: 200px;
line-height: 200px; /* 与父元素高度相同 */
}
.child { display: inline-block; }
适用场景:单行文本垂直居中。
回答: JavaScript 有 7 种基础数据类型(Primitive Types):
undefined
:表示未定义的值,变量声明但未赋值时默认值。null
:表示空值,通常用于显式清空变量。boolean
:布尔值,true
或 false
。number
:数值类型,包括整数、浮点数、NaN
(非数字)和 Infinity
。string
:字符串类型,如 "hello"
。symbol
(ES6):唯一且不可变的值,用于对象属性键。 const sym = Symbol('key');
obj[sym] = 'value'; // 唯一属性键
bigint
(ES2020):大整数,以 n
结尾,如 12345678901234567890n
。引用类型(非基础):
Object
(包括 Array
、Function
、Date
等)。类型检测:
typeof
检测基础类型(typeof null
返回 "object"
,是历史遗留问题)。
instanceof
检测引用类型。
回答: Symbol 的主要用途是创建唯一标识符,避免命名冲突:
const id = Symbol('id');
const user = {
[id]: '123', // 唯一键,外部无法直接访问
name: 'Alice'
};
console.log(user[id]); // '123'
Symbol.iterator
:定义对象的迭代器,支持 for...of
。 const iterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
}
};
Symbol.toStringTag
:自定义对象的 toString
输出。模拟私有属性:
const _private = Symbol('private');
class MyClass {
constructor() {
this[_private] = 'secret';
}
}
注意事项:
Object.keys()
或 JSON.stringify()
遍历。
Symbol.for('key')
可创建全局共享的 Symbol。
回答:
闭包是函数与其词法作用域的结合,即使外部函数执行完毕,内部函数仍能访问外部变量。
形成条件:
示例:
function outer() {
let count = 0;
return function inner() {
count++;
return count;
};
}
const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
闭包的作用:
封装私有变量:避免全局污染。
模块化开发:通过 IIFE(立即执行函数)暴露公共接口。
const module = (function() {
let privateVar = 0;
return {
increment: () => privateVar++,
getValue: () => privateVar
};
})();
内存泄漏风险:
counter = null
)。回答: 实际开发中闭包常用于以下场景:
防抖(Debounce)与节流(Throttle):
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
函数柯里化(Currying):
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return (...nextArgs) => curried.apply(this, args.concat(nextArgs));
}
};
}
React Hooks:
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer); // 闭包保留timer
}, []);
回答:
特性 | 防抖(Debounce) | 节流(Throttle) |
---|---|---|
定义 | 事件触发后延迟执行,若期间重复触发则重新计时。 | 事件触发后固定时间间隔执行一次。 |
适用场景 | 搜索框输入联想、窗口 resize。 | 滚动加载、高频点击(如抢购按钮)。 |
实现原理 | 每次触发重置定时器。 | 通过时间戳或定时器限制执行频率。 |
代码实现对比:
// 防抖
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流(时间戳版)
function throttle(fn, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
回答: ES5 通过原型链实现继承的完整步骤:
定义父类构造函数和原型方法:
function Parent(name) {
this.name = name;
}
Parent.prototype.say = function() {
console.log('Parent:', this.name);
};
定义子类构造函数并继承父类实例属性:
function Child(name, age) {
Parent.call(this, name); // 继承父类实例属性
this.age = age;
}
设置子类原型为父类实例:
Child.prototype = Object.create(Parent.prototype);
// 修复构造函数指向
Child.prototype.constructor = Child;
添加子类原型方法:
Child.prototype.intro = function() {
console.log('Child:', this.name, this.age);
};
测试代码:
const child = new Child('Alice', 12);
child.say(); // Parent: Alice
child.intro(); // Child: Alice 12
缺点:
Parent.call()
和 new Parent()
)。
回答:
普通函数和箭头函数在语法、作用域、this
绑定等方面有显著差异:
特性 | 普通函数 | 箭头函数 |
---|---|---|
语法 | 使用 function 关键字定义。 | 使用 => 箭头语法,可省略 {} 和 return。 |
this 绑定 | 动态绑定,由调用方式决定(如 obj.fn() 的 this 是 obj)。 | 静态绑定,继承外层作用域的 this(定义时的上下文)。 |
arguments | 可用 arguments 对象获取参数列表。 | 无 arguments,需用剩余参数(...args)。 |
构造函数 | 可作为构造函数,通过 new 调用生成实例。 | 不可作为构造函数,new 调用会报错。 |
原型链 | 有 prototype 属性,用于继承。 | 无 prototype 属性。 |
方法简写 | 在对象字面量中需完整定义:method: function() {}。 | 可简写为:method() {}(但此时是普通函数)。 |
示例 1:this
绑定的差异
const obj = {
name: 'obj',
regularFunc: function() {
console.log(this.name); // 输出 'obj'
},
arrowFunc: () => {
console.log(this.name); // 输出 undefined(外层无 name)
}
};
obj.regularFunc();
obj.arrowFunc();
示例 2:箭头函数与 arguments
function regular() {
console.log(arguments); // Arguments(3) [1, 2, 3]
}
const arrow = () => {
console.log(arguments); // ReferenceError: arguments is not defined
};
regular(1, 2, 3);
arrow(1, 2, 3);