搜索
首页web前端js教程LeetCode 的 JavaScript 时代实际上填补了空白

The Gap That LeetCode

大多数编码挑战都会教你解决难题。 LeetCode 的 30 天 JavaScript 学习计划做了一些不同的事情:它向您展示了拼图如何变成砖块,准备好构建现实世界的项目。

这种区别很重要。当您解决典型的算法问题时,您正在训练您的思维进行抽象思考。但是,当您实现去抖1函数或构建事件发射器2时,您正在学习真正的软件是如何工作的。

我自己在应对挑战时发现了这一点。这种体验不太像解决脑筋急转弯问题,而更像考古学——揭示特定的现代 JavaScript 概念。每个部分都重点介绍 JS 的另一项现代功能。

这个学习计划的奇特之处在于它不会教你 JavaScript。事实上,我相信您需要相当了解 JavaScript 才能从中受益。相反,它教的是如何使用 JavaScript 来解决实际的工程问题。

考虑 Memoize3 挑战。从表面上看,它是关于缓存函数结果的。但你真正学到的是为什么像 React 这样的库需要记忆来有效地处理组件渲染。或者以 Debounce1 问题为例 - 这不仅仅是实现延迟;它还涉及延迟。它可以帮助您直接理解为什么每个现代前端框架、电梯以及基本上任何具有交互式 UI 的系统都需要这种模式。

这种对实用模式而不是语言基础知识的关注创造了一个有趣的限制;您需要处于以下两个位置之一才能受益:

  1. 您了解 CS 基础知识(尤其是数据结构和算法)并且熟悉 JavaScript
  2. 您的计算机科学理论很强,并且之前接触过一些 JavaScript

连接计算机科学和软件工程

学习计算机科学和实践软件工程之间会发生一些奇怪的事情。这种转变感觉就像学习了多年的国际象棋理论,却发现自己在玩一种完全不同的游戏 - 规则不断变化,而且大多数动作都不在任何书本中。

在计算机科学中,您将学习二叉树的工作原理。在软件工程中,您需要花费数小时调试 API,试图了解响应缓存不起作用的原因。从远处看,这些世界之间的重叠可能看起来比实际要大得多。其中存在差距,这常常会让计算机科学毕业生在开始职业生涯时感到震惊。不幸的是,大多数教育资源都无法弥补这一点。它们要么纯粹是理论性的(“这是快速排序的工作原理”),要么是纯粹的实用性(“这是如何部署 React 应用程序”)。

这个 JavaScript 学习计划的有趣之处并不是它设计得特别好 - 而是它在这些世界之间创建了联系。以记忆问题为例:2623。记忆3。用计算机科学术语来说,它是关于缓存计算值的。但实现它会迫使您应对 JavaScript 在对象引用、函数上下文和内存管理方面的特殊性。突然,
你不只是在学习算法 - 你开始理解为什么像 Redis 这样的东西存在。

这种风格在整个挑战中不断重复。 Event Emitter2 实现不仅仅是教科书观察者模式 - 您可以将其视为将 V8 引擎从浏览器中取出并围绕它构建 Node.js 的原因,这实际上是有意义的。 Promise Pool4 解决并行执行问题,也就是数据库需要连接限制的原因。

隐藏课程

本学习计划中的问题顺序不是随机的。它正在逐层构建现代 JavaScript 的心理模型。

它从闭包开始。并不是因为闭包是最简单的概念 - 它们非常令人困惑 - 而是因为它们是 JavaScript 管理状态的基础。

function createCounter(init) {
    let count = init;
    return function() {
        return count++;
    }
}

const counter1 = createCounter(10);
console.log(counter1()); // 10
console.log(counter1()); // 11
console.log(counter1()); // 12

// const counter1 = createCounter(10);
// when this^ line executes:
// - createCounter(10) creates a new execution context
// - local variable count is initialized to 10
// - a new function is created and returned
// - this returned function maintains access 
// to the count variable in its outer scope
// - this entire bundle 
// (function (the inner one) + its access to count) 
// is what we call a closure

这种模式是 JavaScript 中所有状态管理的种子。一旦你了解了这个计数器的工作原理,你就了解了 React 的 useState 在幕后是如何工作的。您了解为什么模块模式出现在 ES6 之前的 JavaScript 中。

然后计划转向功能转换。这些教你函数装饰——函数包装其他函数以修改它们的行为。这不仅仅是一个技术技巧;这就是 Express 中间件的工作方式,React 高阶组件的工作方式,
以及 TypeScript 装饰器的工作原理。

当您遇到异步挑战时,您不仅仅是在学习 Promise,您还会发现 JavaScript 最初需要它们的原因。 Promise Pool4 问题并不是在教你一个创新的、古怪的 JS 概念;而是在教你一个创新的、古怪的 JS 概念。它向您展示了为什么每个数据库引擎中都存在连接池。

以下是学习计划各部分与现实世界软件工程概念的粗略映射:

  • 关闭 → 状态管理
  • 基本数组变换 → 基本技能(辅助);实际示例:数据操作
  • 函数转换 → 中间件模式
  • 承诺与时间 ->异步控制流
  • JSON ->基础技能(辅助);实例:数据序列化、API通信
  • (特别是在事件发射器的上下文中)→消息传递系统
  • 奖金(高级锁定)->可能包含在上述部分中的更难的挑战的组合; Promise Pool4 是本节中我最喜欢的一个

模式识别,而不是解决问题

让我们剖析一些问题,以展示该学习计划的真正价值。

  1. 记忆 (#2623)

考虑 Memoize 挑战。我喜欢它的原因是(我能想出的)最好的解决方案
非常简单,就好像代码本身在温和地告诉您它的作用(不过,我添加了一些注释)。

无论如何,这并不会让 #2623 成为一个简单的问题。我之前需要两次迭代才能使它变得如此干净:

function createCounter(init) {
    let count = init;
    return function() {
        return count++;
    }
}

const counter1 = createCounter(10);
console.log(counter1()); // 10
console.log(counter1()); // 11
console.log(counter1()); // 12

// const counter1 = createCounter(10);
// when this^ line executes:
// - createCounter(10) creates a new execution context
// - local variable count is initialized to 10
// - a new function is created and returned
// - this returned function maintains access 
// to the count variable in its outer scope
// - this entire bundle 
// (function (the inner one) + its access to count) 
// is what we call a closure
  1. 反跳 (#2627)

想象一下你在电梯里,有人疯狂地反复按“关门”按钮。

没有去抖:电梯会在每按一次门时尝试关门,导致门机构工作效率低下,甚至可能损坏。

防抖:电梯会等待,直到人停止按下一定时间(假设 0.5 秒),然后才真正尝试关门。这样效率就高多了。

这是另一种情况:

假设您正在实现一个搜索功能,可以在用户键入时获取结果:

没有去抖动:

/**
 * @param {Function} fn
 * @return {Function}
 */
function memoize(fn) {
    // Create a Map to store our results
    const cache = new Map();

    return function(...args) {
        // Create a key from the arguments
        const key = JSON.stringify(args);

        // If we've seen these arguments before, return cached result
        if (cache.has(key)) {
            return cache.get(key);
        }

        // Otherwise, calculate result and store it
        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    }
}

const memoizedFn = memoize((a, b) => {
    console.log("computing...");
    return a + b;
});

console.log(memoizedFn(2, 3)); // logs "computing..." and returns 5
console.log(memoizedFn(2, 3)); // just returns 5, no calculation
console.log(memoizedFn(3, 4)); // logs "computing..." and returns 7


// Explanantion:
// It's as if our code had access to an external database

// Cache creation
// const cache = new Map();
// - this^ uses a closure to maintain the cache between function calls
// - Map is perfect for key-value storage

// Key creation
// const key = JSON.stringify(args);
// - this^ converts arguments array into a string
// - [1,2] becomes "[1,2]"
// - we are now able to use the arguments as a Map key

// Cache check
// if (cache.has(key)) {
//     return cache.get(key);
// }
// - if we've seen these arguments before, return cached result;
// no need to recalculate

这将进行 10 次 API 调用。其中大多数都没用,因为用户仍在打字。

带去抖动(300 毫秒延迟):

// typing "javascript"
'j' -> API call
'ja' -> API call
'jav' -> API call
'java' -> API call
'javas' -> API call
'javasc' -> API call
'javascr' -> API call
'javascri' -> API call
'javascrip' -> API call
'javascript' -> API call

去抖就像告诉你的代码:“等到用户停止执行某些操作 X 毫秒后再实际运行此函数。”

这是 LeetCode #2627 的解决方案:

// typing "javascript"
'j'
'ja'
'jav'
'java'
'javas'
'javasc'
'javascr'
'javascri'
'javascrip'
'javascript' -> API call (only one call, 300ms after user stops typing)

现实世界中其他常见的去抖动用例(搜索栏除外):

  • 保存草稿(等待用户停止编辑)
  • 提交按钮(防止重复提交)

出了什么问题

我希望,从这篇文章整体积极的基调来看,我对JS 30天的看法现在已经清晰了。

但是没有任何教育资源是完美的,而且,当涉及到局限性时,诚实是有价值的。这个学习计划有几个盲点值得审视。

首先,学习计划假设有一定水平的先验知识。
如果您还不太熟悉 JavaScript,那么有些挑战可能会令人难以承受。这可能会让初学者感到沮丧,因为他们可能对学习计划有其他期望。

其次,挑战是以孤立的方式呈现的。
这在一开始是有道理的,但随着计划的进展,你可能会感到失望。现实世界的问题通常需要结合多种模式和技术。研究计划可以受益于更综合的挑战,这些挑战需要一起使用多个概念(例外:我们在整个计划中都使用了闭包)。这些很适合放在奖励部分(已经为高级用户保留)。

最后,这组挑战的主要弱点在于其概念解释。来自竞争性节目,
我习惯于在问题陈述中明确新术语和概念的定义。然而,LeetCode 的描述通常过于复杂——理解他们对去抖函数的解释比实现实际的解决方案更难。

尽管有缺点,该学习计划仍然是理解现代 JavaScript 的宝贵资源。

30 天之后

理解这些模式只是一个开始。
真正的挑战是识别何时以及如何将它们应用到生产代码中。这是我在野外遇到这些模式后发现的。

首先,这些模式很少单独出现。真实的代码库以挑战无法探索的方式将它们组合起来。考虑一个从头开始实现的搜索功能。您可能会发现自己使用:

  • 输入处理的反跳
  • 结果缓存的记忆
  • 承诺 API 调用超时
  • 用于搜索状态管理的事件发射器

所有这些模式相互作用,创造了复杂性,没有任何单一的挑战能让您做好准备。但是,在自己实现了每个部分之后,您就会大致了解整个实现的运作方式。

与直觉相反,您将获得的最有价值的技能不是实现这些模式 - 而是在其他人的代码中识别它们。

最后的想法

完成本学习计划后,编程面试并不是您认识这些模式的唯一地方。

您会在开源代码、同事的拉取请求中发现它们,并且可能会开始在您过去的项目中注意到它们。您以前可能已经实现了它们,甚至没有意识到。最重要的是,您会明白它们为何存在。

最初的解谜转变为对现代 JavaScript 生态系统的更深入理解。

这就是本学习计划填补的空白:将理论知识与实践工程智慧联系起来。



  1. 2627。 Debounce(承诺与时间)↩

  2. 2694。事件发射器(类)↩

  3. 2623。 Memoize(函数转换)↩

  4. 2636。承诺池(奖金)↩

以上是LeetCode 的 JavaScript 时代实际上填补了空白的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

node.js流带打字稿node.js流带打字稿Apr 30, 2025 am 08:22 AM

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python vs. JavaScript:性能和效率注意事项Python vs. JavaScript:性能和效率注意事项Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript的起源:探索其实施语言JavaScript的起源:探索其实施语言Apr 29, 2025 am 12:51 AM

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

幕后:什么语言能力JavaScript?幕后:什么语言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

Python和JavaScript的未来:趋势和预测Python和JavaScript的未来:趋势和预测Apr 27, 2025 am 12:21 AM

Python和JavaScript的未来趋势包括:1.Python将巩固在科学计算和AI领域的地位,2.JavaScript将推动Web技术发展,3.跨平台开发将成为热门,4.性能优化将是重点。两者都将继续在各自领域扩展应用场景,并在性能上有更多突破。

Python vs. JavaScript:开发环境和工具Python vs. JavaScript:开发环境和工具Apr 26, 2025 am 12:09 AM

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境