大多数编码挑战都会教你解决难题。 LeetCode 的 30 天 JavaScript 学习计划做了一些不同的事情:它向您展示了拼图如何变成砖块,准备好构建现实世界的项目。
这种区别很重要。当您解决典型的算法问题时,您正在训练您的思维进行抽象思考。但是,当您实现去抖1函数或构建事件发射器2时,您正在学习真正的软件是如何工作的。
我自己在应对挑战时发现了这一点。这种体验不太像解决脑筋急转弯问题,而更像考古学——揭示特定的现代 JavaScript 概念。每个部分都重点介绍 JS 的另一项现代功能。
这个学习计划的奇特之处在于它不会教你 JavaScript。事实上,我相信您需要相当了解 JavaScript 才能从中受益。相反,它教的是如何使用 JavaScript 来解决实际的工程问题。
考虑 Memoize3 挑战。从表面上看,它是关于缓存函数结果的。但你真正学到的是为什么像 React 这样的库需要记忆来有效地处理组件渲染。或者以 Debounce1 问题为例 - 这不仅仅是实现延迟;它还涉及延迟。它可以帮助您直接理解为什么每个现代前端框架、电梯以及基本上任何具有交互式 UI 的系统都需要这种模式。
这种对实用模式而不是语言基础知识的关注创造了一个有趣的限制;您需要处于以下两个位置之一才能受益:
- 您了解 CS 基础知识(尤其是数据结构和算法)并且熟悉 JavaScript
- 您的计算机科学理论很强,并且之前接触过一些 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 是本节中我最喜欢的一个
模式识别,而不是解决问题
让我们剖析一些问题,以展示该学习计划的真正价值。
- 记忆 (#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
- 反跳 (#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 生态系统的更深入理解。
这就是本学习计划填补的空白:将理论知识与实践工程智慧联系起来。
-
2627。 Debounce(承诺与时间)↩
-
2694。事件发射器(类)↩
-
2623。 Memoize(函数转换)↩
-
2636。承诺池(奖金)↩
以上是LeetCode 的 JavaScript 时代实际上填补了空白的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

10款趣味横生的jQuery游戏插件,让您的网站更具吸引力,提升用户粘性!虽然Flash仍然是开发休闲网页游戏的最佳软件,但jQuery也能创造出令人惊喜的效果,虽然无法与纯动作Flash游戏媲美,但在某些情况下,您也能在浏览器中获得意想不到的乐趣。 jQuery井字棋游戏 游戏编程的“Hello world”,现在有了jQuery版本。 源码 jQuery疯狂填词游戏 这是一个填空游戏,由于不知道单词的上下文,可能会产生一些古怪的结果。 源码 jQuery扫雷游戏

本教程演示了如何使用jQuery创建迷人的视差背景效果。 我们将构建一个带有分层图像的标题横幅,从而创造出令人惊叹的视觉深度。 更新的插件可与JQuery 1.6.4及更高版本一起使用。 下载

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

Matter.js是一个用JavaScript编写的2D刚体物理引擎。此库可以帮助您轻松地在浏览器中模拟2D物理。它提供了许多功能,例如创建刚体并为其分配质量、面积或密度等物理属性的能力。您还可以模拟不同类型的碰撞和力,例如重力摩擦力。 Matter.js支持所有主流浏览器。此外,它也适用于移动设备,因为它可以检测触摸并具有响应能力。所有这些功能都使其值得您投入时间学习如何使用该引擎,因为这样您就可以轻松创建基于物理的2D游戏或模拟。在本教程中,我将介绍此库的基础知识,包括其安装和用法,并提供一

本文演示了如何使用jQuery和ajax自动每5秒自动刷新DIV的内容。 该示例从RSS提要中获取并显示了最新的博客文章以及最后的刷新时间戳。 加载图像是选择


热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),