从 JS 学习 Lua
对 JavaScript 已经了解,想学习下 Lua?下面我们来快速列举下两者的相似和不同之处。更多资料见“学习 Lua”。
相似之处
区分大小写
Lua 和 JS 都区分大小写。true
和 false
是布尔型字面量值,和 True
、TRUE
完全不同。
函数可以有可变数目的参数
在 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 中,只有 nil
和 false
等于 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 中没有提供。不过,使用 and
和 or
能够(大多数情况下)满足需要:
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
会始终在 x
为 true
(或为“真”)时将 y
赋值给 m
。
而 Lua 代码 m = x and y or z
会在 x
为 true
并且 y
也不是 false
或 nil
时将 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."
其他方面
我(译注:作者)太懒了,不想再写更多内容,就列下其他的东西吧:
- Numeric for loops cache boundary conditions
- Limited regular expressions
- Undeclared Variables return nil, not an Error
- Iterators and the Generic for Loop
- No brackets needed for conditionals
- Tables, Metatables
- Multiple Assignment, Multiple Return Values
- String concatentation uses .., not +
虽然我也是刚接触 Lua,但是对于这篇文章中讨论的一些内容也有些自己的看法和补充,回头也整理下吧。