자바스크립트(Vanilla JS) vs 루아(Lua) 비교

한올·2026년 6월 18일
post-thumbnail

웹과 프론트엔드의 절대 강자 자바스크립트(JavaScript)와, 게임 엔진 및 임베디드 스크립트의 감초 루아(Lua)는 닮은 듯하면서도 완전히 다른 매력을 가진 멀티 패러다임 언어입니다.

두 언어의 철학, 문법, 데이터 구조, 비동기 메커니즘까지 벨로그 독자분들을 위해 모든 차이점을 세부적인 코드 예시와 함께 파헤쳐 봅니다.


1. 핵심 설계 철학 및 용도

비교 항목자바스크립트 (JavaScript)루아 (Lua)
탄생 목적웹 브라우저 내 동적 제어 및 상호작용C/C++ 프로그램에 쉽게 내장(Embedded)할 수 있는 가벼운 스크립트 엔진
주요 사용처웹 프론트엔드/백엔드(Node.js), 앱 개발(RN)게임 개발(로블록스, 월드오브워크래프트), 임베디드, IoT
엔진 크기V8 엔진 기준 수십 MB 이상 (무겁고 복잡함)순수 C 언어로 작성되어 수백 KB 수준 (극도로 가볍고 빠름)

2. 기본 문법 및 스타일 차이

두 언어는 코드 표기법(Syntax) 스타일에서 확연한 차이를 보입니다. 자바스크립트는 C-Style(중괄호)을, 루아는 Ada/Pascal-Style(텍스트 키워드)을 따릅니다.

2.1. 코드 블록 및 주석 스타일

  • JavaScript: 중괄호 {}로 블록을 구분하며, 주석은 // 또는 /* */를 사용합니다. 문장 끝에 세미콜론 ;을 붙이는 것이 관례입니다.
  • Lua: then, do로 블록을 시작하고 end로 블록을 닫습니다. 주석은 -- 또는 --[[ --]]를 사용합니다. 세미콜론 ;은 완전히 선택 사항이며 거의 쓰지 않습니다.
// [JavaScript] 조건문 예시
if (score >= 90) {
    console.log("A 학점");
} else {
    console.log("B 학점");
}
-- [Lua] 조건문 예시
if score >= 90 then
    print("A 학점")
else
    print("B 학점")
end

2.2. 변수 선언과 기본 스코프 (가장 주의할 점!)

  • JavaScript: 키워드 없이 변수를 선언하면 에러가 나거나 strict 모드가 아닐 때 전역 변수가 됩니다. 주로 let, const를 사용해 깔끔한 블록 스코프를 만듭니다.
  • Lua: 기본적으로 키워드 없이 변수를 선언하면 무조건 전역 변수(Global)가 됩니다. 지역 블록 스코프를 제한하려면 변수 앞에 local 키워드를 반드시 명시해야 합니다.
// [JavaScript] 변수 스코프
function test() {
    let localVar = "이것은 지역 변수";
    const constantVar = "이것은 상수";
}
-- [Lua] 변수 스코프
function test()
    local localVar = "이것은 지역 변수"
    globalVar = "키워드가 없으므로 전역 변수가 됨 (주의!)"
end

3. 자료형 및 데이터 구조

3.1. 인덱스 시작 번호 (0 vs 1)

개발자들 사이에서 가장 유명한 차이점입니다.

  • JavaScript: 배열의 첫 번째 요소 인덱스는 0부터 시작합니다.
  • Lua: 모든 리스트와 테이블의 인덱스는 기본적으로 1부터 시작합니다.
// [JavaScript] 인덱싱
const arr = ["사과", "바나나"];
console.log(arr[0]); // 출력: 사과
-- [Lua] 인덱싱
local arr = {"사과", "바나나"}
print(arr[1])        -- 출력: 사과 (1부터 시작!)

3.2. 만능 데이터 구조: Object vs Table

  • JavaScript: 데이터를 표현할 때 배열 []과 객체 {}를 명확히 구분합니다.
  • Lua: 오직 테이블(Table) {}이라는 단 하나의 데이터 구조만 존재합니다. 테이블을 순서대로 쓰면 배열이 되고, 키-값 쌍으로 쓰면 딕셔너리/객체가 됩니다.
// [JavaScript] 배열과 객체 분리
let userArray = ["Minjo", 25];
let userObject = { name: "Minjo", age: 25 };
-- [Lua] 모든 것은 테이블로 해결
local userArray = {"Minjo", 25}                    -- 리스트 스타일 테이블
local userObject = { name = "Minjo", age = 25 }    -- 딕셔너리 스타일 테이블

3.3. 존재하지 않는 값 (null/undefined vs nil)

  • JavaScript: 값이 비어있음을 뜻하는 null과 정의되지 않음을 뜻하는 undefined가 분리되어 있습니다.
  • Lua: 오직 nil 하나만 존재합니다. 테이블에서 특정 키에 nil을 대입하면 해당 데이터가 완전히 삭제되는 독특한 특성이 있습니다.
// [JavaScript] 데이터 빈 값 처리
let data = null;
let profile = { name: "Minjo" };
profile.name = null; // 값은 여전히 key로 남아있음
-- [Lua] nil 대입을 통한 요소 삭제
local profile = { name = "Minjo", age = 25 }
profile.age = nil   -- age 키 자체가 테이블에서 완전히 삭제됨

4. 객체지향 프로그래밍(OOP) 구현 방식

두 언어 모두 클래스 기반 언어(Java, C++ 등)가 아니며, 프로토타입과 메타 구조를 활용해 OOP를 흉내 냅니다.

  • JavaScript (Class Syntax): 프로토타입 기반 체인이지만, ES6 이후 class, constructor, extends 키워드를 도입하여 직관적인 클래스 상속 문법을 제공합니다.
  • Lua (Metatable): 클래스 관련 키워드가 아예 없습니다. 대신 테이블의 동작을 재정의하는 메타테이블(Metatable)과 __index 메타메소드를 활용해 개발자가 직접 상속 구조를 바닥부터 구현해야 합니다.
// [JavaScript] 현대적인 클래스 상속
class Animal {
    constructor(name) { this.name = name; }
    speak() { console.log(this.name + "가 소리를 냅니다."); }
}
class Dog extends Animal {}
-- [Lua] 메타테이블을 활용한 프로토타입 상속 직접 구현
Animal = {}
function Animal:new(name)
    local obj = { name = name }
    setmetatable(obj, { __index = self }) -- 상속 구조 연결
    return obj
end
function Animal:speak() print(self.name .. "가 소리를 냅니다.") end

Dog = Animal:new() -- 상속 효과

5. 비동기 및 동시성 메커니즘

  • JavaScript (이벤트 루프): 싱글 스레드로 동작하지만 웹 브라우저/Node.js 환경의 이벤트 루프(Event Loop)를 기반으로 합니다. Promise, async/await를 통해 비동기 Non-blocking I/O 처리가 핵심 강점입니다.
  • Lua (코루틴): 이벤트 루프가 없습니다. 대신 코루틴(Coroutine, 협력적 멀티태스킹)을 제공합니다. 실행 중인 루틴을 일시 정지(coroutine.yield)시키고, 필요할 때 다시 재개(coroutine.resume)하는 방식으로 스레드 제어권을 개발자가 동기적으로 직접 주고받습니다.
// [JavaScript] Promise 기반 비동기 처리
async function fetchData() {
    let response = await fetch('https://api.example.com');
    let data = await response.json();
    console.log(data);
}
-- [Lua] 코루틴을 이용한 상태 일시 정지 및 재개
local co = coroutine.create(function()
    print("코루틴 시작")
    coroutine.yield() -- 중간에 제어권 반납하고 멈춤
    print("코루틴 재개됨")
end)

coroutine.resume(co) -- "코루틴 시작" 출력 후 대기
coroutine.resume(co) -- "코루틴 재개됨" 출력

6. 한눈에 보는 비교 요약표

특징자바스크립트 (JavaScript)루아 (Lua)
문법 스타일C 스타일 ({}, //, ;)Ada/Pascal 스타일 (end, --)
배열 인덱스0번부터 시작1번부터 시작
기본 변수 스코프let, const (블록 스코프 선언 필요)키워드 없으면 전역(Global), local 선언 필수
대표 데이터 구조Array [], Object {} 분리오직 Table {}로 통합 관리
비어있는 값null 및 undefinednil
동시성 처리이벤트 루프, Promise, async/await코루틴 (Coroutine) 체계
클래스 상속class, extends 문법 내장메타테이블(metatable)로 직접 구현

💡 벨로그 업로드 총평

자바스크립트는 거대한 웹 생태계와 강력한 비동기 처리를 위해 엔진 자체가 거대해지고 고도화된 언어라면, 루아는 메인 프로그램(C/C++)을 보조하기 위해 불필요한 기능을 전부 덜어내고 극도의 가벼움과 커스텀 가능성을 추구한 언어입니다.

자바스크립트에 익숙한 프론트엔드 개발자가 루아(예: 로블록스 개발 등)를 접할 때는 1번 인덱스 시작과 local 키워드 생략 시 전역 변수가 되는 점만 주의하면 빠르게 적응하실 수 있습니다!

profile
노션이 터져서 임시로 사용하는 오픈 세컨 브레인

0개의 댓글