HTML & CSS
1. HTML5 新增的表单元素有哪些?它们各自适用于哪些场景?
1 . <datalist>
<datalist>
元素可与<input>
元素配合使用,为输入框提供预定义的选项列表。当用户输入时,会显示与之匹配的选项,供用户选择。
ini
<label for="ice-cream-choice">选择你喜欢的冰淇淋口味:</label>
<input list="ice-cream-flavors" id="ice-cream-choice" name="ice-cream-choice" />
<datalist id="ice-cream-flavors">
<option value="巧克力">
<option value="香草">
<option value="草莓">
<option value="薄荷巧克力">
<option value="曲奇奶油">
</datalist>
适用场景:当你希望用户从一个预定义的列表中选择选项,但又允许用户输入其他值时,可以使用<datalist>
。比如,搜索框的自动补全功能、选择城市名称等。
2. <keygen>
<keygen>
元素可用于生成公钥和私钥对,在提交表单时,公钥会被发送到服务器,用于加密通信。不过,由于安全问题,该元素已被弃用。
ini
<form action="demo_keygen.asp" method="get">
用户名: <input type="text" name="usr_name">
加密: <keygen name="security">
<input type="submit">
</form>
适用场景:在早期,该元素适用于需要进行安全通信的场景,如在线银行、电子商务等。但如今已不建议使用,可采用更安全的加密技术。
3. <output>
<output>
元素用于显示计算或用户操作的结果。
ini
<form oninput="result.value=parseInt(a.value)+parseInt(b.value)">
<input type="number" id="a" value="0"> +
<input type="number" id="b" value="0"> =
<output name="result" for="a b"></output>
</form>
适用场景:适用于需要实时显示计算结果的表单,如计算器、表单验证结果显示等。
4. <progress>
<progress>
元素用于显示任务的完成进度,通常以条形图的形式呈现。
ini
<progress value="22" max="100"></progress>
适用场景:适用于显示文件上传进度、下载进度、任务完成百分比等。
<meter>
<meter>
元素用于显示已知范围的标量值,或分数值。
xml
<meter value="2" min="0" max="10">2 out of 10</meter>
<br>
<meter value="0.6">60%</meter>
适用场景:适用于显示磁盘使用情况、投票结果、考试成绩等。
2. CSS 中的 transform 属性有哪些常见的变换类型?请举例说明如何使用这些变换实现动画效果。
常见变换类型
- 平移(translate) :能够让元素在水平和垂直方向上移动。
-
translateX(x)
:让元素在水平方向移动x
的距离。translateY(y)
:让元素在垂直方向移动y
的距离。translate(x, y)
:让元素在水平和垂直方向同时移动。
- 旋转(rotate) :可以使元素绕着一个点旋转。
-
rotate(angle)
:让元素按顺时针方向旋转指定的角度。
- 缩放(scale) :对元素进行放大或缩小。
-
scaleX(x)
:在水平方向上按x
的比例缩放。scaleY(y)
:在垂直方向上按y
的比例缩放。scale(x, y)
:在水平和垂直方向上按指定比例缩放。
- 倾斜(skew) :让元素在水平和垂直方向上倾斜。
-
skewX(angle)
:在水平方向上倾斜指定角度。skewY(angle)
:在垂直方向上倾斜指定角度。skew(x-angle, y-angle)
:在水平和垂直方向上同时倾斜。
实现动画
配合animation实现动画
css
.box {
animation: transformAnimation 5s infinite;
}
@keyframes transformAnimation {
0 % {
transform: translate(0, 0) rotate(0deg) scale(1) skew(0deg, 0deg);
}
100% {
transform: translate(0, 0) rotate(360deg) scale(1) skew(0deg, 0deg);
}
}
3. 详细阐述 CSS 中 display 属性的常用取值及其对应的布局特点。
- display: block
- 元素会独占一行,不管其内容的宽度如何,都会从新的一行开始显示。
- 可以设置宽度和高度,默认宽度是其父元素的 100%。
- 能够设置上下左右的外边距(margin)和内边距(padding)。
- display: inline
- 元素会在同一行内显示,不会换行。
- 无法设置宽度和高度,宽度和高度由其内容决定。
- 只能设置左右外边距和内边距,上下外边距和内边距的设置不会影响布局。
- display: inline-block
- 元素会在同一行内显示,不会换行。
- 可以设置宽度和高度。
- 能够设置上下左右的外边距和内边距。
- display: none
- 元素不会在页面中显示,并且不会占据页面的空间,就好像该元素不存在一样。
- display: flex
- 开启弹性盒模型布局,子元素会按照弹性容器的规则进行排列。
- 可以通过
flex-direction
、justify-content
、align-items
等属性来控制子元素的排列方向、水平对齐方式和垂直对齐方式。
- display: grid
- 开启网格布局模型,子元素会按照网格容器的规则进行排列。
- 可以通过
grid-template-columns
、grid-template-rows
等属性来定义网格的列和行。
- display: table、display: table-row、display: table-cell
- 模拟 HTML 表格的布局方式,
display: table
将元素显示为表格,display: table-row
将元素显示为表格行,display: table-cell
将元素显示为表格单元格。 - 可以实现类似表格的布局效果,并且可以通过 CSS 控制表格的样式。
4. 如何使用 CSS 实现一个粘性导航栏(sticky navigation),即在页面滚动到一定位置时导航栏固定在顶部?
- 方案一
position: sticky
属性达成
- 方案二
js监听滚动条+css控制position
(二)JavaScript
1. 深入分析 JavaScript 中函数的防抖(Debounce)和节流(Throttle)原理,并分别举例说明在实际项目中的应用场景。
防抖
- 原理
防抖的核心概念是,在用户频繁触发某个事件时,只有当事件停止触发一段时间后,才会执行相应的处理函数。具体来说,当事件第一次被触发时,会开启一个定时器,若在定时器设定的时间内事件再次被触发,就会清除之前的定时器并重新开启一个新的定时器。只有当在设定时间内没有新的事件触发,定时器计时结束后,才会执行处理函数。
简单的防抖函数实现:
ini
function debounce(func, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
- 场景
搜索框、窗口大小改变事件、
节流
- 原理
节流的主要目的是限制函数的执行频率,确保在一定的时间间隔内,函数只能执行一次。当事件触发时,会检查距离上一次函数执行的时间是否超过了设定的时间间隔。如果超过了,就执行函数并更新上次执行的时间;如果没有超过,则忽略此次触发。
基于时间戳的节流函数实现:
ini
function throttle(func, limit) {
let lastExecTime = 0;
return function() {
const now = Date.now();
const context = this;
const args = arguments;
if (now - lastExecTime >= limit) {
func.apply(context, args);
lastExecTime = now;
}
};
}
- 场景
滚动加载、点击限流等
2. 请描述 JavaScript 中事件流的三个阶段,以及如何利用事件流机制进行事件委托。
事件流的三个阶段
- 捕获阶段
事件从最外层元素(如document
或window
)逐级向目标元素传播。
-
- 特点 :默认不触发监听函数,需通过
addEventListener(event, handler, true)
显式启用。 - 应用场景:在事件到达目标前拦截处理,例如全局权限校验或日志记录。
- 特点 :默认不触发监听函数,需通过
- 目标阶段
事件到达目标元素,触发其绑定的事件处理函数。
-
- 特点:无论事件监听器设置在捕获还是冒泡阶段,都会在此阶段执行。
- 示例 :点击按钮时,按钮自身的
click
事件在此阶段响应。
- 冒泡阶段
事件从目标元素逐级向上冒泡至最外层元素。
-
- 特点 :默认触发机制,可通过
addEventListener(event, handler, false)
(或省略第三个参数)设置监听。 - 应用场景:事件委托的实现基础
- 特点 :默认触发机制,可通过
事件委托
- 原理
事件委托是利用事件流的冒泡阶段来实现的一种技术。它的核心思想是将事件处理程序绑定到一个共同的祖先元素上,而不是为每个子元素都单独绑定事件处理程序。当子元素上的事件触发时,事件会冒泡到祖先元素上,祖先元素上的事件处理程序就可以根据事件的来源(event.target)来进行相应的处理。
- 示例
javascript
// 示例:为父元素绑定点击事件,统一处理子元素的点击
document.getElementById('parent').addEventListener('click', function(event) {
const target = event.target; // 获取实际触发的子元素
if (target.classList.contains('child')) {
console.log('子元素被点击:', target.id);
// 执行具体逻辑(如跳转、数据加载等)
}
});
- 优势
- 性能优化:减少事件监听器数量,降低内存消耗(尤其适用于列表、表格等大量子元素场景)。
- 动态适配:自动支持后续动态添加的子元素,无需重复绑定事件。
- 代码简洁:统一管理逻辑,避免重复代码
3. 解释 JavaScript 中Object.create()
方法的作用,与使用构造函数创建对象相比,它有什么优势?
Object.create()
是 JavaScript 中用于创建新对象的核心方法,其核心作用是通过 指定原型对象 和 属性描述符 来动态生成对象。具体语法:
css
Object.create(proto, [propertiesObject])
proto
:这是必需参数,代表新对象的原型对象。propertiesObject
:这是可选参数,是一个对象,用于为新对象定义额外的属性。
a. 作用
原型继承
Object.create(proto)
会创建一个新对象,并将该对象的原型([[Prototype]]
)指向传入的 proto
参数。这意味着新对象可以直接继承原型对象的属性和方法
例如:
ini
const animal = { eat() { console.log("Eating..."); } };
const dog = Object.create(animal);
dog.eat(); // 输出 "Eating..." [7](@ref)
自定义属性特性
通过第二个参数 propertiesObject
,可以为新对象定义属性的特性(如可写性 writable
、可枚举性 enumerable
、可配置性 configurable
),从而精确控制属性的行为
例如:
php
const person = Object.create({}, {
name: {
value: "John",
writable: false, // 不可修改
enumerable: true
}
});
创建无原型对象
当传入 proto
为 null
时,可以创建一个完全纯净的对象(无 Object.prototype
继承),避免原型链上的方法干扰,适合作为轻量级字典
例如:
ini
const pureObj = Object.create(null);
pureObj.key = "value";
console.log(pureObj.toString); // undefined [5](@ref)
b. 对比
原型链控制的灵活性
Object.create()
:
直接指定新对象的原型,适合需要动态继承或组合式继承的场景。例如,可以从多个原型对象继承属性和方法。- 构造函数(
new
) :
新对象的原型固定为构造函数的prototype
属性,继承关系受限于构造函数的定义。
避免构造函数调用的开销
Object.create()
:
无需调用构造函数,适合不需要复杂初始化逻辑的场景,减少内存和性能开销。- 构造函数(
new
) :
必须执行构造函数内部的代码(如this
属性初始化),若构造函数包含复杂逻辑,可能影响性能。
属性特性的精细控制
Object.create()
:
支持通过属性描述符定义属性的可写性、可枚举性等特性,适合需要严格限制属性行为的场景。- 构造函数(
new
) :
属性默认均为可写、可枚举,需额外调用Object.defineProperty()
修改属性特性。
纯净对象的创建
Object.create(null)
:
生成的对象无Object.prototype
继承,避免原型方法(如hasOwnProperty
)的冲突,适合作为数据容器。- 构造函数(
new
) :
所有实例默认继承Object.prototype
,可能引入不必要的原型方法。
组合式继承的实现
Object.create()
:
常用于实现组合式继承(如混合模式),允许对象灵活组合多个原型的特性。例如:
ini
const canEat = { eat() {} };
const canWalk = { walk() {} };
const person = Object.create(canEat);
Object.assign(person, canWalk); // 组合多个原型特性
- 构造函数(
new
) :
只能通过原型链实现单继承,若需多继承需手动绑定方法或使用复杂设计模式。
c. 优势
更灵活的原型链控制
无需依赖构造函数,可直接指定任意对象作为原型,甚至实现无原型对象
避免构造函数副作用
不执行构造函数代码,减少资源消耗(如避免网络请求或 DOM 操作)
精细化的属性管理
支持通过属性描述符定义属性的可枚举性(enumerable
)、可写性(writable
)等特性,提升代码安全性
支持高级继承模式
如组合继承、寄生组合继承等,解决构造函数继承中的原型链冗余问题
d. 总结
- 优先使用 ****
Object.create()
:当需要精确控制原型链、定义不可变属性,或避免构造函数副作用时。 - 选择构造函数(
new
) :当需要批量初始化对象、共享方法,或利用面向对象编程的经典模式时。
4. 说一说 JavaScript 中的严格模式(strict mode)有哪些限制和好处,如何启用严格模式?
a. 严格模式的主要限制
严格模式通过抛出错误或禁止某些语法,强制开发者编写更规范的代码,具体限制包括:
变量必须声明后使用
未声明的变量赋值会抛出 ReferenceError
,防止意外创建全局变量
javascript
"use strict";
a = 10; // 报错:a未定义
禁止重复参数名或属性名
函数参数或对象属性重复命名会触发 SyntaxError
javascript
"use strict";
function foo(a, a) {} // 报错:参数名重复
禁止删除不可删除的属性
删除变量、函数或不可配置的属性会抛出 TypeError
javascript
"use strict";
delete Object.prototype; // 报错:不可删除
禁用八进制字面量语法
禁止使用 0
前缀的八进制表示(如 0123
),需改用 0o
前缀
javascript
"use strict";
let num = 0o123; // 合法
限制 this
的默认指向
普通函数独立调用时,this
为 undefined
,避免误操作全局对象
javascript
"use strict";
function test() { console.log(this); } // 输出:undefined
禁止 with
语句
with
语句会导致作用域混乱,严格模式下直接禁用
javascript
"use strict";
with (Math) { x = cos(PI) }; // 报错
隔离 eval
作用域
eval
内部定义的变量不会泄露到外部作用域
javascript
"use strict";
eval("var z = 30;");
console.log(z); // 报错:z未定义
b. 好处
消除静默错误
将原本隐式忽略的错误(如未声明变量、修改只读属性)显式抛出,提升代码健壮性
提升代码安全性
禁止 eval
污染全局作用域、限制 this
指向,避免意外修改全局对象
优化引擎执行效率
修复阻碍 JavaScript 引擎优化的语法(如动态绑定),使代码运行更快
为未来语法铺路
提前禁用可能在未来版本中废弃的语法,确保代码兼容性
c. 启用严格模式
- 全局启用
在 JavaScript 文件的开头添加 "use strict";
或 'use strict';
语句,整个文件都会处于严格模式下。例如:
javascript
'use strict';
// 以下代码都处于严格模式
function func() {
// 函数内部也是严格模式
}
- 函数内启用
在函数内部的第一行添加 "use strict";
或 'use strict';
语句,该函数及其内部嵌套的函数都会处于严格模式下。例如:
csharp
function func() {
'use strict';
// 此函数内部是严格模式
function innerFunc() {
// 嵌套函数也是严格模式
}
}
5. 如何在 JavaScript 中检测一个对象是否为数组?请列举至少两种方法,并说明它们的优缺点。
Array.isArray()
原理 :
通过 ES5 标准提供的内置方法直接判断对象是否为数组,是官方推荐的最优方案。
示例:
javascript
const arr = [1, 2, 3];
console.log(Array.isArray(arr)); // true
console.log(Array.isArray({})); // false
优点:
- 准确可靠 :专为数组检测设计,能正确处理跨
iframe
的数组实例。 - 简洁高效:语法直观,无需额外封装,性能优于其他方法。
- 兼容性好:现代浏览器及 Node.js 均支持,旧环境可通过 Polyfill 实现。
缺点 :
在 ES5 之前的浏览器(如 IE8)中不支持,需结合 Polyfill 使用。
Object.prototype.toString.call()
原理 :
利用对象内部属性 [[Class]]
返回类型字符串,通过比对 [object Array]
判断是否为数组。
示例:
javascript
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(isArray([1, 2])); // true
console.log(isArray({})); // false
优点:
- 通用性强 :支持所有对象类型检测(如区分数组、对象、
null
等)。 - 兼容性极佳:适用于所有 JavaScript 环境,包括旧版浏览器。
- 稳定性高:不受原型链修改或跨框架问题影响。
缺点 :
语法稍显复杂,需手动封装函数,可读性略逊于 Array.isArray()
。