Java, .NET 程序员如何学习Javascript?

最近有原本是 Java 或者 .NET 背景的朋友问我:“如果学习 Javascript (后文简称 JS) 应该走什么学习路径?”

其实之前在知乎上此类问题是很多的,但是真要回答这个问题还真不容易。因为没有办法定义什么叫“学会”。JS 应用领域如此广泛,从 Web 前端、Native Client 到各种后台服务、工具链;npm 上的包超过了 20万;超过100种语言可以编译到 JS。这么多的应用领域和编程风格的尝试,使得如何定义“学会”成为一个首要的问题。

好在 NodeSchool 已经为入门安排了台阶。学习 JS 其实离不开学习 Node.JS,这个和前端后端无关。因为即使是现在的前端框架,也离不开 Node.JS 构造的工具链。

NodeSchool 将课程划分为 Core 和 Electives 两部分。Core 部分的课程是基础,Electives 则可以根据个人的工作方向进行选择。

NodeSchool的很多贡献者都是 Node.JS 的核心贡献者:GitHub/substack, GitHub/rvagg, GitHub/julianduque等等。每个课程都是独立维护的 GitHub Repo.

在这个学习过程中,先不要去想 React, Angular, Relay, Gulp, WebPack 之类的高层框架,先掌握基本知识,锻炼新的思维方式和编程方法。

Core

Core 的课程分为以下6门:

  1. Javascripting: 这是针对没有任何 JS 基础的程序员的,对于有经验的程序员可以快速过一遍。这门课没有牵扯到任何 ES2015 的语法,是基础的基础。
  2. LearnYourNode: 这门课让你尝尝 Node.JS 的滋味,学习基于 CommonJS 的模块系统的使用,重点是异步调用(基于时间、文件IO, HTTP等),体会 Callback 的风格和问题。传统的基于栈展开的异常处理突然不能用了等等。你会很快发现 Callback 给你带来的“不快”,但是需要很久才能接受这种“命运”,最终对现实世界是异步的本质真的理解,未掌握新的“工具”和思考方式打下基础。
  3. git-it: 这门课是 git 的入门,可能有人已经了解很深。重点是教会程序员从创建 repo.、commit、fork、pull request 到 merge 的过程,让程序员能够尽快地参与到开源社区的贡献中(例如为既有的 repo. 提交pull request)。
  4. How to npm: npm 以前是 Node.JS 的“家”,现在已经是所有 JS 程序员的“家”,以前的一些前端包管理工具要么停止(Component)要么萎缩(Bower)。这个教程教你如何安装你自己的依赖包,Packags.json 文件的基本定义。发布自己的包到 npm 让全世界的程序员都能使用。Node.JS 的成功有一半是因为 npm, 想想为什么。npm + js 让 “Module Driven Development” 成为现实,你也应该有意识地讲自己的代码尽量写成独立的小“模块”,拥有自己的 README,可选的样例程序或者单元测试,让使用者有一个很平缓的学习曲线。
  5. Scope Chains & Closures: 闭包的概念其实在 Java/.NET 中早已经添加,但是没有像在 JS 中用得如此普遍。教程最后会让你尝试一下在 Chrome 里面抓一抓内存时序的Dump,体会一下 GC对内存的影响。
  6. Stream Adventure: Node.JS 只有非常有限的核心库以及很少的“约定”。如果说 Callback 是第一重要的“约定”的话,那么 Stream 可以排在第二。在异步编程中,Callback 是 Request/Response的最原始实现方式,而 Stream 则用来定义如何处理异步事件流。Stream 最早的概念来自于 Unix 的管道操作,使得每个应用都可以专注于很小的功能,但是通过组合这些小应用来完成非常复杂的任务。在Node.JS中,Stream既可以像Unix管道那样传输任何二进制数据,也可以用来传递传输 JS 对象流(Gulp就是基于JS对象流设计的)。在学习完这门课程之后(或者学习完后面的 Async 课程),可以看一下 highlandjs(高层的基于 JS 对象 Stream 的库)以及 BaconKefir这样的 FRP(Functional Reactive Programming) 库,或者 transducers(关注输入输出源无关的转换过程),它们都具有近似的基因,就是如何将函数式编程的方法用在变化的事件流上,不断组合出新的输出。

Electives

Electives 的课程很多,慢慢分到了不同的方向。其中甚至有 WebGL 的课程(前端程序员和Native Client是时候关心 GL 编程了)。随着时间推移,有一些课程原本不属于 Core 的课程我觉得也应该是基础课了:

  1. Functional Javascript:Javascript 可以支持四种编程思维:命令式,面向对象(OO),函数式编程(Functional)以及元编程(Meta Programming,例如: ES2015 的 Proxy)。其中函数式编程的方式是最应该被 Java/.NET 程序员重视的。因为Java/.NET 程序员往往工作在OO为主,FP 为辅(偶尔用用 Lambda 之类的)的环境中,但是在大量的 JS 世界中 FP 的方式要远远多于 OO的方式。函数真的是被当成第一级的公民。函数返回函数再返回函数再返回函数的代码比比皆是,大量使用递归,再加上异步的话,如果没有对既有模式形成条件反射,阅读别人得代码很容易迷失。
  2. Planet Proto: Javascript 原型继承绝不是你熟悉的 Java/.NET 的方式。这门课让你了解什么是原型链,消息是如何在原型链上传递的等等概念。
  3. Async You: 在 Promise 之前,async 库是Callback最早的治愈系。其作者GitHub/caolan 后来撰写了 highlandjs。通过这个课程你可能会体会到,异步问题有异步的解决思路和方法。如果像Java/.NET 通常那样把异步编程都包装成同步方式,看起来简单,但是缺在其他付出了更大代价。我建议你试试自己实现 async 的个别功能,这对于掌握异步函数式编程是非常有帮助的。
  4. Promise It Wont Hurt:Promise 已经成为 JS 的规范的一部分,被广泛使用,也被广泛支持,因此是 Callback 最直接的替代者,不可不知道。这个教程用的Promise 库是 Q,现在用Bluebird性能更好。如果前端开发,需要精简的代码,那么ES2015 的 Promise (可以用 Babel的实现)基本也够用了。
  5. count-to-6:这是 ES2015 (原来叫 ES6)相关的教程。其实学习到这个阶段,能看的 ES2015 的教程就太多了。阮一峰ECMAScript 6入门 就不错。用 ES2015 编写的包越来越多,我建议你也开始学习和使用。如果你不掌握 ES2015,你很快就会发现看不懂别人写的 JS 程序了。
  6. Tower-of Babel: 如果没有 Babel,你也就不能充分享受 Es2015或者 ES7带来的新功能了。Babel 已经不仅仅是为新语法做 Polyfill,同时也在帮你优化代码的性能。大量的前端库没有都是在 Babel 支持下开发的,例如 React 或者 React Native。后端用 Babel 也不亏😀。

至于其他课程,你完全可以根据自己的方向来选择,例如:

  1. 如果希望看到如何基于Javascript 搭建出乐高积木一样的存储引擎,那么可以从 Level Me Up Scotty开始。
  2. learnuv 则已经是 LibUV 的教程了。Node.JS 的消息泵、异步IO的文件和网络、时钟功能实际上都是 LibUV 提供的。了解 LibUV 有助于你了解所有和消息泵时序有关的功能(process.nextTick(), setImmediate(), setTimeout() 等等),同时也是写 Native Binding 的基础。在了解 LibUV 之后,如果真的要写 Native Binding,那么就是 Go Native这个教程了。当然这个 Native 是针对的 Google V8 引擎。
  3. 大部分 Node.JS 的教程都是从 Express 开始的。Node.JS 也提供了对应的课程Express Works。在学习 ESNext Generation 之后,可以学习 Koa,一个基于 Coroutine(Javascript 有很多 Coroutine 的实现库,Koa 用了 co)实现的 Web Server 框架(用来替代 Express)。

其实学到到这个阶段,对于有经验的 Java/.NET 程序员来说已经可以自由学习了,只要英文的阅读理解能够过关。但是这个阶段的学习过程绝不是把教程看一遍,作业做一遍,一定要结合上自己的设问,以及对这些问题的答案寻求(通过 Google、实验、互联网或者问身边的有竟然的人来寻求答案)。因此这个过程不应该很快,持续几个月是很正常的。

其他注意事项

不要有“成见”

对于有经验的 Java, .NET 程序员,学习 JS 最大的障碍实际是你心中的“成见”,例如:

  1. JS 是个玩具语言
  2. JS 性能差
  3. Callback Hell
  4. JS 类型约束太弱,不安全,容易犯错
  5. JS 是单线程的,不能写 Server 应用
  6. 没有有效的内存管理…
  7. 函数式编程消耗太大…
  8. 闭包造成内存泄露不释放…
  9. JS 不是真正的函数式语言(来自Haskell 程序员或者 F#)

“然并卵”,如果你之前掌握的语言没有足够的应用场景,语言本身再好又有什么用?再说这个世界上从来就没有所谓“最好”的编程语言,只有适合不适合当时当地场景的语言。JS 能够获得广泛运用的原因之一,就是其松散的约定和实现的低成本,结果就被大家在不同的时间装扮成了自己喜欢的样子。与其坐着骂 JS,不如想想怎么装扮 JS 来满足自己的需要。

尽量不要用 Windows 进行开发

尽管 Node.JS 号称支持 Windows,但是大部分开发者写的包都没有专门在 Windows 下调试过,尤其是那些有 Native Binding 的包,情况会变得更复杂。

不要依赖 IDE

没有 Windows 就没有 Visual Studio,而且也就没有什么 IntelliSense 之类的代码提示。专注于好的命名比工具更重要。 很遗憾,Mac/Linux 没有能媲美 Visual Studio 的工具。我的选择是速度最快的那个 Sublime,这么多年不仅没有用到 IntelliSense,Debug 也基本靠 console.log

大量阅读别人的代码

阅读别人的程序也是很好的学习方法。从一个库入手,捋着它的npm 依赖开始阅读,不了解的概念就 Google,或者进行实验,往往几天时间就可以有很大的提高。这个学习过程也是体会 “Module Driven Development” 的过程,你经常会惊诧于,这么一点点功能也可以包成一个 npm 包,但是如果是我来写真没人家考虑得周全。

阅读别人的代码的过程往往能发现无数的小知识点:它 npm 的 package.json 为什么有这个字段?还可以这样写?它怎么用 tap 做单元测试而不是 mocha? 这个项目用 Beefy 比 WebPack 更经济;npm shrinkwrap 是什么意思…

和有经验的人一起写

除了上面所说的,最好找有经验的人来带或者和能力高强的人一起工作。JS 是“大海”一样的领域,你永远不知道下周会出现什么新的知识,更何况海中已经有的这么多资源。学完上面的东西毕竟只是学会了游泳。自己摸索到能够扬帆出海还是要花费大量的时间成本。

    原文作者:jacobbubu
    原文地址: https://www.jianshu.com/p/3355074feb00
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞