【2024】前端面试题

1,320 阅读17分钟

要看react的这篇文章不合适,本人主要用vue,本篇文章分五段,html,css,js,vue,杂谈


html

  1. 请解释一下HTML5中的Web Components是什么,包括Custom Elements、Shadow DOM、HTML Templates和HTML Imports的作用和用法。
  • 在HTML5中,Web Components是一种用于创建可重用自定义元素的技术。它由四个主要部分组成:
    1. Custom Elements:允许开发者定义自定义HTML元素,并定义其行为和样式。
    2. Shadow DOM:提供了一种将样式和脚本封装在自定义元素内部的方法,避免与外部样式和脚本冲突。
    3. HTML Templates:允许开发者定义包含HTML标记的模板,可以被多次重复使用。
    4. HTML Imports:已被废弃,曾用于导入HTML文档,现在可以使用ES6模块替代。
  1. 请谈谈你对HTML5中的服务端事件(Server-Sent Events)的理解,并说明它与WebSocket的区别和适用场景。
  • 服务端事件(Server-Sent Events)是一种浏览器与服务器之间的单向通信技术,服务器可以向客户端推送实时数据。与WebSocket相比,Server-Sent Events是基于HTTP协议,只支持服务器向客户端的单向通信,适用于需要从服务器获取实时更新的场景,如实时股票报价、天气预报等。
  1. 请解释一下HTML5中的IndexedDB是什么,以及它与传统的Web存储(如localStorage)的区别和优势。 -`IndexedDB是HTML5中的一种客户端存储数据库,可以存储大量结构化数据,并支持事务操作和索引。与传统的Web存储(如localStorage)相比,IndexedDB更适合存储大量数据和复杂数据结构,具有更好的性能和可扩展性。

` 4. 请说明一下HTML5中的跨文档消息传递(Cross-document Messaging)的原理和用法,以及在实际项目中的应用场景。

  • 跨文档消息传递(Cross-document Messaging)是一种在不同域之间进行安全通信的技术,通过postMessage方法发送消息,并在接收方通过监听message事件来接收消息。在实际项目中,跨文档消息传递常用于父子窗口或跨域iframe之间的通信,如实现单点登录、嵌套页面通信等场景。
  1. 请谈谈你对HTML5中的动画技术(如CSS动画、Canvas动画、Web动画API等)的理解,以及在实际项目中如何选择合适的动画方案。
  • HTML5中的动画技术包括CSS动画、Canvas动画、Web动画API等。在实际项目中,可以根据需求选择合适的动画方案:CSS动画适合简单动画效果和样式变换;Canvas动画适合复杂绘图和游戏动画;Web动画API提供更多控制和性能优化选项。
  1. 请谈谈你对HTML5中的WebRTC(Web Real-Time Communication)的理解,包括其在实时通信和视频会议中的应用。
  • WebRTC(Web Real-Time Communication)是一种实现浏览器间实时通信的技术,包括音视频通话、文件共享等功能。在实时通信和视频会议中,WebRTC可以直接在浏览器中实现点对点通信,无需安装插件,具有低延迟和高质量的优势。
  1. 请解释一下HTML5中的Web Cryptography API是什么,以及如何使用它实现加密和安全通信。
  • Web Cryptography API是HTML5提供的加密和解密功能的API,可以用于生成密钥、加密数据、签名验证等安全通信操作。通过Web Cryptography API,开发者可以实现端到端加密、数据保护等安全功能。
  1. 请说明一下HTML5中的WebAssembly是什么,以及它如何提高Web应用程序的性能和功能。
  • WebAssembly是一种新型的低级字节码格式,可以在浏览器中运行高性能的编译语言(如C/C++)程序。通过WebAssembly,开发者可以将性能敏感的代码编译成浏览器可执行的格式,提高Web应用程序的性能和功能。
  1. 请谈谈你对HTML5中的PWA(Progressive Web Apps)的理解,包括其特点、优势以及如何构建一个PWA。
  • PWA(Progressive Web Apps)是一种结合Web技术和移动应用体验的新型应用形式,具有离线访问、推送通知、快速加载等特点。优势包括跨平台兼容、无需安装、更新便捷等。构建PWA需要使用Service Worker实现离线缓存、Web App Manifest定义应用信息等步骤。

CSS

  1. 请解释Flexbox中的flex属性和flex-grow、flex-shrink、flex-basis属性之间的区别(其实也有问flex: 1解释一下, flex: 1挤压其他元素怎么处理,这些问题都是相关的,持续性深入的,关于flex: 1和挤压问题自行百度)。
  • flex属性是flex-grow, flex-shrink, flex-basis的缩写,用于同时设置这三个属性的值。
  • flex-grow定义项目的放大比例,如果所有项目的flex-grow值都为1,则它们将等分剩余空间。
  • flex-shrink定义项目的缩小比例,当空间不足时,项目根据其flex-shrink值缩小。
  • flex-basis定义项目在主轴上的初始大小,在分配剩余空间之前,项目将占据其基础大小。
  1. 请解释Flexbox中的align-self属性的作用。
  • align-self属性允许单个Flex项目覆盖其父Flex容器的align-items值,从而在交叉轴上独立地控制该项目的对齐方式。
  1. 请描述Flexbox中的Flex行为如何受到Flex容器的属性影响。
  • Flex容器的属性(如flex-direction, justify-content, align-items, align-content)会影响其中Flex项目的布局方式和对齐方式,通过合理设置这些属性可以实现不同的布局效果。
  1. 请解释Flexbox中的order属性的作用。
  • order属性用于指定Flex项目的排列顺序,数值越小越靠前,默认为0。通过设置不同的order值可以改变项目在Flex容器中的排列顺序。

JavaScript

  1. 请解释一下JavaScript的事件循环(event loop)机制。
  • JavaScript是一种单线程语言,事件循环是其异步编程的基础。事件循环不断地从消息队列中取出消息并处理,包括执行同步任务和异步任务,确保异步任务在适当的时机执行。
  1. 什么是闭包(closure)?请举一个闭包的例子。
  • 闭包是指函数和其周围状态(词法环境)的组合。一个函数可以访问其词法作用域外部的变量,即使该函数在其他地方执行。例如:
function outerFunction() {
  let outerVariable = 'I am from outer function';
  
  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

const closureExample = outerFunction();
closureExample(); // 输出:I am from outer function
  1. 请解释什么是原型链(prototype chain)。
  • 在JavaScript中,每个对象都有一个指向其原型对象的内部链接。当试图访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript会沿着原型链向上查找,直到找到匹配的属性或达到原型链的顶部(Object.prototype)。
  1. 什么是异步编程?请列举几种处理异步操作的方法。
  • 异步编程是指在不阻塞程序执行的情况下处理耗时操作的编程方式。常用的处理异步操作的方法包括回调函数、Promise对象、Async/Await等。
  1. 请解释什么是ES6中的箭头函数(Arrow Functions),并说明与传统函数的区别。
  • 箭头函数是ES6中引入的一种更简洁的函数定义方式,具有以下特点:
    1. 箭头函数没有自己的this,会捕获所在上下文的this值。
    2. 箭头函数不能作为构造函数使用。
    3. 箭头函数没有arguments对象,可以使用Rest参数代替。 当面试官想要挑战你对JavaScript深入理解时,可能会问到以下更具挑战性的问题:
  1. 请解释JavaScript中的事件委托(event delegation)是什么,以及它的优势。
  • 事件委托是一种利用事件冒泡机制,将事件处理程序添加到父元素而不是每个子元素的技术。当子元素触发事件时,事件会冒泡到父元素,然后根据事件的目标来执行相应的处理函数。其优势包括减少内存占用、提高性能、动态元素的事件处理等。
  1. 请解释JavaScript中的原型继承(prototype inheritance)和类继承(class inheritance)之间的区别。
  • 原型继承是JavaScript中基于原型链的继承方式,每个对象都有一个指向其原型对象的链接。而类继承是ES6中引入的类和继承概念,使用class关键字定义类和继承关系。原型继承更灵活,类继承更符合传统面向对象编程的思维。
  1. 请解释JavaScript中的执行上下文(execution context)和作用域链(scope chain)。
  • 执行上下文是JavaScript代码执行时的环境,包括变量对象、作用域链、this等。作用域链是在函数创建时确定的,用于查找变量的值。
  1. 请解释JavaScript中的防抖(debounce)和节流(throttle)是什么,以及它们的应用场景。
  • 防抖和节流都是用于优化性能的技术。防抖是在一段时间内只执行一次函数,常用于输入框输入检测等;节流是在一段时间内限制函数的执行次数,常用于滚动加载等场景。

字符串操作

  1. 实现字符串反转
function reverseString(str) {
    return str.split('').reverse().join('');
}

// 示例
console.log(reverseString('hello')); // 输出:'olleh'
  1. 判断一个字符串是否是回文字符串
function isPalindrome(str) {
    return str === str.split('').reverse().join('');
}

// 示例
console.log(isPalindrome('madam')); // 输出:true
console.log(isPalindrome('hello')); // 输出:false
  1. 实现字符串的排列组合(使用递归):
function permute(str, prefix = '') {
    if (str.length === 0) {
        console.log(prefix);
    } else {
        for (let i = 0; i < str.length; i++) {
            permute(str.slice(0, i) + str.slice(i + 1), prefix + str[i]);
        }
    }
}

// 示例
permute('abc');
  1. 实现字符串的查找算法,如KMP算法(KMP算法是一种高效的字符串匹配算法,这里给出一个简化版的实现):
function kmpSearch(text, pattern) {
    let n = text.length;
    let m = pattern.length;
    
    let lps = computeLPSArray(pattern);
    
    let i = 0; // 指向text的指针
    let j = 0; // 指向pattern的指针
    
    while (i < n) {
        if (text[i] === pattern[j]) {
            i++;
            j++;
        }
        
        if (j === m) {
            console.log('Pattern found at index ' + (i - j));
            j = lps[j - 1];
        } else if (i < n && text[i] !== pattern[j]) {
            if (j !== 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
}

function computeLPSArray(pattern) {
    let m = pattern.length;
    let lps = new Array(m).fill(0);
    
    let len = 0;
    let i = 1;
    
    while (i < m) {
        if (pattern[i] === pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            if (len !== 0) {
                len = lps[len - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
    
    return lps;
}

// 示例
kmpSearch('ABABDABACDABABCABAB', 'ABABCABAB');

数组操作

  1. 实现数组去重
function uniqueArray(arr) {
    return Array.from(new Set(arr));
}

// 示例
const arr = [1, 2, 2, 3, 4, 4, 5];
console.log(uniqueArray(arr)); // 输出:[1, 2, 3, 4, 5]
  1. 实现数组扁平化
function flattenArray(arr) {
    return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenArray(val)) : acc.concat(val), []);
}

// 示例
const arr = [1, [2, [3, 4], 5], 6];
console.log(flattenArray(arr)); // 输出:[1, 2, 3, 4, 5, 6]
  1. 实现数组排序算法,如快速排序、归并排序等(以下为快速排序的示例):
function quickSort(arr) {
    if (arr.length <= 1) {
        return arr;
    }

    const pivot = arr[0];
    const left = [];
    const right = [];

    for (let i = 1; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }

    return quickSort(left).concat(pivot, quickSort(right));
}

// 示例
const arr = [3, 1, 4, 1, 5, 9, 2, 6, 5];
console.log(quickSort(arr)); // 输出:[1, 1, 2, 3, 4, 5, 5, 6, 9]
  1. 查找数组中的最大值、最小值、第K大/小的元素等
const arr = [3, 1, 4, 1, 5, 9, 2, 6, 5];

// 最大值
const max = Math.max(...arr);

// 最小值
const min = Math.min(...arr);

// 第K大的元素
function findKthLargest(arr, k) {
    const sortedArr = arr.slice().sort((a, b) => b - a);
    return sortedArr[k - 1];
}

// 示例
console.log('最大值:', max); // 输出:9
console.log('最小值:', min); // 输出:1
console.log('第3大的元素:', findKthLargest(arr, 3)); // 输出:5

链表操作

  1. 实现链表的反转
class ListNode {
    constructor(val, next = null) {
        this.val = val;
        this.next = next;
    }
}

function reverseLinkedList(head) {
    let prev = null;
    let current = head;

    while (current !== null) {
        let nextTemp = current.next;
        current.next = prev;
        prev = current;
        current = nextTemp;
    }

    return prev;
}

// 示例
let head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);

let reversedHead = reverseLinkedList(head);
  1. 判断链表是否有环
function hasCycle(head) {
    let slow = head;
    let fast = head;

    while (fast !== null && fast.next !== null) {
        slow = slow.next;
        fast = fast.next.next;

        if (slow === fast) {
            return true;
        }
    }

    return false;
}

// 示例
// 判断是否有环,返回true或false
  1. 合并两个有序链表
function mergeTwoLists(l1, l2) {
    if (!l1) return l2;
    if (!l2) return l1;

    if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

// 示例
// 合并两个有序链表,返回合并后的链表头节点
  1. 删除链表中指定数值的节点
function deleteNodesWithValue(head, val) {
    while (head && head.val === val) {
        head = head.next;
    }

    let current = head;
    while (current !== null && current.next !== null) {
        if (current.next.val === val) {
            current.next = current.next.next;
        } else {
            current = current.next;
        }
    }

    return head;
}

// 示例
// 删除链表中所有值为val的节点,返回删除后的链表头节点

还有树操作常见的,二叉树遍历,前序,中序,后序遍历,还有动态规划的斐波那契数列算法那些,这些我是不会,哈哈!

vue

  1. vue2常见的问题,我就不一一列答案了啊,都是高频问题,问的也比较常见和基础。
  • Vue生命周期钩子函数:被问及Vue实例的创建、更新和销毁过程中各个生命周期钩子函数的执行顺序以及各自的作用。
  • 组件通信:被问及父子组件之间、兄弟组件之间、跨级组件之间通信的实现方式,包括props、emitemit、attrs/$listeners、provide/inject等。
  • Vue的响应式原理:被问及Vue是如何实现数据双向绑定的,包括数据劫持、依赖追踪、发布-订阅模式等。
  • Vuex状态管理:被问及Vuex的核心概念、模块化、状态管理流程、辅助函数等。
  • Vue Router:被问及Vue Router的核心功能、路由传参、导航守卫、懒加载路由等。
  • 性能优化:被问及Vue性能优化的方法,包括虚拟DOM、keep-alive、懒加载、异步组件等。
  1. Vue.js 2和Vue.js 3之间的一些主要区别包括:

    a. Composition API: - Vue.js 3引入了Composition API,这是一种新的组织组件逻辑的方式,允许将相关代码组织在一起,提高了代码的复用性和可维护性。Vue.js 2主要使用Options API。

    b. 性能优化: - Vue.js 3在性能方面有所改进,包括更快的渲染速度和更小的包大小,从而提高了应用程序的性能表现。

    c. Tree-shaking支持: - Vue.js 3通过使用ES模块来实现Tree-shaking,使得构建工具能够更好地优化打包大小,减少不必要的代码。

    d. 响应性系统: - Vue.js 3使用Proxy来实现响应性系统,相比Vue.js 2中使用的Object.defineProperty,Proxy具有更好的性能和更直观的API。

    e. Teleport: - Vue.js 3引入了Teleport特性,允许将组件的内容渲染到DOM树中的任何位置,这在处理模态框、弹出框等场景时非常有用。

    f. Fragments: - Vue.js 3支持Fragments,允许组件返回多个根节点,而不需要包裹在额外的元素中。

    g. 全局API重构: - Vue.js 3对全局API进行了重构,使得全局API更加模块化和易于使用。

    h. TypeScript支持: - Vue.js 3对TypeScript提供了更好的支持,包括改进的类型推断和更好的类型定义文件。

  2. Vue 3中的Composition API相对于Options API的优势和使用场景?

    Composition API vs Options API

    • 优势

      • 更灵活的逻辑复用:Composition API允许将逻辑按照功能组织在一起,提高了代码的可读性和维护性。
      • 更好的TypeScript支持:Composition API结构更有利于TypeScript的类型推断,使得代码更加健壮。
      • 更好的代码组织:通过Composition API,可以更容易地将相关逻辑聚合在一起,使得组件更加清晰和易于扩展。
    • 使用场景

      • 复杂逻辑处理:当组件逻辑变得复杂时,使用Composition API可以更好地组织和重用逻辑。
      • 跨组件逻辑共享:需要在多个组件之间共享逻辑时,Composition API能够提供更好的解决方案。
      • TypeScript项目:对于使用TypeScript的项目,Composition API能够更好地与类型系统结合,提供更好的开发体验。
  3. 及Vue 3中新增的Teleport特性的作用和用法。

    Teleport

    • 作用:Teleport是Vue 3中新增的特性,可以将组件的内容渲染到DOM树中的任何位置,而不受父组件的限制。
    • 用法:通过<Teleport>组件和teleport属性,可以将组件的内容渲染到指定的目标容器中,这在处理模态框、弹出框等需要脱离父组件布局的情况下非常有用。
  4. Vue 3是如何实现响应式数据的,包括Proxy相对于Object.defineProperty的优势。

    Vue 3响应式原理

    • 实现原理:Vue 3中通过使用ES6的Proxy对象来实现响应式数据。当数据发生变化时,Proxy可以捕获到对数据的访问和修改,并触发相应的更新。
    • Proxy相对于Object.defineProperty的优势
      • 更灵活:Proxy可以监听对象的任意深度,而Object.defineProperty只能监听对象的属性。
      • 更高效:Proxy在监听多个属性时只需要一个Proxy实例,而Object.defineProperty需要为每个属性都创建一个getter和setter。
      • 更易扩展:Proxy可以监听数组变化,并且支持Map、Set等数据结构,相比之下Object.defineProperty不支持数组监听。

杂谈

  1. 问的最多的是根据简历问的一些项目经历或者后期职业规划啥的(这个就不写了,我接着写些技术相关的)。
  2. webpack和vite的区别 Webpack和Vite是两种常用的前端构建工具,它们有一些区别:

Webpack

  • 成熟度:Webpack是一个非常成熟且功能强大的前端构建工具,广泛应用于各种项目中。
  • 打包速度:在大型项目中,Webpack的打包速度可能会比较慢,特别是在开发环境下。
  • 配置复杂性:Webpack需要较复杂的配置,尤其是对于初学者来说,需要花一些时间来学习和配置。 Vite
  • 轻量级:Vite是一个轻量级的前端构建工具,专注于快速开发体验。
  • 快速冷启动:Vite采用了ESM(ES Module)原生支持,因此具有快速的冷启动速度,特别适合开发阶段的调试和热更新。
  • 开发体验:Vite提供了更好的开发体验,支持快速的热更新、按需编译等功能,使得开发过程更加高效。
  • 总的来说,Webpack适用于更复杂的项目和需求,而Vite则更适合于快速原型开发和小型项目。
  1. Vite与Vue 3之间有着密切的关系,而Vue 3推荐使用Vite作为开发工具的原因如下:
  • 开发体验:Vite提供了快速的冷启动速度和即时热更新的功能,可以使开发者在开发过程中获得更快的反馈,提高开发效率。
  • ES Module(ESM)原生支持:Vite采用ES Module(ESM)原生支持,这意味着在开发过程中无需进行打包,可以直接以浏览器原生支持的方式加载模块,加快了开发速度。
  • 按需编译:Vite支持按需编译,只编译和构建需要的模块,而不是整个应用,这有助于减少不必要的构建时间和资源消耗。
  • 更好的TypeScript支持:Vite对TypeScript的支持更加友好,能够提供更好的类型推断和错误提示,使得开发过程更加健壮和高效。
  • 与Vue 3的优化配合:由于Vue 3本身对构建工具有一些优化需求,如更快的热更新、更好的Tree-shaking等,Vite作为一个专注于快速开发体验的工具,与Vue 3非常匹配。
  • 综上所述,Vue 3推荐使用Vite作为开发工具,主要是因为Vite提供了更快的开发体验、更好的构建优化和更好的TypeScript支持,能够使开发者更加高效地构建现代化的Vue 3应用。希望这个回答能够帮助您理解Vite与Vue 3之间的关系。