​从语言使用时间上看,我使用 JavaScript 从 2014 年开始,使用 Golang 则是 2018 年。

毕业后第一份工作是以 C++ 工程师身份进入公司,入门是使用 Node.js 开发 C++ addons,然后在领导支持下,开始在公司推广 Node.js,后期全面使用它开发创业项目的前后端。2018 年左右在新公司使用 Golang 重写部分旧项目,自此新项目完全使用 Golang 语言。

我此篇文章中的对比不会深入到底层,也不会做过多比较,非得说哪个好,只是直观的开发经验和感受对比。

学习体验

因为有 C++ 的基础,我在初学 Node.js 时,第一感觉是开发效率高。由于 Js 执行单线程,事件驱动风格,写代码时没有了各种多线程锁、进程间通信、内存申请释放等问题,一下子有种如释重负的感觉。

但事件驱动的编程风格我还是花了比较久的时间才有较深的理解。

学习 Golang 时,因为有了 C++ 和 Node.js 的基础,觉得更简单了,没有什么难以理解的概念,只需掌握些语法和 Go 语言特性就能干活。

从体验上来看, 对比 Node.js, 强类型语言我比较喜欢,避免了很多程序员的犯错机会。

最舒服的还是写并发程序方便,对比写 C、C++ 程序,没啥负担;数据处理的性能、web 程序并发处理请求数量又明显优于 Node.js。唯一不太适应的是 Golang 和 JavaScript 语法的差别有些大,下面会详细讲讲。

语言特性

1)

JavaScript 是解释性的脚本语言,Node 使用了 V8(C++编写) 引擎解释执行Js;Go 语言则先编译后执行。

2)

JavaScript 是弱类型的动态语言,Golang 是强类型的静态语言。在这一点上,我个人比较喜欢强类型语言,严格且有秩序,能最大化避免犯错。

3)

JavaScript 通过原型链来支持面向对象编程,但同样也支持函数式编程,因为函数也是对象,函数也可以被保存在变量中。

Golang 是不是面向对象官方的说辞是:

Yes and No.

但我个人认为,Golang 与我对面向对象的理解,不是严格的 OOP 语言,但允许有 OOP 的风格。

4)

两者都支持垃圾自动回收,基本上所有流行的高级语言都支持了这一功能。

比起 C 和 C++ 完全手动的内存管理方式, 大大减轻了程序员的负担,并且很大程度避免了程序出错的概率。

5)

Golang 函数支持返回多值,这是 Go 的一大特性。

6)

Golang 错误处理不像传统的编程语言,使用 try()catch{},而是利用返回多值的特点,一般判断第二个值 error 是否为空判断,我很不喜欢这一点,写代码时要写很多类似下面的代码:

如果直接忽略可写成这样:

这样写的话,程序又变得不健壮,非常不严谨。Js 则支持 try…catch。

7)

Golang 内置数据类型丰富,支持接口和反射。Js 类型主要有以下:

  • Number(数字)
  • String(字符串)
  • Boolean(布尔)
  • Function(函数)
  • Object(对象)
  • null(空)
  • undefined(未定义)

8)

Golang 对并发编程支持较好,这也是最大的亮点,Go语言引入了用户级线程 goroutine 概念,关于并发编程,Go 的理念是:

Don’t communicate by sharing memory; share memory by communicating.

不要通过共享内存来通信,而应该通过通信来共享内存。

我们还可以利用 通道(channel)在多个 goroutine 之间传递数据。

Node.js 则主要是单线程异步事件触发的风格。

9)

Golang 跨平台运行的支持比 Node.js 好些,编译后能在任意主流系统平台执行。

Node.js 则需要安装 Node 平台,但现在大家都使用了 Docker,也没什么特大的优势。

语法差别

1)

Golang 完全去掉了多余的符号,Js 是可选的,对我来说,刚开始挺不习惯,因为之前接触到的语言每个语句都有分号”;“。

2)

Golang 类型放在变量后面,允许 x, y int 这种写法,这一点在刚开始入门的时候我同样不习惯。

3)

Golang 语法格式要求严格,比如if语句中,强制把 “{” 与if放在同一行,不能换行。JS 则相对灵活。

Golang 开发团队还指定了统一的代码风格,提供了 gofmt 来格式化代码,JS 则没有官方要求,开发中团队自己制定风格。

4)

Go 利用原生的 import 关键字通过包的路径导入模块,Node.js 中使用 require 引入。

在导出变量或者函数时,Node.js 使用 module.exports 显式导出。

在 Go 中,任何首字母大写的函数或者变量都会被默认导出,外部模块引入该包都可使用。

5)

Go 变量必须在编译前先声明或初始化才能使用,也可使用操作符 := 做类型推导。

Js 则在运行时声明类型。

6)

Go string 类型里面每个元素都是一个 byte,显得相对复杂;

JavaScript 中的字符串 String 是一串 Unicode 字符序列,比较容易理解和使用。

包管理

Go 对于包的获取,用go get命令从远程代码库拉(GitHub,Google Code),依赖是扁平化的。

不支持 go mod 管理依赖前,非常不方便,还缺乏明确的版本管理,团队开发不同的项目容易导入不一样的版本。v1.11版本后支持 go mod 并且引入 vendor 目录存放依赖之后体验好多了。

Node.js 的包管理采用 npm 或 yarn,相对成熟和方便,依赖集中存放在 node_modules 目录下,但包的链式递归查找,一层又一层的嵌套,让我在开发中有点痛恨。

测试

写后端代码,单元测试是少不了的。Node.js 单元测试一般我们会引入第三方测试框架 Mocha,以及断言库 should.js。测试用例中直接使用 Mocha 测试 API 中提供的特殊关键字:

  • describe() 表示任意嵌套的测试用例分组
  • it() 表示单个测试用例。

Go 语言中,测试包 testing 是内置的,且含有自带的测试指令go test。测试代码必须写在一个命名为 xxx_test.go 的文件中,它将会在每次执行go test的时候运行,用例有以下特点:

  • 测试函数唯一的参数必须是t *testing.T。
  • 函数名称以 Test 开头,紧接着以大写字母开头的单词或短语。eg: TestFoo(t*testing.T)

社区

Node.js 有广泛的社区,因为毕竟是依托 JavaScript 的,发展了这么多年,JavaScript 是 Web 应用程序开发中最常用的语言,比较成熟,社区也非常活跃。

Golang 的社区则小得多,但两者都有自己的基础社区,在国内, Node.js 主要活跃在 https://cnodejs.org。Go 主要是 https://golang.org,https://studygolang.com。

以上是我粗浅的体验。