JS面试题3

1、使用递归完成1~100的累加

// 1~100累加
    function addRes(x,y){
         if(x === y){
             return x
         }else{
           return y + addRes(x,y-1) // 第一次:3 + addRes(1,2) => 往后依次递减,到达目标值位置后依次计算累加值
         }
     }
     console.log(addRes(1,3))

// 斐波那契数列(兔子数列) => 第1,2位不参与计算,第3位开始是前两位数值的和:0,1,1,2,3,5,8,13,21,34
     function fn(x){
          if(x === 1){
              return 0; // 如果是第一位数则返回0 => 因为第0位数是固定的,也就是0
          }else if(x=== 2){
              return 1; // 如果是第二位数则返回1 => 因为第1位数是固定的,也就是1
          }else {
              return func(x-1)+ func(x-2); // 左边计算前一位值,右边计算前两位值,依次调用fn后递减得到目标值后计算两个值的和
          }
      }
      console.log(func(5)); // 第5位为3

2、浮点数精度的问题

为什么:console.1og(0.2+0.1==0.3)得到的值为:false

  1. 因为计算机在处理浮点数时有精度问题
  2. 0.2/0.1 这样的浮点数在二进制中不能被精确表示,所以0.2+0.1的结果实际上是一个非常接近0.3但不完全等于0.3的值
  3. 不仅Js,所有遵循IEEE 754规范的语言都是如此

3、什么是严格模式,及使用它的区别

3.1、概念:

  1. 严格模式是从ES5开始新增的一种:在代码执行时,采用更严格解析和错误处理的方式。
  2. 它可以通过在脚本(针对整个脚本文件)函数的开头添加"use strict" 声明来启用

3.2、区别:

  1. 变量声明
    • 普通模式:可以使用未声明的变量,这会隐式创建全局变量。
    • 严格模式:使用未声明的变量会抛出错误。
  2. this 绑定
    • 普通模式:在全局上下文中,this 绑定到全局对象(浏览器中是 window)。
    • 严格模式:在全局上下文中,this 是 undefined。
  3. 删除不可删除的属性
    • 普通模式:删除不可删除的属性不会报错。
    • 严格模式:尝试删除不可删除的属性会抛出错误。
  4. 重复参数
    • 普通模式:函数可以有重复的参数名。
    • 严格模式:函数参数名不能重复。
  5. 八进制字面量
    • 普通模式:允许八进制字面量(如 075)。
    • 严格模式:禁止八进制字面量。
  6. eval
    • 普通模式:eval 中创建的变量在外部作用域可见。
    • 严格模式:eval 有自己的独立作用域,变量不会泄露到外部作用域。
  7. 关键字保护
    • 普通模式:可以将 arguments 或 eval 作为变量名。
    • 严格模式:禁止使用 arguments 或 eval 作为变量名。
  8. 新增错误
    • 普通模式:一些错误被静默忽略。
    • 严格模式:抛出更多错误,帮助发现和修复问题。

4、JS的垃圾回收机制

4.1、 概念:

  1. javaScript具有自动垃圾回收机制,垃圾收集器会按照固定的时间间隔周期性的执行
  2. javaScript常见的垃圾回收方式:标记清除引用计数方式

4.2、垃圾回收方式:

  1. 标记清除方式
    • 当变量进入环境时,将这个变量标记为“进入环境”。
    • 当变量离开环境时,则将其标记为“离开环境”, 然后回收标记为“离开环境”的变量所占用的内存
  2. 引用计数方式
    • 跟踪记录每个值被引用的次数,当引用次数变为0时,释放该值的内存

5、weakmap对象

解释:weakmap对象map对象弱引用版本

  1. Map对象

Map 对象是一种存储键/值对的数据结构,类似于普通的对象,但有以下几个特点:

  • 键名唯一不可重复
  • 类似于集合,是键/值对的集合,任何值都可以作为一个键或者一个值。
  • 可以遍历,可以转换各种数据格式,方法有:get、set、has、delete
  1. WeakMap对象

WeakMap 对象也是用来存储键值对的,但与 Map 有几个关键区别:

  • 只接受对象为键名,不接受其他类型的值作为键名,键值可以是任意
  • 键名是弱引用,键名所指向的对象,会被垃圾回收机制回收
  • 不能遍历,方法有:get、set、has、delete

6、weakset对象

  1. Set对象

Set 对象是一种特殊的集合,用来存储唯一的值,无论是原始值还是对象。它有以下特点:

  1. 成员唯一,无序且不会重复
  2. 类似于数组集合,键值和键名是一致的(只有键值。没有键名)
  3. 可以遍历,方法有:add、delete、hasWeakSet
  4. WeakSet对象

WeakSet是一个类似Set的集合,但有一些重要区别:

  1. 只能存储对应引用,不能存放值
  2. 成员都是弱引用,会被垃圾回收机制回收
  3. 不能遍历,方法有:add、delete、has

7、深/浅拷贝的区别及如何实现?

7.1、浅拷贝:

  1. 定义
    • 创建一个新对象,新对象的属性是原对象属性的引用。
    • 对于对象属性,浅拷贝不会复制内部对象,只复制引用。
  2. 实现
    • 使用 Object.assign
    • 展开运算符({ …obj })进行拷贝。
    • Array.prototype.slice(用于数组)
    • Array.from(用于数组)
  3. 结果
    • 修改新对象中的嵌套对象会影响原对象中的嵌套对象。

7.2、深拷贝:

  1. 定义
    • 创建一个新对象,新对象的所有属性(包括嵌套对象)都是原对象的副本,完全独立于原对象
  2. 实现
    • 使用递归函数手动复制每一层对象。
    • 使用JSON.parse(JSON.stringify(obj))方法,注意:适用于简单对象,不支持函数、undefined 和循环引用
    • 使用第三方库(如 Lodash)
  3. 结果
    • 修改新对象中的嵌套对象不会影响原对象中的嵌套对象。

7.3、总结:

  1. 浅拷贝:复制对象的第一层属性,嵌套对象保持引用。
  2. 深拷贝:递归复制所有层级的属性,完全独立于原对象。

8、JS中的eval方法是什么?一般在什么时候使用?

  1. 定义
    • eval 是一个Js函数,用于将字符串(但要是字符串版的js)当作Js代码执行
  2. 使用场景
    • 动态代码执行,在运行时构建和执行代码。
  3. 注意事项
    • 安全风险:eval 会执行任意代码,可能导致安全漏洞。
    • 性能问题:eval 会影响性能,尽量避免使用。
    • 替代方法:通常可以使用 JSON.parse、Function 构造函数或其他方法代替。

9、什么是函数柯里化

  1. 定义
    • 函数柯里化是:将一个接受多个参数的函数,转换成一系列每次接受一个参数的函数。
  2. 使用场景
    • 参数复用:让函数更灵活,可以在不同的场景中复用参数。
    • 延迟计算:可以分步传递参数,有助于延迟计算和更好地控制函数的执行。
  3. 简单示例:
    函数柯里化简示

10、Node.js中的事件循环,以及和浏览器的事件循环有何不同?

10.1、浏览器的事件循环

  1. 概念
    • 事件循环是:浏览器处理任务的机制。
    • 简单来说:它确保了代码的顺序执行,并处理用户交互和异步任务。
  2. 执行步骤
    • 执行全局代码:
      ■ 浏览器首先会执行你写的同步代码
      ■ 比如在 <script> 标签内的代码,这些代码会按顺序执行,直到完成。
    • 执行微任务:
      ■ 微任务包括Promise的.then/catch().finally() 回调MutationObserver
      ■ 这些任务会在当前执行的脚本结束后立即执行。微任务的优先级高于宏任务(如定时器回调)
    • 执行宏任务
      ■ 宏任务包括 setTimeout、setInterval、setImmediate、I/O 操作等。
      ■ 这些任务会被放到宏任务队列中等待执行。
      ■ 每次循环迭代时,事件循环会从宏任务队列中取出一个任务来执行。
    • 渲染更新
      ■ 如果需要,浏览器会在执行宏任务后进行渲染更新,例如,更新页面布局、绘制新的内容等。
      ■ 这通常在每个事件循环的迭代过程中进行,确保用户看到最新的页面状态。
    • 返回第一步
      ■ 事件循环会继续循环,从步骤 1 开始执行下一个任务,直到所有任务完成。

10.2、Node.js的事件循环

Node.js的事件循环机制基于libuv库(c++库)实现,其执行步骤如下:

  1. 执行全局代码
  2. 执行微任务
  3. 执行宏任务
  4. 事件循环阶段——Node.js的事件循环主要分为六个阶段:
    • timers:执行定时器回调。
    • pending callbacks:执行系统级别的回调。
    • idleprepare:node.js内部使用。
    • poll:处理除了 timers 和 setImmediate 以外的所有回调,比如 I/O 操作。
    • check:执行 setImmediate 的回调。
    • close callbacks:执行一些关闭的回调,比如 socket 的关闭。
  5. 渲染更新
  6. 重复执行

10.3、两者之前的不同

  1. 环境
    • Node.js:用于服务器端,事件循环由libuv库实现。
    • 浏览器:用于客户端,事件循环由浏览器引擎实现(如Chrome的V8和它的事件循环)。
  2. 任务队列
    • Node.js:有多个队列,包括微任务队列(微任务如process.nextTick、Promise的回调)和不同优先级的任务队列(如setImmediate、setTimeout)。
    • 浏览器:有宏任务队列(如setTimeout、setInterval)和微任务队列(如Promise的回调)。
  3. 执行顺序
    • Node.js:每个事件循环阶段处理特定类型的任务,然后处理微任务队列,依次循环。
    • 浏览器:每个事件循环中处理一个宏任务,然后处理所有的微任务。
  4. I/O处理
    • Node.js:高度优化的I/O处理能力,专为处理大量并发I/O操作设计。
    • 浏览器:用于处理用户交互和界面渲染,I/O操作通过异步API完成,如:XMLHttpRequest/fetch
  5. 总之
    • Node.js浏览器的事件循环都负责处理异步任务
    • 但它们的设计和执行顺序有所不同,以适应各自的应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值