百度八股 面经

154 阅读12分钟

百度八股 面经

获取 DOM 元素的方式,DOM 元素选择器

常见的 DOM 元素选择器

  1. document.getElementById(id) :通过元素的 ID 获取元素。

    javascript
    复制代码
    const element = document.getElementById('myId');
    
  2. document.getElementsByClassName(className) :通过类名获取元素集合。

    javascript
    复制代码
    const elements = document.getElementsByClassName('myClass');
    
  3. document.getElementsByTagName(tagName) :通过标签名获取元素集合。

    javascript
    复制代码
    const elements = document.getElementsByTagName('div');
    
  4. document.querySelector(selector) :通过 CSS 选择器获取第一个匹配的元素。

    javascript
    复制代码
    const element = document.querySelector('.myClass');
    
  5. document.querySelectorAll(selector) :通过 CSS 选择器获取所有匹配的元素集合。

    javascript
    复制代码
    const elements = document.querySelectorAll('.myClass');
    

计算机网络 7 层模型

  1. 物理层:传输介质、信号
  2. 数据链路层:以太网、MAC 地址
  3. 网络层:IP、ICMP
  4. 传输层:TCP、UDP
  5. 会话层:PPTP
  6. 表示层:JPEG、MPEG、SSL
  7. 应用层: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垂直居中,常用的方法包括:

  1. Flexbox:

    .container {
      display: flex;
      align-items: center; /* 垂直居中 */
      justify-content: center; /* 水平居中 */
    }
    
  2. Grid:

    .container {
      display: grid;
      place-items: center; /* 水平和垂直居中 */
    }
    
  3. 使用transform:

    .child {
      position: relative;
      top: 50%;
      transform: translateY(-50%);
    }
    

隐藏元素方式、区别

  1. display: none; : 完全从渲染树中移除,不占据空间,不会触发重绘或回流。
  2. visibility: hidden; : 元素隐藏但仍占据空间,会触发重绘。
  3. opacity: 0; : 元素透明但仍可交互和占据空间,会触发重绘。

原型和原型链

在JavaScript中,每个对象都有一个指向另一个对象的内部链接,称为其“原型”。这个原型对象本身也可能有原型,以此类推,这就形成了一个“原型链”。当你尝试访问一个对象的属性时,如果在当前对象上找不到,JavaScript会沿着这条原型链向上查找,直到找到该属性或者到达原型链的末端。

闭包

闭包是函数和声明该函数的词法环境的组合。闭包使得函数即使在外部函数已经执行完毕后,仍能访问到外部函数的作用域变量。

webpack优化

  1. 代码拆分:利用import()语法或SplitChunksPlugin进行代码分割,按需加载。
  2. 压缩:使用TerserPlugin等工具压缩JS和CSS。
  3. 缓存:通过设置[contenthash]确保文件内容变更时更新缓存。
  4. Tree Shaking:去除未使用的代码。

你提到了很多前端开发和JavaScript的关键概念。我会逐一解释这些问题,同时也会涉及到一些代码示例。

原型和原型链

在JavaScript中,每个对象都有一个指向另一个对象的内部链接,称为其“原型”。这个原型对象本身也可能有原型,以此类推,这就形成了一个“原型链”。当你尝试访问一个对象的属性时,如果在当前对象上找不到,JavaScript会沿着这条原型链向上查找,直到找到该属性或者到达原型链的末端。

闭包

闭包是函数和声明该函数的词法环境的组合。闭包使得函数即使在外部函数已经执行完毕后,仍能访问到外部函数的作用域变量。

Webpack优化

  1. 代码拆分:利用import()语法或SplitChunksPlugin进行代码分割,按需加载。
  2. 压缩:使用TerserPlugin等工具压缩JS和CSS。
  3. 缓存:通过设置[contenthash]确保文件内容变更时更新缓存。
  4. 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

localStoragesessionStorage都是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: 定义了项目中可以运行的脚本命令。
  • nameversion: 包的名称和版本号,用于发布和依赖管理。

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到渲染的过程

  1. DNS解析:将域名解析为IP地址
  2. TCP连接:通过三次握手建立TCP连接
  3. 发送HTTP请求:浏览器发送HTTP请求到服务器
  4. 服务器响应:服务器处理请求并返回资源
  5. 浏览器渲染:浏览器解析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]
    

盒模型,怪异盒模型

  • 标准盒模型widthheight只包含内容,不包含paddingborder
  • 怪异盒模型widthheight包含内容、paddingborder

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