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

LeetCode 的 JavaScript 时代实际上填补了空白

Dec 16, 2024 pm 04:34 PM

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

热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

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

前端热敏纸小票打印遇到乱码问题怎么办? 前端热敏纸小票打印遇到乱码问题怎么办? Apr 04, 2025 pm 02:42 PM

前端热敏纸小票打印的常见问题与解决方案在前端开发中,小票打印是一个常见的需求。然而,很多开发者在实...

神秘的JavaScript:它的作用以及为什么重要 神秘的JavaScript:它的作用以及为什么重要 Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

谁得到更多的Python或JavaScript? 谁得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript开发者的薪资没有绝对的高低,具体取决于技能和行业需求。1.Python在数据科学和机器学习领域可能薪资更高。2.JavaScript在前端和全栈开发中需求大,薪资也可观。3.影响因素包括经验、地理位置、公司规模和特定技能。

JavaScript难以学习吗? JavaScript难以学习吗? Apr 03, 2025 am 12:20 AM

学习JavaScript不难,但有挑战。1)理解基础概念如变量、数据类型、函数等。2)掌握异步编程,通过事件循环实现。3)使用DOM操作和Promise处理异步请求。4)避免常见错误,使用调试技巧。5)优化性能,遵循最佳实践。

如何实现视差滚动和元素动画效果,像资生堂官网那样?
或者:
怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? 如何实现视差滚动和元素动画效果,像资生堂官网那样? 或者: 怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? Apr 04, 2025 pm 05:36 PM

实现视差滚动和元素动画效果的探讨本文将探讨如何实现类似资生堂官网(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的演变:当前的趋势和未来前景 JavaScript的演变:当前的趋势和未来前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? 如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中将具有相同ID的数组元素合并到一个对象中?在处理数据时,我们常常会遇到需要将具有相同ID�...

console.log输出结果差异:两次调用为何不同? console.log输出结果差异:两次调用为何不同? Apr 04, 2025 pm 05:12 PM

深入探讨console.log输出差异的根源本文将分析一段代码中console.log函数输出结果的差异,并解释其背后的原因。�...

See all articles