前端面试题(十六)

89. 什么是闭包?

  • 闭包的定义
    闭包是指一个函数可以访问它的词法作用域中的变量,即使这个函数在它的词法作用域之外被调用。换句话说,闭包使得函数可以记住并访问它所在的作用域中的变量,即使该函数在这个作用域之外执行。

  • 闭包的用途

    1. 数据的持久化:闭包可以用于创建私有变量或持久化状态。
    2. 函数工厂:可以用来创建不同作用域中的函数。
    3. 回调函数:在异步操作或事件处理程序中使用闭包,以保持对外部变量的访问。
  • 闭包示例

    function outerFunction(outerVariable) {
      return function innerFunction(innerVariable) {
        console.log('Outer Variable:', outerVariable);
        console.log('Inner Variable:', innerVariable);
      };
    }
    
    const newFunction = outerFunction('外部');
    newFunction('内部');
    

    在这个例子中,innerFunction 是一个闭包,因为它可以访问 outerFunctionouterVariable 变量,即使 outerFunction 已经执行完毕。

90. 作用域链

  • 作用域链的定义
    当访问一个变量时,JavaScript 引擎会首先在当前作用域中查找该变量。如果找不到,它会沿着作用域链向外层作用域查找,直到全局作用域。如果仍未找到,则会抛出 ReferenceError

  • 作用域链的结构

    1. 当前函数作用域。
    2. 外层函数作用域(如果有的话)。
    3. 全局作用域。
  • 作用域链示例

    const globalVar = 'global';
    
    function outerFunction() {
      const outerVar = 'outer';
      
      function innerFunction() {
        const innerVar = 'inner';
        console.log(globalVar); // 'global'
        console.log(outerVar);  // 'outer'
        console.log(innerVar);  // 'inner'
      }
      
      innerFunction();
    }
    
    outerFunction();
    

在这个例子中,innerFunction 可以访问全局变量 globalVar,外层函数 outerVar,以及自身作用域中的 innerVar,这就是作用域链的工作方式。

91. 什么是事件循环(Event Loop)?

  • 事件循环的定义
    事件循环 是 JavaScript 处理异步操作的机制。JavaScript 是单线程语言,它通过事件循环机制使得异步任务不会阻塞主线程,从而实现非阻塞的并发执行。

  • 事件循环的工作原理

    1. 同步任务 被直接放入主线程执行栈中,按顺序执行。
    2. 异步任务(如定时器、网络请求)会被放入 任务队列 中,当主线程执行栈为空时,事件循环会检查任务队列,依次执行任务队列中的任务。
  • 微任务与宏任务

    • 宏任务 (macro task):如 setTimeoutsetInterval、I/O 操作等。
    • 微任务 (micro task):如 Promise.then()MutationObserver 等。
    • 每次事件循环会先清空所有微任务队列,然后再执行一个宏任务。
  • 事件循环示例

    console.log('Start');
    
    setTimeout(() => {
      console.log('宏任务:setTimeout');
    }, 0);
    
    Promise.resolve().then(() => {
      console.log('微任务:Promise.then');
    });
    
    console.log('End');
    

    执行结果:

    Start
    End
    微任务:Promise.then
    宏任务:setTimeout
    

    解释:同步任务先执行,随后执行所有微任务,最后执行宏任务。

92. 什么是跨域?如何解决跨域问题?

  • 跨域的定义
    跨域 是指浏览器执行 XMLHttpRequestFetch 请求时,因 同源策略 限制,不允许访问不同源的资源。同源指协议、域名、端口号必须一致,跨域即其中任一不一致。

  • 跨域的常见解决方法

    1. JSONP (JSON with Padding)

      • 利用 <script> 标签不受跨域限制的特点,通过动态插入 <script> 标签来请求跨域资源。服务端返回一个包含回调函数的 JSON 数据。
      • 缺点:只支持 GET 请求。
      <script>
        function handleResponse(data) {
          console.log(data);
        }
      </script>
      <script src="https://example.com/data?callback=handleResponse"></script>
      
    2. CORS (Cross-Origin Resource Sharing)

      • 服务端设置响应头 Access-Control-Allow-Origin 来允许跨域请求。
      • 示例
        Access-Control-Allow-Origin: https://example.com
        Access-Control-Allow-Methods: GET, POST
        Access-Control-Allow-Headers: Content-Type
        
    3. 代理服务器

      • 通过设置一个代理服务器,由同源的服务器发送请求到不同源的服务器,从而实现跨域。
    4. 服务器端转发

      • 在服务器上设置路由,服务器请求跨域资源并将结果返回给客户端,从而避免浏览器的跨域限制。

93. 防抖与节流

  • 防抖 (Debounce)
    防抖是一种函数优化技术,用于限制函数的执行频率。防抖的关键在于,如果在一定时间内函数再次被触发,计时器将重新计时。适用于输入框输入或窗口调整等频繁触发的事件。

    • 防抖实现
      function debounce(func, wait) {
        let timeout;
        return function (...args) {
          clearTimeout(timeout);
          timeout = setTimeout(() => {
            func.apply(this, args);
          }, wait);
        };
      }
      
      window.addEventListener('resize', debounce(() => {
        console.log('窗口大小已调整');
      }, 500));
      
  • 节流 (Throttle)
    节流同样是一种函数优化技术,但与防抖不同,节流限制的是一段时间内函数只会执行一次。适用于页面滚动或鼠标移动等持续触发的事件。

    • 节流实现
      function throttle(func, limit) {
        let inThrottle;
        return function (...args) {
          if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => {
              inThrottle = false;
            }, limit);
          }
        };
      }
      
      window.addEventListener('scroll', throttle(() => {
        console.log('页面正在滚动');
      }, 1000));
      

94. Set 和 Map 的区别

  • Set

    • Set 是一种无序且唯一的集合,可以存储任何类型的值。

    • 常见方法

      • add(value):向 Set 中添加值。
      • has(value):检查值是否存在于 Set 中。
      • delete(value):从 Set 中删除值。
    • Set 示例

      const set = new Set();
      set.add(1);
      set.add(2);
      set.add(2); // 重复值不会添加
      console.log(set.has(1)); // true
      set.delete(1);
      console.log(set); // Set { 2 }
      
  • Map

    • Map 是一种键值对集合,允许任何类型的键。

    • 常见方法

      • set(key, value):向 Map 中添加键值对。
      • get(key):根据键获取值。
      • delete(key):删除键值对。
    • Map 示例

      const map = new Map();
      map.set('name', 'Alice');
      map.set('age', 25);
      console.log(map.get('name')); // 'Alice'
      map.delete('age');
      console.log(map); // Map { 'name' => 'Alice' }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小于负无穷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值