从Lua学习JavaScript(一)
学习 Lua 对于了解 Javascript 的人来说就是小菜一碟,Tyler Neylon 写了三篇文章来解释其中的原因,这是其中的第一篇。
这是通过 Javascript 来学习 Lua 系列文章的第一篇,一共有三篇,第二篇和第三篇。
登陆 Tyler 的免费的网络广播频道收听 Lua 能做什么?
Lua 是一门优雅的,可移植的,高效的并且异常灵活的语言。所有能够编译 C 语言的操作系统都能运行 Lua,这是一些跨平台的框架,比如 Corona SDK 和 Love game engine,选择 Lua 的原因。Lua 的运行速度很快,足够用来开发游戏——愤怒的小鸟的最初是用 Lua 编写的。 Lua 能和其他的语言很好的融合在一起,它作为脚本语言,在 Adobe lightroom 项目中有出色的表现。我认为 Lua 的设计很优美,用起来也非常的舒服。
对于已经了解 Javascript 的人而言,学习 Lua 是非常简单的,因为Lua 和 Javascript 有很多的共同点。在学习的过程中,我们可以通过这些共同点很快的熟悉 Lua,但需要注意两者间一些关键性的不同的地方。
通过 Javascript 的相关知识学习 Lua 的系列总共三篇,这是其中的第一篇。这篇文章中包含一些基础概念:安装 Lua,变量,数据类型,操作符和表达式。第二篇将会涉及流程控制和数据结构,第三篇讲解对象相关的一些知识。
文章中出现的 Javascript 代码大多都遵循 2009 年制定的 EACMScript 5 标准,也就是 ES5 标准。现在最新的 Javascript 标准的是 ES6 或者称为 ES2015。我会用到一些 ES6 的语法,并指出这是 ES6 的特性,这样读者就能知道这段 Javascript 代码遵循的标准。不过读者并不需要了解 ES6,我也不会对用到的 ES6 特性进行解释。
运行 Lua
官方安装指南传送门。
如果在 Mac 上安装了 homebrew,运行 brew install lua
。ubuntu 的话,运行 sudo apt-get install lua5.2
,如果从源码编译安装可以安装最新的版本的 Lua。在 windows 上请使用 LuaDist 安装。
在 Max OSX 和 Linux 上通过编译源码的方式安装 Lua 很简单,执行下面的 shell 命令。如果是 Max OS X,把最后一行的 linux 替换为 macosx 。
curl -R -O http://www.lua.org/ftp/lua-5.3.3.tar.gz
tar zxf lua-5.3.3.tar.gz
cd lua-5.3.3
make linux test # Mac 的话把 linux 替换为 macosx.
安装完成后,就可以使用 lua 命令了,运行 lua 应该看到以下输出。
$ lua
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
>
任意一个文本编辑器都能用来写 Lua 脚本,写一段代码保存为 my_file.lua,执行 Lua 脚本类似 node.js 执行 Javascript 脚本,使用命令就好了。
lua my_file.lua
注释,空格和分号
Lua 中的多行注释的以 --[[
开始,以 ]]
结尾。 如果 --
之后没有 [[
,那么这行是一个单行注释。例如:
print('Why, hello!') -- print 方法输出一段字符串
--[[ 这里是一个
多行注释!]]
Lua 会忽略缩进。一般的空格也会被忽略,但是会保留字符串的空格和单行注释后面的空白行。行尾的分号可写可不写,一般而言不用写。
变量和作用域
和 Javascript 一样, Lua 的变量是动态类型的,也使用垃圾回收器管理内存。多数的 Lua 变量类型都能在 Javascript 中找对应的类型。
Javascript 变量类型 | Lua 变量类型 | Lua 变量例子 |
---|---|---|
boolean | boolean | true or false |
null or undefined | nil | nil |
number | number | 3.141 |
string | string | 'hi' or "there" |
object or array | table | {a=1, [2]=false} |
function | function | function() return 42 end |
symbol(ES6) | unique tables | 'hi' or "there" |
It's handy to classify boolean values in term of falsiness; a value is called falsy when it evaluates to false to a boolean context; Lua 中仅有的假值是 nil 和 false。类似地在 Javascript 中,0
,''
和 undefined
都是假值。
Lua 的 numbers
类型,由于历史原因,使用了浮点数来表示——就像 Javascript 的 numbers
。从 Lua 5.3 开始,Lua 增加了对整数类型的支持,increasing the range of integral values that can be represented exactly.
直观的来看,如果 Lua 的 number
类型变量被初始化为整数,它被当作一个整数,并且会一直保留整数形式直到遇到可将它变为非整数的操作,比如除法。下面的代码展示了 Lua 如何处计算数学表达式——有些运算得到整数,有些得到浮点数。
-- Lua
n = 100
print(n) --> 100; 使用整数形式存储
print(n * 2) --> 200; 运算结果是整数
print(n / 2) --> 50.0; 运算结果是浮点数
类似 Javascript 中的 objects
,Lua 的 table
类型是一个全能的数据结构。
table
可以被用做哈希表或者是数组。不过 Javascript 中 object
的 keys 只能是字符类型,Lua table
的 keys 可以是任何的非 nil
值。在 Lua 中 只有两个 table 是同一个对象时才会相等,而不是它们拥有相同的内容。
-- Lua
myTable = {}
print(myTable == myTable) --> true
print(myTable == {}) --> false
Lua 中 function 是一等公民——可以创建匿名函数,把函数赋值给变量,也可以把函数当作另一个函数的参数或者返回值。如果在函数中引用了定义在该函数作用域之外的自由变量,将隐式地形成一个闭包(译者注:和 Javascript 中的闭包很类似)。同时 Lua 中的函数支持高效的尾递归,也就是在函数的结尾调用另一个函数,调用栈不会增加。
Lua 中还有两个类型 userdata 和 thread。userdata 是使用 Lua 的 C 语言 API 调用 C 语言生成的对象。userdata 就像一个拥有私有数据的 table,也可以自定义它的行为。 Lua 的 thread 是一个 coroutine,允许函数使用 yield 一些值并保持自身的栈和内部状态。
作用域和可变性
Lua 中变量的作用域默认是全局作用域。Lua 的 local
关键字有点像 Javascript 中的 var
,只不过 Lua 中没有声明提升。也就是说,Lua 中的 local
和 ES6 中的 let
一样,都是块级作用域。
-- Lua
phi = 1.618034 -- `phi` 是全局变量。
local gamma = 0.577216 -- `gamma` 只在当前的块作用域下可见。
Lua 中没有常量或者私有变量。不过可以像 Javascript 中一样,使用闭包来模拟私有变量。创建一个函数,在函数中引用定义在函数之外的变量,这就使得这些变量在函数之外不可见,达到类似私有变量的效果。 Lua 的函数相关内容将在下一篇文章中涉及。
操作符和表达式
Lua 和 Javascript 中的数学运算,像是加法和乘法,基本上是一样的。两者都提供了获取余数的操作%
,不同的是: Javascript 中的 %
在左侧操作数是负数时会返回负值,而 Lua 中的 %
总是返回非负值。Lua 中可以使用 ^ 进行指数操作。
-- Lua
print(2 ^ 10) --> 1024.0
print(-2 % 7) --> 5
Javascript 不支持操作符重载,但是 Lua 支持。Lua 通过一种称为 metamethods(修改元数据) 特殊函数实现的重载,这部分内容将会在最后一篇文章中解释。Javascript 有一个三元操作符,但 Lua 中并没有,不过在 Lua 中能实现类似的效果,这需要借助 Lua 中的短路操作符 or 和 and。
-- Lua
-- Lua 中模拟三元操作符.
local x = myBoolean and valueOnTrue or valueOnFalse
-- 例子:找到 a 和 b 的中的最大值.
local maxNum = (a > b) and a or b
-- 类似 Javascript 中的以下代码
-- var maxNum = (a > b) ? a : b;
这个实现很有效除非 valueOnTrue 是假值。大部分情况下都不会有问题因为 Lua 的数字,字符和表不会被当作假值。
比较
在 Javascript 中被广泛认同的的一个最佳实践是使用 ==
而不是 ==
,因为 Javascript 中的 ==
引发令人疑惑的隐式的类型转换。对于 ===
, Javascript 只有当比较的值有相同的类型的时候才会返回 true
。
Lua 只有 ==
一种比较操作符,和 Javascript 中的 ===
一样要求类型相同。以下的例子使用了 Lua 中的内置函数 tonumber
,它将一个字符串转化为数字。
-- Lua
print(6.0 * 7.0 == '42') --> false, 不同的类型
print(6.0 * 7.0 == tonumber('42')) --> true, 都是 number 类型
Lua 的 <
和 >
操作符在比较的值是不同的类型时将会得到 false
。它们比较字符使用字符标排序,比较数字使用数字排序。
位操作符
Lua 5.3 引入了内置的位操作符,见下表。表中的操作符在 Lua 和 Javascript 中都可用。
操作符 | 含义 |
---|---|
& | 与 |
Ι | 或 |
~ | 取反 |
<< | 左移 |
Lua 中的~
,就像 Javascript 中的 ^。
-- Lua
print(6 & 18) --> 2; 00110b AND 10010b = 00010b.
print(6 | 18) --> 22; 00110b OR 10010b = 10110b.
print(6 ~ 18) --> 20; 00110b XOR 10010b = 10100b.
Javascript 中区分了 >> 和 >>> 操作符, >> 保持符号而 >>> 使用 0 填充。Lua 中的 >> 就像 Javascript 中的 >>> 的操作符,使用 0 来填充空位。
这篇文章包含了一下基础知识,运行 Lua并理解 Lua 中的数据类型和表达式。下一篇文章将会包含更多的内容,比如Lua 的流程控制关键字,函数和很重要的 table。
微信搜索【水勺子】关注我,获取更多详细信息