自学内容网 自学内容网

Javascript进阶——面试常见

以下是对前端JS面试题的详细回答:

1. 对 fetch 的理解及其优缺点

fetch 是一个基于 Promise 的,用于浏览器和服务器之间进行数据交换的 API。它提供了一个简洁的接口来请求资源。

优点

  • 语法简洁:fetch 的语法更加简洁,易于理解和使用。
  • 基于 Promise:fetch 返回的是一个 Promise 对象,这使得它很容易与 async/await 一起使用,实现异步操作的简洁性。
  • 更加语义化:fetch 的 API 设计更加语义化,符合现代 JavaScript 的编程习惯。

不足

  • 低层次 API:fetch 是一个低层次的 API,使用起来可能不如一些封装好的库(如 axios)方便。
  • 错误处理不足:fetch 只在网络错误时拒绝 Promise,对于 HTTP 状态码 4xx 和 5xx 的错误,并不会拒绝 Promise,而是正常返回。这可能需要开发者手动检查响应状态码来处理错误。
  • 默认不携带 Cookie:fetch 在默认情况下不会携带 Cookie,需要显式设置 credentials 选项为 'include'。
  • 不支持超时控制和取消请求:fetch 原生不支持超时控制和取消请求,这可能需要开发者使用额外的代码来实现。

2. JavaScript 中 Object.keys 的返回值是无序的吗?

是的,JavaScript 中 Object.keys() 方法返回的对象的属性数组是无序的。虽然 ECMAScript 5.1 规范之前曾规定属性遍历的顺序应基于属性在对象定义时的顺序,但 ECMAScript 2015(ES6)及之后的规范并未对属性的遍历顺序做出明确规定。因此,Object.keys() 返回的属性数组的顺序可能会因 JavaScript 引擎的实现或对象属性的添加方式而有所不同。

3. JavaScript 的 BigInt 和 Number 类型有什么区别?

BigInt 和 Number 是 JavaScript 中表示数字的两种不同的数据类型。

  • 表示范围:Number 类型可以表示有限范围内的整数和浮点数(通常是 -253),而 BigInt 类型可以表示任意大的整数。
  • 精度:Number 类型是浮点数,可以表示小数和指数,而 BigInt 类型只能表示整数,具有更高的整数精度。
  • 运算:BigInt 类型支持所有整数运算(加、减、乘、除、模),而 Number 类型还支持浮点数运算。

4. 什么是 JavaScript 的尾调用?使用尾调用有什么好处?

尾调用是指在函数的执行过程中,如果最后一个动作是一个函数的调用,并且这个调用的返回值被当前函数直接返回,则称该调用为尾调用。

好处

  • 优化性能:在支持尾调用优化的 JavaScript 引擎中,尾调用可以被优化为只使用一个调用栈帧,从而避免栈溢出的问题。这在进行大量递归操作时尤为重要。
  • 提高代码可读性:尾调用通常使递归函数的实现更加简洁和直观。

5. JavaScript 为什么要进行变量提升?它导致了什么问题?

JavaScript 进行变量提升的原因主要是为了提高性能和容错性。

  • 提高性能:在 JavaScript 代码执行之前,会进行语法检查和预编译。变量提升允许在预编译阶段就确定变量的声明和函数的定义,从而避免在每次执行代码时都重新解析一遍。这可以提高代码的执行效率。
  • 容错性:变量提升可以在一定程度上提高 JavaScript 的容错性。即使代码中存在先使用后声明的变量,由于变量提升的存在,这些代码也不会报错。然而,这也可能导致一些难以察觉的错误,因为开发者可能误以为变量在使用前已经被声明和初始化了。

导致的问题

  • 变量覆盖:由于变量提升的存在,后声明的变量可能会覆盖先声明的同名变量,导致不可预测的行为。
  • 全局变量污染:使用 var 声明的全局变量会成为全局对象的属性(在浏览器中是 window 对象),这可能导致全局变量污染和命名冲突。

6. 能通过 window 对象取到全局变量吗?

是的,在浏览器环境中,可以通过 window 对象访问全局变量。全局变量实际上是 window 对象的属性。例如,如果声明了一个全局变量 var myVar = 10;,则可以通过 window.myVar 来访问这个变量。

7. let、const 和 var 的区别是什么?

  • 作用域var 声明的是函数作用域或全局作用域的变量,而 let 和 const 声明的是块级作用域的变量。
  • 变量提升var 声明的变量会发生变量提升,可以在声明之前访问(但值为 undefined),而 let 和 const 声明的变量不会发生变量提升,在声明之前访问会导致 ReferenceError。
  • 重新赋值var 和 let 声明的变量可以被重新赋值,而 const 声明的变量一旦被赋值后就不能再被重新赋值(但如果是对象或数组,可以修改其内部属性或元素)。

8. 对 JS 作用域的理解

JavaScript 的作用域决定了变量、函数和对象的可访问性。JavaScript 有三种主要的作用域:全局作用域、函数作用域和块级作用域。

  • 全局作用域:在全局作用域中声明的变量和函数可以在整个 JavaScript 代码中访问。
  • 函数作用域:在函数内部声明的变量和函数只能在该函数内部访问,这就是函数作用域。使用 var 关键字声明的变量具有函数作用域。
  • 块级作用域:块级作用域是由 {} 包围的代码块创建的。在块级作用域中声明的变量和函数只能在该块内部访问。使用 let 和 const 关键字声明的变量具有块级作用域。

9. 什么是 JavaScript 的临时性死区?

临时性死区(Temporal Dead Zone,TDZ)是指在变量声明之前,该变量所处的作用域(对于 let 和 const 来说,是块级作用域;对于 var 来说,是函数作用域或全局作用域)中的一个“死区”。在这个死区中,变量是不可访问的,如果尝试访问会导致 ReferenceError。这是因为在变量声明之前,该变量在作用域中并不存在。

10. JavaScript 事件冒泡和捕获的区别是什么?默认是冒泡还是捕获?

区别

  • 事件冒泡:事件从目标元素开始,逐层向上传播到祖先元素,直到文档的根元素(在浏览器中通常是 document 对象)。
  • 事件捕获:事件从文档的根元素开始,逐层向下传播到目标元素。

默认行为

在 JavaScript 中,事件默认是按照冒泡阶段进行传播的。但是,可以通过在事件监听器中使用 capture 选项或 addEventListener 方法的第三个参数来指定事件在捕获阶段进行传播。

11. 什么是 JavaScript 的事件代理?

事件代理(Event Delegation)是一种常用的技术,它利用事件冒泡的原理,将事件监听器添加到父元素上,而不是直接添加到目标元素上。当目标元素触发事件时,事件会冒泡到父元素,父元素上的事件监听器可以捕获并处理该事件。这种方法可以减少事件监听器的数量,提高性能,并且便于管理事件监听器。

综上所述,这些问题是前端 JS 面试中常见的问题,涵盖了 fetch API、数据类型、作用域、变量提升、事件处理等多个方面。希望这些回答能够帮助你更好地准备面试。

JavaScript 的事件流

事件流是 JavaScript 处理事件的机制,它描述了事件从发生到被处理的过程。事件流主要包括两个阶段:捕获阶段和冒泡阶段。在捕获阶段,事件从文档的根元素开始,逐层向下传播到目标元素,这个阶段可以阻止事件到达目标元素。在冒泡阶段,事件从目标元素开始,逐层向上传播到文档的根元素,这个阶段可以对事件进行响应。事件流的顺序是:捕获处理程序 → 目标处理程序 → 冒泡处理程序。

JavaScript 的事件轮询机制

JavaScript 事件轮询(event loop)是 JavaScript 运行时环境中的一个机制,它允许 JavaScript 能够执行非阻塞的异步操作。由于 JavaScript 在大多数环境下(比如 Web 浏览器、Node.js)是单线程运行的,这意味着在任何给定的时刻它只能执行一个任务。事件轮询使得 JavaScript 能够表现出异步行为,即使它在内部是单线程的。事件轮询将任务分为同步任务和异步任务,异步任务又分为异步微任务和异步宏任务。同步任务首先执行,然后是异步微任务,最后是异步宏任务。

JavaScript 的原型链

在 JavaScript 中,原型链是一种继承和委托机制,它允许对象访问和继承其原型的属性和方法。原型链的运作方式如下:当访问一个对象的属性或方法时,如果该对象没有该属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的终点 null。原型链是 JavaScript 实现继承的主要方式之一。

原型重写

原型重写通常指的是修改一个对象的原型对象,或者修改一个类的原型链上的方法或属性。这可以通过多种方式实现,比如直接修改原型对象上的属性或方法,或者通过继承来重写父类的方法。

JavaScript 的原型修改

JavaScript 的原型修改指的是改变一个对象的原型对象,或者改变一个类的原型链。这可以通过多种方式实现,比如直接修改 __proto__ 属性(尽管这种做法不推荐,因为 __proto__ 不是标准属性,并且在严格模式下可能会引发错误),或者使用 Object.setPrototypeOf() 方法(这是一个更标准的方法,但也可能在某些环境中不被支持)。另外,也可以通过修改构造函数的 prototype 属性来影响由该构造函数创建的所有对象的原型链。

JavaScript 的原型链指向什么?

JavaScript 的原型链指向的是对象的原型对象。每个对象都有一个内部属性 [[Prototype]](在 ES5 中可以通过 __proto__ 访问,但 __proto__ 不是标准属性,并且在严格模式下可能会引发错误;ES6 引入了 Object.getPrototypeOf() 方法来获取对象的原型),它指向该对象的原型对象。原型对象本身也可以有自己的原型,这样就形成了一个链式结构,即原型链。

JavaScript 原型链的终点是什么?如何打印出原型链的终点?

JavaScript 原型链的终点是 null。当访问一个对象的属性或方法时,如果沿着原型链一直向上查找都没有找到该属性或方法,那么最终会到达原型链的终点 null。要打印出原型链的终点,可以通过遍历对象的原型链,直到找到 null 为止。例如,可以使用以下代码来打印出一个对象的原型链,并找到原型链的终点:

function printPrototypeChain(obj) {
let current = obj;
while (current !== null) {
console.log(current);
current = Object.getPrototypeOf(current);
}
console.log('Prototype chain end: null');
}


// 示例对象
let obj = {};
printPrototypeChain(obj);

JavaScript 如何获得对象非原型链上的属性?

要获得对象非原型链上的属性,可以直接访问对象的属性。如果属性存在于对象本身(而不是在原型链上),那么就可以通过点操作符(.)或方括号操作符([])来访问它。例如:

let obj = {a: 1, b: 2};
console.log(obj.a); // 输出: 1
console.log(obj['b']); // 输出: 2

在上面的例子中,a 和 b 都是对象 obj 本身的属性,而不是在原型链上的属性。

JavaScript 的闭包

闭包是指能够访问另一个函数作用域中变量的函数。即使外部函数已经执行完毕,闭包仍然可以访问其内部的变量和函数。闭包的作用是实现数据的封装和私有性,以及创建工厂函数等。闭包的使用场景包括数据缓存、函数柯里化、防抖和节流等。

JavaScript 闭包的实现原理

闭包的实现原理是基于 JavaScript 的作用域链和函数对象。当一个函数被定义时,它会创建一个新的作用域,并包含所有局部变量和函数声明。当这个函数被调用时,它的作用域链会被创建,并包含它自己的作用域、它的父作用域以及更上层的作用域(直到全局作用域)。如果一个函数在另一个函数内部被定义,并且引用了外部函数的变量,那么这个内部函数就形成了一个闭包。即使外部函数已经执行完毕,内部函数仍然可以通过作用域链访问外部函数的变量。

JavaScript 作用域、作用域链的理解

作用域是指变量、函数和对象在代码中的可访问范围。JavaScript 有三种主要的作用域:全局作用域、函数作用域和块级作用域。作用域链是在嵌套的作用域中解析变量时沿着的作用域链的列表。当访问一个变量时,JavaScript 引擎会沿着作用域链向上查找,直到找到该变量或者到达全局作用域为止。作用域链是闭包实现的基础。

JavaScript 的执行上下文

执行上下文是 JavaScript 代码在执行时的一个抽象环境。它包括变量对象(VO/AO)、作用域链和 this 值。每当 JavaScript 代码执行时,都会创建一个新的执行上下文。执行上下文分为全局执行上下文和函数执行上下文两种。全局执行上下文在 JavaScript 代码开始执行时创建,而函数执行上下文在每次调用函数时创建。

JavaScript 中 this 的理解、指向什么?

在 JavaScript 中,this 是一个特殊的关键字,它代表当前执行上下文中的一个对象。this 的值取决于函数的调用方式,而不是函数被定义的位置。具体来说,this 的指向有以下几种情况:

  1. 全局上下文中:在全局执行上下文中,this 指向全局对象(在浏览器中通常是 window 对象,在 Node.js 中是 global 对象)。
  2. 函数上下文中:在函数执行上下文中,this 的值取决于函数的调用方式。如果是作为对象的方法被调用,则 this 指向调用该方法的对象;如果是作为普通函数被调用,则 this 指向全局对象(在严格模式下为 undefined);如果是通过 callapply 或 bind 方法调用,则 this 的值被显式指定为调用时传入的第一个参数。
  3. 构造函数中:在构造函数中,this 指向新创建的对象实例。
  4. 箭头函数中:箭头函数没有自己的 this 值,它会捕获其所在上下文的 this 值作为自己的 this 值。

总之,this 的指向是 JavaScript 中的一个重要概念,它决定了函数执行时内部变量的访问方式。理解 this 的指向是掌握 JavaScript 面向对象编程的关键之一。


原文地址:https://blog.csdn.net/m0_55049655/article/details/143845817

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!