【前端学习|面试题】JavaScript合集(三)

Promise优缺点

优点:

  1. 更优雅的异步编程:Promise提供了一种更优雅的方式来处理异步操作,避免了回调地狱(Callback Hell)的问题。通过使用链式调用的方式,可以更清晰地表达异步操作的顺序和依赖关系。
  2. 更好的错误处理:Promise可以通过catch方法捕获异步操作的错误,使错误处理变得更加简洁和一致。在链式调用中,可以在任何一个then方法中捕获错误,而不需要在每个异步操作的回调函数中单独处理错误。
  3. 更好的可读性和可维护性:Promise的链式调用可以使异步代码更易于阅读和理解。每个then方法都可以返回一个新的Promise对象,使得代码的逻辑更加清晰,减少了嵌套的层级。
  4. 更好的错误追踪:Promise可以捕获和传递错误,使得错误的来源更加明确。在链式调用中,每个then方法都可以单独处理错误,可以更精确地定位错误发生的位置。
  5. 支持并行和串行操作:Promise提供了Promise.allPromise.race方法,可以方便地处理多个异步操作的并行和串行执行。Promise.all可以等待多个Promise都完成后再执行后续操作,Promise.race可以在任意一个Promise完成后立即执行后续操作。

缺点:

  1. 不支持取消:一旦创建了一个Promise对象,就无法取消它。这意味着一旦启动了一个异步操作,就无法中途停止或取消它。
  2. 无法处理同步操作:Promise主要用于处理异步操作,对于同步操作来说,使用Promise可能会增加代码的复杂性和冗余性。
  3. 不支持错误重试:Promise本身不提供错误重试的机制,需要额外的代码来实现错误重试的逻辑。
  4. 需要兼容性处理:Promise是ES6引入的特性,不支持ES6的环境需要使用polyfill或转译工具来兼容。

谈谈Promise.all方法、Promise.race方法以及使用

  Promise.allPromise.race是Promise对象提供的两个静态方法,用于处理多个Promise对象的并行串行执行。

  1. Promise.allPromise.all方法接收一个Promise对象数组作为参数,并返回一个新的Promise对象。这个新的Promise对象在所有传入的Promise对象都成功完成时才会被解决(Fulfilled),并将所有Promise对象的结果以数组的形式传递给then方法。如果任何一个Promise对象失败(Rejected),则新的Promise对象会立即被拒绝(Rejected),并将第一个失败的Promise对象的原因传递给catch方法。
  2. Promise.racePromise.race方法接收一个Promise对象数组作为参数,并返回一个新的Promise对象。这个新的Promise对象在传入的Promise对象中有任何一个成功完成时就会被解决(Fulfilled),并将第一个成功的Promise对象的结果传递给then方法。如果所有的Promise对象都失败(Rejected),则新的Promise对象会立即被拒绝(Rejected),并将第一个失败的Promise对象的原因传递给catch方法。

浏览器缓存机制

  浏览器缓存机制是指浏览器在加载网页时,将一些资源(如HTML、CSS、JavaScript、图像等)保存在本地的缓存中,以便在后续访问同一网页时可以直接从缓存中获取资源,而不需要再次从服务器下载。

  1. 缓存位置:浏览器缓存可以分为多个位置,包括内存缓存磁盘缓存。内存缓存速度更快,但容量较小,而磁盘缓存速度较慢,但容量较大。
  2. 缓存策略:浏览器根据资源的缓存策略来确定是否缓存资源以及缓存的有效期。常见的缓存策略包括强缓存和协商缓存。
    • 强缓存:通过设置Cache-ControlExpires响应头来控制资源的缓存。Cache-Control可以指定缓存的最大有效时间,而Expires是一个具体的过期时间。当资源的缓存有效期内,浏览器会直接从缓存中获取资源,而不发送请求到服务器。
    • 协商缓存:通过设置ETagLast-Modified响应头来控制资源的缓存。服务器在响应中返回资源的唯一标识符(ETag)和最后修改时间(Last-Modified)。当浏览器再次请求资源时,会将这些标识符发送给服务器,服务器根据标识符判断资源是否发生了变化。如果资源没有变化,服务器返回304状态码,浏览器直接从缓存中获取资源;如果资源发生了变化,服务器返回新的资源,浏览器将新的资源缓存起来。
  3. 缓存控制:开发人员可以通过设置响应头来控制资源的缓存行为。常见的响应头包括Cache-ControlExpiresETagLast-Modified等。
    • Cache-Control:用于设置缓存的行为,如max-age(指定缓存的最大有效时间),public(可被所有用户缓存)、private(仅限个人用户缓存)、no-cache(不缓存,每次都向服务器请求)等。
    • Expires:用于指定资源的过期时间,是一个具体的日期时间。
    • ETag:用于标识资源的唯一标识符,由服务器生成,用于判断资源是否发生变化。
    • Last-Modified:用于指示资源的最后修改时间,由服务器设置。
  4. 缓存清除:浏览器提供了清除缓存的功能,用户可以手动清除缓存,或者开发人员可以通过修改资源的URL或添加版本号等方式来强制浏览器重新下载资源。

对async/await的理解

  async/await 是 JavaScript 中处理异步操作的一种语法糖,它基于 Promise 对象,使得异步代码的编写和阅读更加简洁和直观。它使得异步操作的流程控制更加类似于同步代码,提高了代码的可读性和可维护性。

  async 关键字用于定义一个函数,表示该函数是一个异步函数,函数内部可以使用 await 关键字来等待一个 Promise 对象的解析结果。当函数执行到 await 关键字时,它会暂停执行并等待 Promise 对象的状态变为 resolved(解决)或 rejected(拒绝),然后继续执行后续代码。

  • 异步函数:使用 async 关键字定义的函数被称为异步函数。异步函数内部可以包含异步操作,如异步请求、定时器等。
  • 等待 Promise 对象:使用 await 关键字可以等待一个 Promise 对象的解析结果。在等待期间,函数会暂停执行,直到 Promise 对象的状态变为 resolved 或 rejected。
  • 返回 Promise 对象:异步函数内部可以使用 return 关键字返回一个值,这个值会被包装成一个 Promise 对象。如果没有显式使用 return 返回值,则函数会隐式返回一个 resolved 状态的 Promise 对象。
  • 错误处理:在异步函数中,可以使用 try/catch 语句来捕获和处理 Promise 对象的拒绝状态。在 try 块中使用 await 等待 Promise 对象,如果 Promise 对象被拒绝,则会跳转到 catch 块中进行错误处理。

await到底在等什么?

  await 关键字用于等待一个 Promise 对象的解析结果。当遇到 await 关键字时,它会暂停当前函数的执行,直到等到的 Promise 对象的状态变为 resolved(解决)或 rejected(拒绝)。

  具体来说,await 等待的是一个表达式,这个表达式可以是一个 Promise 对象,也可以是任何返回 Promise 对象的表达式。当遇到 await 关键字时,JavaScript 引擎会暂停当前函数的执行,并将控制权交给调用者,直到等到的 Promise 对象的状态发生变化。

async/await如何捕捉异常?

  在使用 async/await 进行异步操作时,可以使用 try/catch 语句来捕捉和处理 Promise 对象的拒绝状态。

具体的步骤如下:

  1. 在异步函数内部使用 try 关键字开始一个代码块。
  2. try 块中使用 await 关键字等待一个 Promise 对象的解析结果。
  3. 如果等待的 Promise 对象的状态变为 resolved(解决),则 await 表达式会返回 Promise 对象的解析值。
  4. 如果等待的 Promise 对象的状态变为 rejected(拒绝),则 await 表达式会抛出一个异常。
  5. 使用 catch 关键字定义一个代码块,用于捕捉和处理异常。

下面是示例代码,演示如何使用 async/await 捕捉异常:

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:', error);
  }
}

fetchData();

哪些情况会导致内存泄漏?

  • 未正确清理定时器:如果创建了一个定时器(setTimeout或setInterval),但没有及时清除它,定时器会一直保持对函数的引用,导致相关的内存无法释放。
  • 未正确解除事件监听器:如果在DOM元素上添加了事件监听器(如click、keydown等),但在元素被移除之前没有解除监听器,那么该元素及其相关的内存将无法被垃圾回收。
  • 循环引用:如果两个或多个对象之间存在相互引用,并且这些对象都不再被使用,那么它们将无法被垃圾回收。这种情况通常发生在对象之间建立了强引用关系,但后续没有及时解除这些引用。
  • 大量缓存数据:如果在JavaScript中使用了缓存机制,但没有限制缓存数据的大小或过期时间,那么缓存数据会不断增加,导致内存占用过高。
  • 闭包引用:闭包是指一个函数可以访问其外部作用域中的变量。如果在函数内部创建了一个闭包,并且该闭包引用了外部作用域中的变量,那么这些变量将无法被垃圾回收,直到闭包被释放。

深拷贝和浅拷贝的区别?

浅拷贝:

  • 浅拷贝是指创建一个新对象,新对象的属性值是原对象的引用。也就是说,新对象和原对象共享同一块内存地址,修改其中一个对象的属性会影响到另一个对象
  • 浅拷贝只复制了对象的第一层属性,如果原对象的属性是引用类型(如数组、对象等),则新对象仍然引用原对象的属性。
  • 浅拷贝通常使用一些简单的方法来实现,如简单赋值扩展运算符、对象的 Object.assign() 方法或数组的 slice() 方法。

深拷贝:

  • 深拷贝是指创建一个新对象,新对象的属性值是原对象属性值的完全副本。也就是说,新对象和原对象拥有不同的内存地址,彼此之间互不影响
  • 深拷贝会递归复制对象的所有层级,包括对象的属性和属性值。即使原对象的属性是引用类型,深拷贝也会创建一个新的引用类型对象。
  • 深拷贝通常需要使用递归或其他复杂的方法来实现,如 JSON 序列化和反序列化深度递归遍历对象、第三方库lodash等。

如何实现一个深拷贝?

  实现一个深拷贝可以使用递归或其他复杂的方法来遍历对象的所有层级,并创建一个新的对象,下面是一个使用递归实现深拷贝的示例:

// 递归深拷贝内部数组和变量
        function deepCopy(obj) {
            let result = Array.isArray(obj) ? [] : {}
            if (obj && typeof obj == 'object') {
                for (let key in obj) {
                    if (obj[key] && typeof obj[key] == 'object') {
                        result[key] = deepCopy(obj[key])
                    } else {
                        result[key] = obj[key]
                    }
                }
                return result
            } else {
                return obj
            }
        }

		//定义一个对象obj
        var res = deepCopy(obj)
        console.log(obj == res)  // false

  ⭐️需要注意的是,上述的深拷贝函数只能处理普通的对象和数组,对于包含函数、正则表达式、Date 对象等特殊类型的属性,需要根据具体情况进行额外处理。另外,循环引用的情况也需要特别注意,避免进入无限循环的递归。

对原型和原型链的理解

  在JavaScript中,每个对象都有一个原型(prototype)属性,它指向另一个对象,这个对象被称为原型对象。原型对象可以包含共享的属性和方法,它充当了对象之间共享属性和方法的模板。

  原型链是一种通过原型对象链接起来的对象层级结构。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会通过__proto__沿着原型链向上查找,直到找到该属性或方法或者到达原型链的顶端(即Object.prototype)。


又是10个☀️☀️,后续持续更新❕ ❕ ❕
个人收集整理、创作不易, 若有帮助🉑, 请帮忙点赞👍➕收藏❤️, 谢谢!✨✨🚀🚀

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FLechazo~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值