终极JavaScript和React面试备忘单

为下一次面试做准备:关键的 JavaScript 和 React 主题

JavaScript 主题

**1. 提升**

提升是 JavaScript 的一种机制,在代码执行之前,在编译阶段将变量和函数声明移至其包含范围的顶部。这意味着您可以在代码中实际声明变量和函数之前引用它们。但是,只有声明会被提升,初始化不会被提升。对于使用“var”声明的变量,它们会被提升并初始化为“undefined”,而“let”和“const”会被提升但不会初始化,如果在声明之前访问,则会导致“临时死区”错误。函数声明会被完全提升,这意味着它们可以在出现在代码中之前被调用。

console.log(a); // undefined
var a = 5;

// Equivalent to:
var a;
console.log(a); // undefined
a = 5;

函数声明也会被提升:

greet(); // "Hello!"
function greet() {
  console.log("Hello!");
}

**2. 结束**

闭包是 JavaScript 中的一项功能,即函数即使在其词法作用域之外执行,也能保留对该作用域的访问权。这允许函数“记住”其周围作用域中的变量。闭包通常用于数据封装、维护状态或在 JavaScript 中创建私有变量。当一个函数在另一个函数内定义并且内部函数引用外部函数中的变量时,就会形成闭包。

function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

const increment = outer();
console.log(increment()); // 1
console.log(increment()); // 2

**3. 承诺**

Promises 表示一个占位符,用于表示将来可用的值。与传统的回调函数相比,它们可以更有效地处理异步操作,从而减少“回调地狱”。Promises 可以处于以下三种状态之一:**待处理**、**已实现**或**已拒绝**。一旦 Promises 被实现或拒绝,它就变为不可变的。Promises 可以提高代码的可读性,并使链接异步操作变得更加容易。

const fetchData = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Data fetched!");
  }, 1000);
});

fetchData.then(data => console.log(data)); // "Data fetched!"

**4. 函数柯里化**

函数柯里化是一种将具有多个参数的函数转换为一系列函数的技术,每个函数都接受一个参数。这种方法在函数式编程中被广泛使用,通过修复原始函数的一些参数来创建可重用的函数。柯里化可以提高代码的可读性、可重用性和模块化。

function add(a) {
  return function(b) {
    return a + b;
  };
}

const add5 = add(5);
console.log(add5(3)); // 8

**5. 执行上下文**

执行上下文定义了 JavaScript 代码的执行环境。它包括在特定时间可访问的变量、对象和函数。执行上下文有三种类型:

  • 全局执行上下文:脚本首次运行时创建。全局范围内声明的变量和函数属于此上下文。
  • 函数执行上下文:每当调用函数时创建,包含其局部变量和参数。
  • Eval 执行上下文:很少使用,在调用 eval() 时创建。执行上下文还决定 this 的值,并涉及作用域链的创建。
  • var a = 10; // Global Execution Context
    function foo() {
      var b = 20; // Function Execution Context
      console.log(a + b); // 30
    }
    foo();

    **6. 呼叫、应用、绑定**

    这些是调用函数时明确设置“this”值的方法。

  • 调用:使用给定的上下文和单独传递的参数来调用一个函数。
  • 应用:类似于调用,但参数以数组形式传递。
  • 绑定:返回一个具有特定上下文和预设参数的新函数,但不立即调用它。
  • const person = {
      name: "Alice",
    };
    
    function greet(greeting) {
      console.log(`${greeting}, ${this.name}`);
    }
    
    greet.call(person, "Hello"); // "Hello, Alice"
    greet.apply(person, ["Hi"]); // "Hi, Alice"
    
    const boundGreet = greet.bind(person);
    boundGreet("Hey"); // "Hey, Alice"

    **7. 常用方法的 Polyfill**

    Polyfill 是用于在无法原生使用某些功能的环境中实现这些功能的代码片段。它们允许较旧的浏览器或运行时环境支持“Array.map”、“Promise”或“Object.assign”等现代 JavaScript 功能。Polyfill 通常用于确保兼容性,并使用模拟缺失功能行为的后备逻辑来实现。

    `Array.prototype.map` Polyfill:

    Array.prototype.myMap = function(callback) {
      const result = [];
      for (let i = 0; i < this.length; i++) {
        result.push(callback(this[i], i, this));
      }
      return result;
    };
    
    console.log([1, 2, 3].myMap(x => x * 2)); // [2, 4, 6]

    React 主题

    **1. 和解**

    协调是 React 更新 DOM 以匹配虚拟 DOM 的过程。React 使用差异算法来确定所需的最少更新次数,从而提高渲染效率。当状态或属性发生变化时,React 会创建一个新的虚拟 DOM,将其与前一个虚拟 DOM 进行比较,然后仅更新已更改的部分。

    **2. 钩子**

    Hooks 是允许函数组件使用状态和生命周期方法等功能的函数,这些功能以前仅在类组件中可用。示例包括用于状态管理的“useState”和用于副作用的“useEffect”。Hooks 使 React 代码更简洁,函数组件更强大。

    import React, { useState } from "react";
    
    function Counter() {
      const [count, setCount] = useState(0);
    
      return (
        

    {count}

    ); }

    **3. 类组件与功能组件**

    类组件是使用 `this` 来表示状态和生命周期方法的 ES6 类。函数组件是渲染 UI 的简单函数。通过引入钩子,函数组件无需类即可管理状态和生命周期。函数组件因其简单性和更好的性能而受到青睐。

    class Counter extends React.Component {
      state = { count: 0 };
    
      increment = () => {
        this.setState({ count: this.state.count + 1 });
      };
    
      render() {
        return (
          

    {this.state.count}

    ); } }

    **4. 记忆化**

    记忆化是一种性能优化技术,用于防止不必要的重新计算或重新渲染。在 React 中,记忆化可确保组件仅在其 props 或状态发生变化时重新渲染。这对于计算成本高昂或更新频繁的组件尤其有用。

    const ExpensiveComponent = React.memo(({ data }) => {
      console.log("Rendered!");
      return 
    {data}
    ; });

    **5. 高阶组件(HOC)**

    HOC 是 React 中的一种设计模式,其中函数将组件作为输入并返回该组件的增强版本。HOC 通常用于代码重用、管理状态以及添加日志记录或身份验证等功能。

    function withLogger(Component) {
      return function WrappedComponent(props) {
        console.log("Props:", props);
        return ;
      };
    }

    **6. 性能**

    提高 React 性能需要使用避免不必要的重新渲染、延迟加载组件以及使用“React.memo”或“useMemo”优化渲染等技术。开发人员还可以使用 React Profiler 等工具来识别瓶颈。

    **7. React 路由器**

    React Router 是一个用于管理 React 应用程序中导航的库。它允许开发人员定义路由并根据 URL 动态渲染组件。功能包括嵌套路由、路由参数和导航保护。

    import { BrowserRouter, Route, Link } from "react-router-dom";
    
    function App() {
      return (
        
          Home
           
    Home Page
    } />
    ); }

    **8. 缓存**

    React 中的缓存涉及存储常用数据以避免重新获取。这可以使用“react-query”、“Redux”或 localStorage 等库来实现。缓存通过减少加载时间来提高性能和用户体验。

    **9. 安全**

    为了保护 React 应用程序的安全,开发人员应验证和清理用户输入、使用 HTTPS 并避免使用内联 JavaScript 来防止 XSS 攻击。诸如“Helmet”之类的库有助于设置安全的 HTTP 标头。身份验证和授权也应安全地实施。

    **10. 提高绩效**

    可以通过以下方式提高性能:

  • 通过代码分割来减少捆绑包的大小。
  • 避免不必要的状态更新。
  • 使用 React.lazy 进行延迟加载。
  • 优化图像和资产。
  • 使用高效的算法完成计算任务。
  • **11. 内存泄漏**

    当对象不再使用但未被垃圾回收时,就会发生内存泄漏。在 React 中,泄漏通常源于事件侦听器、计时器或订阅的不当清理。使用带有清理函数的 `useEffect` 可确保正确清理,从而防止此类问题。

    清理 `useEffect` 中的订阅或计时器:

    useEffect(() => {
      const timer = setInterval(() => console.log("Running"), 1000);
      return () => clearInterval(timer); // Cleanup
    }, []);

    总之,掌握 JavaScript 和 React 的核心概念对于任何想要构建强大而高效的应用程序的开发人员来说都至关重要。这些原则不仅构成了 Web 开发的基础,还可以帮助您自信地应对复杂的挑战。无论是理解闭包、使用 React 优化性能,还是实施安全最佳实践,对这些主题的深入了解都将让您在面试和职业生涯中脱颖而出。不断探索、练习和完善您的技能——因为在不断发展的编程世界中,学习之旅永远不会真正结束。