subtle differences between JavaScript and Lua
To be honest it would be easier to list the things which are common to Javascript and Lua than to list the differences. They are both dynamically-typed scripting languages, but that's about as far as you can go really. They have totally different syntax, different original design goals, different modes of operation (Lua is always compiled to bytecode and run on the Lua VM, Javascript varies), the list goes on and on.
Some more differences:
- Lua has native support for coroutines.
- UPDATE: JS now contains the yield keyword inside generators, giving it support for coroutines.
- Lua doesn't convert between types for any comparison operators. In JS, only
===
and!==
don't type juggle. - Lua has an exponentiation operator (
^
); JS doesn't. JS uses different operators, including the ternary conditional operator (?:
vsand/or
), and, as of 5.3, bitwise operators (&
,|
, etc. vs. metamethods ).- UPDATE: JS now has the exponentiation operator
**
.
- UPDATE: JS now has the exponentiation operator
- JS has increment/decrement, type operators (
typeof
andinstanceof
), additional assignment operators and additional comparison operators. - In JS, the
==
,===
,!=
and!==
operators are of lower precedence than>
,>=
,<
,<=
. In Lua, all comparison operators are the same precedence. - Lua supports tail calls.
- UPDATE: JS now supports tail calls.
- Lua supports assignment to a list of variables. While it isn't yet standard in Javascript, Mozilla's JS engine (and Opera's, to an extent) has supported a similar feature since JS 1.7 (available as part of Firefox 2) under the name "destructuring assignment". Destructuring in JS is more general, as it can be used in contexts other than assignment, such as function definitions & calls and loop initializers. Destructuring assignment has been a proposed addition to ECMAScript (the language standard behind Javascript) for awhile.
- UPDATE: Destructuring (and destructuring assignment) is now part of the spec for ECMAScript - already implemented in many engines.
- In Lua, you can overload operators.
- In Lua, you can manipulate environments with
getfenv
andsetfenv
in Lua 5.1 or_ENV
in Lua 5.2 and 5.3. - In JS, all functions are variadic. In Lua, functions must be explicitly declared as variadic.
Foreach
in JS loops over object properties. Foreach in Lua (which use the keywordfor
) loops over iterators and is more general.- UPDATE: JS has Iterables now too, many of which are built into the regular data structures you'd expect, such as
Array
. These can be looped over with thefor...of
syntax. For regular Objects, one can implement their own iterator functions. This brings it much closer to Lua.
- UPDATE: JS has Iterables now too, many of which are built into the regular data structures you'd expect, such as
JS has global and function scope. Lua has global and block scope. Control structures (e.g.
if
,for
,while
) introduce new blocks.Due to differences in scoping rules, a closure's referencing of an outer variable (called "upvalues" in Lua parlance) may be handled differently in Lua and in Javascript. This is most commonly experienced with closures in
for
loops, and catches some people by surprise. In Javascript, the body of afor
loop doesn't introduce a new scope, so any functions declared in the loop body all reference the same outer variables. In Lua, each iteration of thefor
loop creates new local variables for each loop variable.local i='foo' for i=1,10 do -- "i" here is not the local "i" declared above ... end print(i) -- prints 'foo'
The above code is equivalent to:
local i='foo' do local _i=1 while _i<10 do local i=_i ... _i=_i+1 end end print(i)
As a consequence, functions defined in separate iterations have different upvalues for each referenced loop variable. See also Nicolas Bola's answers to Implementation of closures in Lua? and "What are the correct semantics of a closure over a loop variable?", and "The Semantics of the Generic for".
UPDATE: JS has block scope now. Variables defined with
let
orconst
respect block scope.
- Integer literals in JS can be in octal.
- JS has explicit Unicode support, and internally strings are encoded in UTF-16 (so they are sequences of pairs of bytes). Various built-in JavaScript functions use Unicode data, such as
"pâté".toUpperCase()
("PÂTÉ"
). Lua 5.3 and up have Unicode code point escape sequences in string literals (with the same syntax as JavaScript code point escape sequences) as well as the built-inutf8
library, which provides basic support for the UTF-8 encoding (such as encoding code points into UTF-8 and decoding UTF-8 into code points, getting the number of code points in a string, and iterating over code points). Strings in Lua are sequences of individual bytes and can contain text in any encoding or arbitrary binary data. Lua does not have any built-in functions that use Unicode data; the behavior ofstring.upper
depends on the C locale. - In Lua, the
not
,or
,and
keywords are used in place of JS's!
,||
,&&
. - Lua uses
~=
for "not equal", whereas JS uses!==
. For example,if foo ~= 20 then ... end
. - Lua 5.3 and up use
~
for binary bitwise XOR, whereas JS uses^
. - In Lua, any type of value (except
nil
andNaN
) can be used to index a table. In JavaScript, all non-string types (except Symbol) are converted to strings before being used to index an object. For example, after evaluation of the following code, the value ofobj[1]
will be"string one"
in JavaScript, but"number one"
in Lua:obj = {}; obj[1] = "number one"; obj["1"] = "string one";
. - In JS, assignments are treated as expressions, but in Lua they are not. Thus, JS allows assignments in conditions of
if
,while
, anddo while
statements, but Lua does not inif
,while
, andrepeat until
statements. For example,if (x = 'a') {}
is valid JS, butif x = 'a' do end
is invalid Lua. - Lua has syntactic sugar for declaring block-scoped function variables, functions that are fields, and methods (
local function() end
,function t.fieldname() end
,function t:methodname() end
). JS declares these with an equals sign (let funcname = function optionalFuncname() {}
,objectname.fieldname = function () {}
).
A couple of subtle differences that will catch you out at least once:
- Not equal is spelled
~=
in Lua. In JS it is!=
- Lua arrays are 1-based - their first index is 1 rather than 0.
- Lua requires a colon rather than a period to call object methods. You write
a:foo()
instead ofa.foo()
†
† you can use a period if you want, but have to pass the self
variable explicitly. a.foo(a)
looks a bit cumbersome. See Programming in Lua for details.