百度八股 面经
获取 DOM 元素的方式,DOM 元素选择器
常见的 DOM 元素选择器
-
document.getElementById(id):通过元素的 ID 获取元素。javascript 复制代码 const element = document.getElementById('myId'); -
document.getElementsByClassName(className):通过类名获取元素集合。javascript 复制代码 const elements = document.getElementsByClassName('myClass'); -
document.getElementsByTagName(tagName):通过标签名获取元素集合。javascript 复制代码 const elements = document.getElementsByTagName('div'); -
document.querySelector(selector):通过 CSS 选择器获取第一个匹配的元素。javascript 复制代码 const element = document.querySelector('.myClass'); -
document.querySelectorAll(selector):通过 CSS 选择器获取所有匹配的元素集合。javascript 复制代码 const elements = document.querySelectorAll('.myClass');
计算机网络 7 层模型
- 物理层:传输介质、信号
- 数据链路层:以太网、MAC 地址
- 网络层:IP、ICMP
- 传输层:TCP、UDP
- 会话层:PPTP
- 表示层:JPEG、MPEG、SSL
- 应用层:HTTP、FTP、SMTP、DNS
为什么是 7 层
7 层模型(OSI 模型)将网络通信分解为更小的、更容易管理的部分,每层都有明确的功能和职责,使得网络设计、实现和调试更加简单和模块化。
设计模式
发布-订阅者模式(Observer Pattern)
发布-订阅者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers() {
this.observers.forEach(observer => observer.update());
}
}
class Observer {
update() {
console.log('Observer updated');
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers();
单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供一个全局访问点。
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
工厂模式(Factory Pattern)
工厂模式提供了一种创建对象的接口,而不指定具体的类。它让子类决定实例化哪个类。
class Car {
constructor() {
this.type = 'Car';
}
}
class Truck {
constructor() {
this.type = 'Truck';
}
}
class VehicleFactory {
createVehicle(vehicleType) {
switch(vehicleType) {
case 'car':
return new Car();
case 'truck':
return new Truck();
default:
return null;
}
}
}
const factory = new VehicleFactory();
const car = factory.createVehicle('car');
console.log(car.type); // Car
Vue 3 和 Vue 2 的区别
- Composition API:Vue 3 引入了 Composition API,使得逻辑复用和代码组织更灵活。
- 更好的性能:Vue 3 在内部进行了优化,使得性能比 Vue 2 更好。
- 更小的体积:Vue 3 通过 tree-shaking 技术使得包的体积更小。
- Proxy 代替 Object.defineProperty:Vue 3 使用 Proxy 进行响应式处理,克服了 Vue 2 中的一些限制。
- Fragment, Teleport 和 Suspense:Vue 3 引入了新的组件特性,提供了更多的灵活性和功能。
promise 的作用和用法
Promise 是一种用于处理异步操作的对象。它代表一个可能在将来完成或失败的操作及其结果。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then(result => {
console.log(result); // 'Success!'
}).catch(error => {
console.log(error);
});
async/await
async/await 是基于 Promise 的语法糖,使得异步代码更简洁和可读。
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
Vue 双向绑定原理
Vue实现双向绑定主要依靠数据劫持结合发布者-订阅者模式:
- 使用
Object.defineProperty()方法劫持各个属性的getter和setter, - 在数据变动时发布消息给订阅者,触发相应的监听回调。
闭包
createCounter是一个工厂函数,它创建并返回一个闭包,该闭包持续访问和修改count变量。
function createCounter() {
let count = 0;
return function() {
count += 1;
console.log(count);
};
}
const counter1 = createCounter();
counter1(); // 应输出什么?
counter1(); // 应输出什么?
const counter2 = createCounter();
counter2(); // 应输出什么?
counter1(); // 应输出什么?
counter2(); // 应输出什么?
CSS垂直居中
可以通过多种方式实现CSS垂直居中,常用的方法包括:
-
Flexbox:
.container { display: flex; align-items: center; /* 垂直居中 */ justify-content: center; /* 水平居中 */ } -
Grid:
.container { display: grid; place-items: center; /* 水平和垂直居中 */ } -
使用transform:
.child { position: relative; top: 50%; transform: translateY(-50%); }
隐藏元素方式、区别
display: none;: 完全从渲染树中移除,不占据空间,不会触发重绘或回流。visibility: hidden;: 元素隐藏但仍占据空间,会触发重绘。opacity: 0;: 元素透明但仍可交互和占据空间,会触发重绘。
原型和原型链
在JavaScript中,每个对象都有一个指向另一个对象的内部链接,称为其“原型”。这个原型对象本身也可能有原型,以此类推,这就形成了一个“原型链”。当你尝试访问一个对象的属性时,如果在当前对象上找不到,JavaScript会沿着这条原型链向上查找,直到找到该属性或者到达原型链的末端。
闭包
闭包是函数和声明该函数的词法环境的组合。闭包使得函数即使在外部函数已经执行完毕后,仍能访问到外部函数的作用域变量。
webpack优化
- 代码拆分:利用
import()语法或SplitChunksPlugin进行代码分割,按需加载。 - 压缩:使用
TerserPlugin等工具压缩JS和CSS。 - 缓存:通过设置
[contenthash]确保文件内容变更时更新缓存。 - Tree Shaking:去除未使用的代码。
你提到了很多前端开发和JavaScript的关键概念。我会逐一解释这些问题,同时也会涉及到一些代码示例。
原型和原型链
在JavaScript中,每个对象都有一个指向另一个对象的内部链接,称为其“原型”。这个原型对象本身也可能有原型,以此类推,这就形成了一个“原型链”。当你尝试访问一个对象的属性时,如果在当前对象上找不到,JavaScript会沿着这条原型链向上查找,直到找到该属性或者到达原型链的末端。
闭包
闭包是函数和声明该函数的词法环境的组合。闭包使得函数即使在外部函数已经执行完毕后,仍能访问到外部函数的作用域变量。
Webpack优化
- 代码拆分:利用
import()语法或SplitChunksPlugin进行代码分割,按需加载。 - 压缩:使用
TerserPlugin等工具压缩JS和CSS。 - 缓存:通过设置
[contenthash]确保文件内容变更时更新缓存。 - Tree Shaking:去除未使用的代码。
Node.js 线程
Node.js主要在单个线程上运行,使用非阻塞I/O操作。对于CPU密集型任务,Node.js可以使用worker_threads模块来实现多线程处理。
网络攻击防护
- 使用HTTPS保护数据传输。
- 对输入数据进行验证和清洗,避免SQL注入和XSS攻击。
- 使用Helmet增强Express应用的安全性。
JWT (JSON Web Tokens)
JWT用于在网络应用环境间传递声明。它可以用于认证和信息交换,其安全性基于数字签名,可以验证和信任发送方。
事件委托机制
事件委托利用了事件冒泡原理,只在父元素上设置一个事件监听器,管理多个子元素的事件。这样做可以减少内存消耗,避免多次事件注册。
JS 继承
JavaScript支持原型链继承,构造函数继承和ES6类继承。ES6之前常用的继承方式是组合继承,结合原型链和构造函数继承的优点。
localStorage 和 sessionStorage
localStorage和sessionStorage都是Web存储解决方案,用于在客户端存储键值对数据。localStorage数据没有时间限制,而sessionStorage数据在页面会话结束时被清除。
useState 渲染机制
在React中,useState是一个钩子(Hook),用于在函数组件中添加状态。当状态更新时,组件将重新渲染。
Flex布局
Flex布局是CSS的一种布局方式,允许容器内的项能够在不同屏幕尺寸上灵活地伸缩。
响应式布局
响应式布局是一种Web设计方法,目的是使Web页面能够响应用户的设备环境(屏幕大小、平台和方向)。
Promise
Promise是异步编程的一种解决方案,比传统的回调函数和事件更强大和合适。它代表了一个尚未完成但预计将来会完成的操作。
let 和 var 的作用域
let提供块级作用域,而var提供函数级作用域。使用let可以减少很多由于变量提升引起的问题。
await 和 Promise
await是用于等待Promise解决的关键字,只能在async函数中使用。它可以让异步代码以同步的方式写出来,更易于理解和维护。
map 的执行方式
JavaScript的Array.prototype.map()方法是串行执行的。每个元素的处理结果将组成新数组返回。
Less 的优势
Less是一种动态样式语言,扩展了CSS的静态特性,提供变量、混合、函数等特性,有助于编写更加清晰和可维护的CSS代码。
打包和线下编译的过程
代码打包通常包括合并、压缩JavaScript和CSS文件,以减少请求次数和减少文件大小。线下编译则是在本地或开发环境完成这一过程,生成可以直接部署到生产环境的代码。
package.json 的重要属性
dependencies: 生产环境下应用所依赖的模块。devDependencies: 开发环境下所需要的模块,如测试框架和构建工具。scripts: 定义了项目中可以运行的脚本命令。name和version: 包的名称和版本号,用于发布和依赖管理。
dependencies 和 devDependencies 的区别
dependencies是项目运行时所必需的。devDependencies是开发时需要的,不会在生产环境下安装。
WebSocket
WebSocket 是一种在单个TCP连接上进行全双工通讯的协议。它使得客户端和服务器能够实时地进行双向数据传输。
应用场景:
- 实时聊天应用
- 在线游戏
- 实时数据更新(股票行情、体育赛事)
跨域解决方案
跨域是指浏览器的同源策略限制从一个源(域名、协议、端口)加载资源或脚本到另一个源。
解决方案:
- JSONP:通过动态添加
<script>标签来实现跨域请求,仅支持GET请求。 - CORS:服务器在响应头中设置
Access-Control-Allow-Origin来允许跨域请求。 - 代理服务器:通过同源的代理服务器转发请求到目标服务器。
- PostMessage:通过iframe与主页面进行安全的跨域通信。
GET 和 POST 请求的区别
-
GET:
- 用于请求数据
- 参数包含在URL中
- 请求长度有限制
- 不安全,敏感信息容易暴露在URL中
-
POST:
- 用于提交数据
- 参数包含在请求体中
- 请求长度较大,无明显限制
- 更安全,敏感信息不会暴露在URL中
输入URL到渲染的过程
- DNS解析:将域名解析为IP地址
- TCP连接:通过三次握手建立TCP连接
- 发送HTTP请求:浏览器发送HTTP请求到服务器
- 服务器响应:服务器处理请求并返回资源
- 浏览器渲染:浏览器解析HTML、CSS和JavaScript,构建DOM树和CSSOM树,生成渲染树,布局和绘制页面
var, let, const 的区别
-
var:
- 函数作用域
- 存在变量提升
- 可以重复声明
-
let:
- 块级作用域
- 不存在变量提升
- 不可重复声明
-
const:
- 块级作用域
- 不存在变量提升
- 不可重复声明
- 声明时必须赋值,且值不可变(引用类型的值可变)
== 和 === 的区别,null 和 undefined
- ==:比较时会进行类型转换
- ===:比较时不会进行类型转换,类型和值都要相等
- null:表示空值,手动赋值为空
- undefined:表示未定义,变量声明但未赋值
深拷贝和浅拷贝
-
浅拷贝
:只复制对象的引用,不复制对象本身
- 方法:
Object.assign(),Array.prototype.slice()
- 方法:
-
深拷贝
:复制对象本身及其所有嵌套对象
-
方法:
JSON.parse(JSON.stringify()),手动递归复制 -
JSON.parse(JSON.stringify()) 存在的问题
- 循环引用:会导致报错。
- 丢失函数:无法拷贝函数。
- 丢失特殊对象:如
Date对象、RegExp对象会丢失原有类型和方法。 - 无法拷贝原型链:拷贝的对象没有原型链。
-
const a = [1, 2, 3, 4];
const b = a;
a.push(5);
console.log(a); // [1, 2, 3, 4, 5]
console.log(b); // [1, 2, 3, 4, 5]
18. 使 b 不被改变
使用浅拷贝或深拷贝。
-
浅拷贝:
const a = [1, 2, 3, 4]; const b = [...a]; a.push(5); console.log(a); // [1, 2, 3, 4, 5] console.log(b); // [1, 2, 3, 4] -
深拷贝:
const a = [1, 2, 3, 4]; const b = JSON.parse(JSON.stringify(a)); a.push(5); console.log(a); // [1, 2, 3, 4, 5] console.log(b); // [1, 2, 3, 4]
盒模型,怪异盒模型
- 标准盒模型:
width和height只包含内容,不包含padding和border - 怪异盒模型:
width和height包含内容、padding和border
px, em, rem
- px:像素,相对屏幕分辨率
- em:相对父元素字体大小
- rem:相对根元素字体大小
cookie, localStorage, sessionStorage 的区别
-
cookie:
- 由服务器生成
- 存储在客户端,每次请求都会发送到服务器
- 容量小(约4KB)
-
localStorage:
- 持久化存储数据,除非手动删除,否则数据不会过期
- 容量大(约5MB)
-
sessionStorage:
- 会话级存储数据,浏览器关闭后数据被清除
- 容量大(约5MB)
v-show 和 v-if 的区别
- v-show:通过设置
display属性来显示或隐藏元素,切换开销较小 - v-if:通过条件渲染来插入或删除DOM元素,切换开销较大
computed 和 watch 的区别
- computed:计算属性,基于依赖缓存结果,只有依赖发生变化时才重新计算
- watch:监听属性,监视某个数据的变化并执行回调
虚拟DOM,diff算法
- 虚拟DOM:用JavaScript对象表示DOM结构,更新时对比新旧虚拟DOM,最小化实际DOM操作
- diff算法:通过分层对比和同层比较,实现高效的差异更新
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式是函数内部返回一个函数。
发现网页加载慢,如何排查,解决优化
排查方法:
- 使用浏览器开发者工具查看网络请求和资源加载情况
- 检查页面的渲染性能
解决优化:
- 减少HTTP请求数
- 使用CDN加速
- 图片懒加载
- 压缩资源文件
- 使用缓存
- 优化JavaScript和CSS
CSS 选择器及其权重
- 元素选择器:权重为 1,例如
div - 类选择器:权重为 10,例如
.class - ID 选择器:权重为 100,例如
#id - 内联样式:权重为 1000,例如
<div style="color: red;"> - 伪类选择器:例如
:hover - 伪元素选择器:例如
::before