JavaScript 是一门解释型语言或即时编译型语言,在运行时经过编译生成二进制机器码,它的运行大体通过如下几个阶段(以 V8 引擎为例):html
若是使用了 TypeScript,则在运行以前 TypeScript 将会编译成 JavaScript 代码。git
v8 引擎首先会解析源码,生成抽象语法树(AST),基于 AST,解释器即可以开始工做生成字节码,通过编译器后生成能够运行的机器码。github
Go 是一门编译型语言,在代码***运行以前***须要经过编译器生成二进制机器码。它的编译过程大体以下:golang
代码首先会被扫描(词法分析)生成 token,后通过 Parser(语法分析) 生成 AST,接着会有一个类型检查的阶段,一般叫作语义分析,生成中间代码,后通过优化处理后最终生成目标机器码。typescript
TypeScript 和 Go 都是静态类型语言。函数
对于 TypeScript,笔者时常看到有关于它的各类「骚操做」,好比从 A | B
获得 A & B
:优化
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never interface A { name: string; } interface B { age: number; } type Res = UnionToIntersection<A | B>; // A & B 复制代码
或者是:ui
type GetArrayMembers<T> = T extends {[index in keyof T]: infer V } ? V : never
const example = [1, 2, 3] as const;
type Members = GetArrayMembers<typeof example>; // 1, 2, 3
复制代码
这些「骚操做」,几乎不多有人第一眼就能彻底明白其中的含义。甚至多少有点「秀的我脑袋疼」的感受。this
可是考虑到 TypeScript 定义为 JavaScript 的超级,类型系统设计的这么复杂也就不足为奇了,毕竟 JavaScript 是「怎么灵活怎么来」。spa
对于 Go 语言,在 1.x 版本中,它的静态类型常常被调侃成「大道至简」。其中缺乏「泛型」一直被列为该语言须要修复的三大问题之一,探其缘由,无非就是「这个需求我不接」之类的套路话了。不过好在在 2.0 版本中,Go 语言将会实现「泛型」这个功能。
此外,对于咱们时常纠结「何时该用 interface
与 type
」 的问题,Go 语言对此作了很好的限制,它使用了一个新的 struct
,而 interface
则被限制为一组抽象方法的集合:
package main;
import "fmt";
type Human struct {
name string;
age int;
phone string;
}
// go 里方法(函数和方法不相同)
// Human 实现 SayHi 方法
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone);
}
type Men interface {
SayHi()
}
func main() {
mike := Human{ "mike", 25, "137xxx"};
var i Men;
i = mike;
i.SayHi();
}
复制代码
最后,在 TypeScrip 中,你可使用 any
来规避编译器的类型检查,在 Go 中,可使用空 interface
实现与此类似的做用:
let a: any = 1;
a = 'hello';
复制代码
var a interface{}
var i int = 5;
s := "Hello world";
a = i;
a = s;
复制代码
JavaScript 是一种基于原型继承的语言,自 ES6 发布之后,可使用 class
、extends
等语法糖来替代之前繁琐的写法。TypeScript 在此基础上,扩展了类的能力,如添加 public
、private
、protected
等修饰符。
class AChild {
protected name = 'hello world'
}
class PA extends AChild {
say() {
return this.name;
}
}
复制代码
在 Go 语言中,因为没有构造函数,实现面向对象时,你须要这么写:
package main;
import "fmt";
type Human struct {
name string;
age int;
phone string;
}
type Employ struct {
Human; // 匿名字段
company string;
}
// Human 实现 SayHi 方法
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone);
}
// Human 实现 Sing 方法
func (h Human) Sing() {
fmt.Printf("hahaha");
}
// Employee 重载 Human 的 SayHi 方法
func (e Employ) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone)
}
func main() {
mike := Employ { Human { "mike", 25, "137xxx" }, "上海" };
fmt.Printf("name: %s, age: %d. phone: %s, company: %s", mike.name, mike.age, mike.phone, mike.company); // name: mike, age: 25, phone: 137xxx. company: 上海
mike.Sing(); // hahaha
mike.SayHi(); // Hi, I am mike, I work at 千寻. Call me on 137xxx
}
复制代码
不用再纠结该用 export default
仍是 export { xxx }
(因为某些缘由 笔者向来都是推荐使用 export { xxx }
的形式),在 GO 中,当变量或者函数首字母大写,会被认为是导出(公有)。
没有了 this
带来的问题。
go get xxx
装包,可获取一个可执行的二进制文件。
...
欢迎关注公众号