前端面试题(十二)

63. JavaScript 模块化

  • 什么是 JavaScript 模块化?

    • 模块化 是指将代码分割成独立的模块,每个模块负责一个单一的功能或逻辑。通过模块化,代码更加结构化、易于维护、复用性强。
    • 在 JavaScript 中,模块化的实现经历了多个阶段,从最早的全局作用域到后来的 AMD、CommonJS 和 ES6 模块系统。
  • 常见的模块化方案:

    1. CommonJS :Node.js 中使用的模块化方案,模块通过 module.exports 导出,通过 require 导入。

      • 特点:同步加载,适用于服务器端。

      • 例子

        javascript 复制代码
        // 导出模块
        module.exports = function add(a, b) {
          return a + b;
        };
        // 导入模块
        const add = require('./add');
        console.log(add(2, 3)); // 输出 5
    2. AMD (Asynchronous Module Definition) :一种前端模块化方案,主要用于浏览器环境,模块通过 define 定义,通过 require 导入。

      • 特点:异步加载,适用于浏览器端。

      • 例子

        javascript 复制代码
        define(['math'], function(math) {
          console.log(math.add(2, 3));
        });
    3. ES6 模块 :ES6 标准引入的模块系统,通过 export 导出,通过 import 导入。

      • 特点:支持静态分析,异步加载,适用于浏览器和服务器。

      • 例子

        javascript 复制代码
        // 导出模块
        export function add(a, b) {
          return a + b;
        }
        // 导入模块
        import { add } from './math';
        console.log(add(2, 3)); // 输出 5

64. 原型链

  • 什么是原型链?

    • 原型链 (Prototype Chain) 是 JavaScript 中实现继承的机制。每个对象都有一个 [[Prototype]] 属性(可以通过 __proto__ 访问),指向它的原型对象。原型对象也可以有自己的原型,形成一个链条,直到指向 null 为止。
    • 当访问一个对象的属性时,如果对象本身没有这个属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或到达链条末端 null
  • 例子:

    javascript 复制代码
    function Person(name) {
      this.name = name;
    }
    Person.prototype.greet = function() {
      console.log('Hello, ' + this.name);
    };
    
    const alice = new Person('Alice');
    alice.greet(); // 输出 "Hello, Alice"
    console.log(alice.__proto__ === Person.prototype); // true
  • 原型链的常见面试问题:

    1. instanceof 的工作原理是什么?

      • instanceof 运算符会沿着对象的原型链查找,判断对象的原型链中是否有构造函数的 prototype 属性。如果有,则返回 true

      • 例子

        javascript 复制代码
        console.log(alice instanceof Person); // true
    2. 原型链继承的缺点是什么?

      • 所有实例共享同一个原型对象上的属性或方法,如果原型对象上有引用类型的属性,可能会导致实例之间相互影响。

      • 例子

        javascript 复制代码
        function Animal() {
          this.traits = ['fur'];
        }
        Animal.prototype.getTraits = function() {
          return this.traits;
        };
        
        const cat = new Animal();
        const dog = new Animal();
        cat.traits.push('claws');
        console.log(dog.getTraits()); // 输出 ["fur", "claws"]

65. 浏览器缓存

  • 浏览器缓存的机制有哪些?

    浏览器缓存是提升性能的重要手段,通过将资源缓存到本地,避免重复下载相同的资源。常见的缓存机制有两种:强缓存协商缓存

    1. 强缓存:浏览器根据缓存规则,直接从缓存中读取资源,不与服务器进行通信。常见的 HTTP 头包括:

      • Expires:设置资源的过期时间,使用的是服务器时间,缺点是时间同步问题。
      • Cache-Control:更灵活的缓存控制方式,可以使用 max-age 指定资源的最大缓存时间。
    2. 协商缓存:浏览器在请求资源时,会与服务器进行验证,服务器会根据资源是否更新来决定是返回新的资源还是使用缓存。常见的 HTTP 头包括:

      • Last-Modified / If-Modified-Since:通过文件的最后修改时间来验证资源是否更新。
      • ETag / If-None-Match:通过文件的唯一标识符来验证资源是否更新,优先级高于 Last-Modified
    • 缓存控制的例子:

      http 复制代码
      Cache-Control: max-age=31536000, public
      ETag: "abc123"

66. DOM 操作

  • 如何高效地操作 DOM?
    1. 批量操作 DOM :尽量减少直接操作 DOM 的次数,使用文档片段 (DocumentFragment) 或缓存 DOM 元素来优化性能。

      • 例子

        javascript 复制代码
        const fragment = document.createDocumentFragment();
        for (let i = 0; i < 1000; i++) {
          const li = document.createElement('li');
          li.textContent = `Item ${i}`;
          fragment.appendChild(li);
        }
        document.getElementById('list').appendChild(fragment);
    2. 使用 innerHTML 代替 createElement :对于创建较简单的 HTML 结构,使用 innerHTML 相较于 createElement 性能更高。

      • 例子

        javascript 复制代码
        document.getElementById('list').innerHTML = '<li>Item 1</li><li>Item 2</li>';
    3. 减少回流和重绘:尽量减少对 DOM 树结构的频繁修改,特别是涉及布局属性的修改(如宽高、位置等),这些操作会触发回流(重排)和重绘。

      • 例子

        javascript 复制代码
        const el = document.getElementById('box');
        el.style.width = '100px';
        el.style.height = '100px';
        el.style.backgroundColor = 'blue'; // 这三行操作会触发多次回流
    4. 事件代理:对于动态生成的元素,可以通过事件代理的方式提高性能,而不是给每个元素都绑定事件。

      • 例子

        javascript 复制代码
        document.getElementById('list').addEventListener('click', function(event) {
          if (event.target.tagName === 'LI') {
            console.log('Item clicked:', event.target.textContent);
          }
        });

67. Vue 响应式原理

  • Vue 的响应式系统是如何工作的?

    Vue 的响应式系统基于 数据劫持发布-订阅模式 来实现。它通过使用 Object.defineProperty 对数据进行劫持,在数据发生变化时触发视图更新。

    1. 数据劫持 :当 Vue 实例初始化时,Vue 会递归地遍历数据对象的每一个属性,并使用 Object.defineProperty 将这些属性转换为 getter 和 setter,从而拦截对这些属性的访问和修改。
    2. 依赖收集:当组件渲染时,Vue 会将渲染过程中使用到的数据属性进行依赖收集,并建立依赖关系,当数据发生变化时,会通知对应的观察者(watcher)重新渲染视图。
    3. 发布-订阅模式:当数据发生变化时,setter 会触发依赖更新,执行观察者的更新方法,达到数据驱动视图更新的效果。
    • 示例代码:

      javascript 复制代码
      let data = { name: 'Alice' };
      Object.defineProperty(data, 'name', {
        get() {
          console.log('获取 name');
          return name;
        },
        set(newVal) {
          console.log('设置 name 为', newVal);
          name = newVal;
        }
      });
      
      console.log(data.name); // 触发 get
      data.name = 'Bob';      // 触发 set
相关推荐
y先森2 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy2 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189112 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿3 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡4 小时前
commitlint校验git提交信息
前端
虾球xz4 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇4 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒4 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员5 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐5 小时前
前端图像处理(一)
前端