【译】从 JS 学习 Lua

1,770 阅读7分钟
原文链接: www.jianshu.com

原文:Learning Lua/From JS

对 JavaScript 已经了解,想学习下 Lua?下面我们来快速列举下两者的相似和不同之处。更多资料见“学习 Lua”。

相似之处

区分大小写

Lua 和 JS 都区分大小写。truefalse 是布尔型字面量值,和 TrueTRUE 完全不同。

函数可以有可变数目的参数

在 Lua 中,和 JS 类似,可以向你的函数传递比声明的更多或更少的参数:

function showem( a, b, c )
  print( a, b, c )
end

showem( 'first' )                              --> first nil nil
showem( 'first', 'second' )                    --> first second nil
showem( 'first', 'second', 'third' )           --> first second third
showem( 'first', 'second', 'third', 'fourth' ) --> first second third

JS 中通过特殊的 arguments 可以获取所有的实参。在 Lua 5.0 中,对应是称为 arg 的表,但是只收集通过特殊的 ... 在形参列表标记的那些形参:

function showem( a, b, ... )
  local output = tostring(a) .. "\t" .. tostring(b)
  for i,v in ipairs(arg) do
    output = output .. "\t#" .. i .. ":" .. v
  end
  print( output )
end

showem( 'first'  )                             --> first  nil
showem( 'first', 'second' )                    --> first  second
showem( 'first', 'second', 'third' )           --> first  second  #1:third
showem( 'first', 'second', 'third', 'fourth' ) --> first  second  #1:third  #2:fourth

在 Lua 5.1 中,表 arg 被“可变参数表达式(vararg expressions)”替代:

function showem( a, b, ... )
  local output = tostring(a) .. "\t" .. tostring(b)
  local theArgs = { ... }
  for i,v in ipairs( theArgs ) do
    output = output .. "\t#" .. i .. ":" .. v
  end
  print( output )
end

showem( 'first'  )                             --> first  nil
showem( 'first', 'second' )                    --> first  second
showem( 'first', 'second', 'third' )           --> first  second  #1:third
showem( 'first', 'second', 'third', 'fourth' ) --> first  second  #1:third  #2:fourth

哈希表(hash)通过中括号或点记法引用

在 JS 和 Lua 中,访问哈希表的索引可以通过中括号:

theage = gavin[ 'age' ]

或点记法:

theage = gavin.age

数值就是数值

在 JS 和 Lua 中,整数和浮点数没有区别,不同长度的对象也没有对应不同的类型。所有的数值在 Lua 中都是“数值(number)”。

语句以分号结尾

在 JS 和 Lua 中,分号(;)用于表明语句的结束。并且两门语言中在一行结尾的分号都是可选的。

在 JS 中,习惯上使用分号。在 Lua 中,习惯上不用分号。

缺省的全局变量

在 JS 中,如果在一个函数中为之前未出现的变量赋值,如果存在 var 关键字那么变量是局部变量,否则是全局变量:

function foo( )
{
  var jim = "This variable is local to the foo function";
  jam = "This variable is in global scope";
}

Lua 中也类似,关键字 local 声明局部变量,没有时则为全局变量:

function foo( )
  local jim = "This variable is local to the foo function";
  jam = "This variable is in global scope";
end

字符串以双引号和单引号为界

在 JS 和 Lua 中,字符串字面量允许使用单引号或双引号(成对)。和 JS 一样(但与 Ruby 或 PHP 不同),使用哪个没有区别。和 JS 一样,可以通过反斜杠在字符串中转义引号:

local moniker = 'Gavin \'Wiki\' Kistner'; --> Gavin 'Wiki' Kistner
local moniker = "Gavin 'Wiki' Kistner";   --> Gavin 'Wiki' Kistner
local moniker = 'Gavin "Wiki" Kistner';   --> Gavin "Wiki" Kistner
local moniker = "Gavin \"Wiki\" Kistner"; --> Gavin "Wiki" Kistner

头等函数

在 JS 和 Lua 中,函数是头等对象。这意味着可以将函数赋值给变量,作为参数传递,以及通过 () 进行调用:

mytable = { }
mytable.squareit = function( x )
  return x * x
end

thefunc = mytable.squareit
print( thefunc( 7 ) ) --> 49

函数是闭包

在 JS 和 Lua 中,函数对象是闭包(closure)。简单来说,这意味着函数可以访问其声明的位置所在的作用域中的局部变量,甚至在该作用域“消失”之后。

function MakeAdder( inBaseValue )
  return function( inValueToAdd )
    return inBaseValue + inValueToAdd
  end
end

add10 = MakeAdder( 10 )
add30 = MakeAdder( 30 )
print( add10( 1 ) )  --> 11
print( add10( 6 ) )  --> 16
print( add30( 3 ) )  --> 33

不同之处

单行和多行注释

在 JS 中,单行注释以 // 开始。

在 Lua 中,注释以 -- 开始。

在 JS 中,多行注释使用 /* ... */ 来包裹内容。第一个出现的 */ 结束注释。

在 Lua 中,多行注释像这样 --[[ ... ]]。在 5.0 中,可以在注释中使用嵌套的 [[ ... ]]。在 5.1 中,多行注释可以有任意多个成对出现的等号(包括0个),如 --[==[ ... ]===]

Lua 多行注释的神奇之处在于,可以通过增加单个字符实现启用或禁用整个多行注释块:

-- This is a single line Lua comment
local jim = "This is not commented"
--[[
local foo = "This code is not active"
local bar = "Neither is this code line"
--]]

local jam = "This line is active"
---[[
local foo = "This code is ALSO active"
local bar = "because of the extra hyphen above"
--]]

使用 end 而非大括号

Lua(类似 Ruby)使用关键字 end 来关闭代码块。例如:

function foo( )
  --my code here
end

if foo( ) then
  --my code here
end

for i=0,1000 do
  --my code here
end

null 是 nil

在 Lua 中,“空”值以关键字 nil 表示,而非 JS 的 null

nil 和 false 是仅有的非真的值

在 JavaScript 中,""0 在条件判断时都等于 false。在 Lua 中,只有 nilfalse 等于 false

任何值都可以是表的索引

在 JavaScript 中,作为对象的索引的值始终是字符串。(在 JS 中,myObj[11] 与myObj["11"] 相同。)在 Lua 中,字符串,数值,甚至表都可以是索引:

a = {}
b = {}
mytable = {}
mytable[1] = "The number one"
mytable["1"] = "The string one"
mytable[a] = "The empty table 'a'"
mytable[b] = "The empty table 'b'"

print( mytable["1"] ) --> The string one
print( mytable[1] )   --> The number one
print( mytable[b] )   --> The empty table 'b'
print( mytable[a] )   --> The empty table 'a'

没有数组

在 JS 中,有明确的数组类型。它是一个基本的对象(哈希),在设置像整数的值时会修改 length 属性,同时也定义有特殊的方法:

var myArray = new Array( 10 );
var myOtherArray = [ 1, 2, 3 ];

在 Lua 中,表(table)是对象(object),表是原型(prototype),表是哈希(hash),表是数组(array),表...

Lua 中的“数组”是表,只不过有整数属性,且从 1(不是0!)开始连续编号,直到遇到第一个 nil 值。可以通过表字面量来创建数组,这样不必为每个值标出索引:

people = { "Gavin", "Stephen", "Harold" }
-- the above is the exact same as:
people = { [1]="Gavin", [2]="Stephen", [3]="Harold" }

table 有两个方法直接操作作为数组使用的表的“长度”,从而可以初始化一个元素为 nil 的“数组”:

people = { "Gavin", "Stephen", "Harold" }
print( table.getn( people ) )              --> 3

people[ 10 ] = "Some Dude"
print( table.getn( people ) )              --> 3
print( people[ 10 ] )                      --> "Some Dude"
for i=1,table.getn( people ) do
  print( people[ i ] )
end
--> Gavin
--> Stephen
--> Harold

table.setn( people, 10 )
print( table.getn( people ) )              --> 10

for i=1,table.getn( people ) do
  print( people[ i ] )
end
--> Gavin
--> Stephen
--> Harold
--> nil
--> nil
--> nil
--> nil
--> nil
--> Some Dude

数值、字符串和表是非 OOP 对象

在 Lua 中,过程式编程是王道。没有 myString.length 属性,也没有 myString.toLowerCase() 方法。只能使用库函数:

mystring = "Hello World"
print( string.len( mystring ) )    --> 11
print( string.lower( mystring ) )  --> hello world

这在 5.1 有所变更

没有 ++,没有 --

对不起,Lua 中没有简写的方法,只能用啰嗦的写法。

local themessage = "Hello"
themessage = themessage .. " World"

local thecounter = 1
thecounter = thecounter + 1

没有三元运算符

方便的 a ? b : c 语法在 Lua 中没有提供。不过,使用 andor 能够(大多数情况下)满足需要:

local foo = ( math.random( ) > 0.5 ) and "It's big!" or "It's small!"

local numusers = 1
print( numusers .. " user" .. ( numusers == 1 and " is" or "s are" ) .. " online." )
--> 1 user is online.

numusers = 10
print( numusers .. " user" .. ( numusers == 1 and " is" or "s are" ) .. " online." )
--> 10 users are online.

注意,这并不能直接替代三元表达式的使用情况。JavaScript 代码 m = x ? y : z始终xtrue(或为“真”)时将 y 赋值给 m

而 Lua 代码 m = x and y or z 会在 xtrue并且 y 也不是 falsenil 时将 y 赋值给 m

local x=true, y=false, z="oops"
if x then
  print( y )
else
  print( z )
end
--> false

print( x and y or z )
--> "oops"

尽管你可能很少注意到,上面的例子在 JavaScript 中也可以通过 &&|| 实现。而且在 JS 中甚至更危险,因为有更多的“非真”的值,例如空字符串 ""

// 下面的 JavaScript 代码无法正常工作,它会始终输出一个 's'。
var cats = 1;
console.log( "I have " + cats + " cat" + (cats==1 && "" || "s") + "." );
"I have 1 cats."

其他方面

我(译注:作者)太懒了,不想再写更多内容,就列下其他的东西吧:

虽然我也是刚接触 Lua,但是对于这篇文章中讨论的一些内容也有些自己的看法和补充,回头也整理下吧。