🔸 표준 내장 객체 (Standard Built-in Objects)
대표적인 예로 String, Number, Math, Date, Array, JSON 등이 있다. 별도 import 없이 바로 사용 가능하다는 점이 특징.
console.log(Math.max(1, 5, 10)); // 10 console.log(JSON.stringify({ name: "현지" })); // '{"name":"현지"}'
🔸 Symbol
유일한 식별자가 필요할 때 사용하는 원시 타입
Symbol()로 생성된 값은 절대 중복되지 않음. 객체의 프로퍼티 키로도 활용 가능해서 은닉으로 쓰이기도 한다.
const id = Symbol("id"); const user = { name: "Jiwoo", [id]: 123 }; console.log(user[id]); // 123
🔸 이터러블(Iterable)과 제너레이터(Generator)
이터러블은 반복 가능한 객체이고, 제너레이터는 이터러블을 만드는 함수다
- for...of 문에서 사용 가능
- Symbol.iterator를 구현한 객체는 모두 이터러블
function* gen() { yield 1; yield 2; yield 3; } const g = gen(); console.log(g.next()); // { value: 1, done: false }
🔸옵셔널 체이닝 (Optional Chaining)
중첩된 객체에서 중간에 값이 undefined라도 에러 없이 안전하게 접근
const user = { profile: null }; console.log(user.profile?.name); // undefined
예전엔 if문으로 하나하나 확인했지만, 이제는 ?. 한 줄로 끝남.
🔸 렉시컬 환경과 클로저
렉시컬 스코프는 “코드가 작성된 위치”를 기준으로 변수 범위를 결정
클로저는 함수가 “자신이 선언된 환경”을 기억하는 개념
function outer() { let count = 0; return function inner() { count++; return count; }; } const fn = outer(); console.log(fn()); // 1 console.log(fn()); // 2
inner() 함수는 외부 함수인 outer()의 변수 count에 접근 가능 → 이게 클로저.
🔸 this
this는 실행되는 “컨텍스트(문맥)”에 따라 달라짐
- 일반 함수 호출: this는 전역(window or undefined)
- 객체 메서드: 해당 객체
- 화살표 함수: 상위 스코프의 this를 그대로 사용
const obj = { name: "현지", say() { console.log(this.name); }, }; obj.say(); // 현지
🔸 프로토타입과 상속
모든 객체는 자신의 부모 역할을 하는 프로토타입 객체를 참조한다
프로토타입 체인을 통해 상위 객체의 속성과 메서드를 상속받는 구조를 가진다.
function Person(name) { this.name = name; } Person.prototype.sayHi = function() { console.log(`Hi, I'm ${this.name}`); }; const me = new Person("현지"); me.sayHi(); // Hi, I'm 현지
🔸 비동기 프로그래밍 (Async Programming)
자바스크립트는 싱글 스레드지만 비동기 처리를 통해 대기 없이 작업을 처리한다
콜백 → 프로미스 → async/await으로 발전해왔다.
async function fetchData() { const res = await fetch("https://api.example.com/data"); const data = await res.json(); console.log(data); }
await 키워드는 프로미스가 처리될 때까지 기다리며, 코드를 동기처럼 보이게 만들지만 실제론 비동기적으로 처리된다.
[렉시컬 스코프와 클로저]
클로저를 이해하려면 렉시컬 스코프를 먼저 이해해야 한다고 나와있다.
따라서 렉시컬 스코프가 무엇인지 알아보겠다.
스코프란?
스코프란 참조 대상 식별자(변수, 함수의 이름과 같이 어떤 대상을 다른 대상과 구분하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다.
var global = 'global';
function foo() {
// var 키워드로 선언한 변수는 "함수 레벨 스코프"를 가진다.
var local = 'local';
console.log(global);
}
foo();
console.log(local);
// 결과
// global
// Uncaught ReferenceError: local is not defined
위 예제에서 global 이름을 가진 변수는 전역 스코프를 가지기 때문에 foo 함수 내에서도 참조할 수 있지만, local 이름을 가진 변수는 함수 레벨 스코프를 가지므로 foo 함수 외부에서 참조하려고 한다면 참조에러가 발생한다. 즉, 이와 같은 개념을 스코프라 한다.
렉시컬 스코프(Lexical Scope)란?
렉시컬 스코프는 함수를 어디에 선언하였는지에 따라 상위 스코프가 결정되는 것을 말한다.
자바스크립트를 포함한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따르며, 이를 정적 스코프(Static Scope)라고 부르기도 한다.
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
위와 같은 상황에서 bar 함수에서 참조하는 x 변수는 bar 함수의 상위 스코프가 무엇인지에 따라 결정된다.
따라서, 상위 스코프가 무엇인지 알려면 bar 함수가 어디에 선언되었는지 봐야되는데, 위 코드에서는 bar 함수가 전역에 선언되었으므로 상위 스코프는 전역 스코프가 된다.
그래서 bar 함수 내의 x 변수는 전역에 선언된 x 변수를 참조하게 된다.
- 동적 스코프
- 렉시컬 스코프와 다르게 함수를 어디서 호출하였는지에 따라 상위 스코프가 결정되는 것을 동적 스코프라고 한다.
Bash Scripting, Common Lisp 등 일부 언어에서 동적 스코프를 따른다.
클로저(Closure)
클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(렉시컬 스코프)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다.
즉, 자신이 생성될 때의 환경(렉시컬 스코프)을 기억하는 함수다.
const outerFunc = () => {
let x = 10; // '자유 변수' 라고 한다.
// 클로저
const innerFunc = (y) => {
x = x + y;
console.log(x);
}
return innerFunc;
}
const addFunc = outerFunc();
addFunc(5); // 15
addFunc(10); // 25
위 코드에서 innerFunc의 x는 렉시컬 스코프에 의해 outerFunc의 지역변수 x를 참조하고 있다.
그리고 outerFunc는 const addFunc = outerFunc(); 구문에서 호출된 후 콜스택에서 제거된다.
따라서, 이후에 addFunc를 호출 할 때 innerFunc의 x를 참조할 수 없어 보이는데, 외부함수 실행 컨텍스트 내의 *활성 객체가 내부함수에 의해 참조되는 한 유효하기 때문에 그렇지 않다.
즉, 내부함수가 유효한 상태에서 외부함수가 종료되어도, 외부함수의 x 변수를 참조할 수 있다. 여기서 내부함수를 클로저라고 한다.
- 활성 객체란? 실행 컨텍스트가 생성될 때 자바스크립트 엔진이 해당 컨텍스트에서 실행에 필요한 여러가지 정보(변수, 함수 선언 등의 정보를 담을 객체를 생성하는데, 이를 활성 객체라고 한다.
[JavaScript에서의 캡슐화와 정보 은닉]
프로그래밍에서 캡슐화와 정보 은닉은 객체지향 설계 원칙의 핵심 요소로 복잡성을 줄이고 유지보수성을 향상시키기 위한 중요한 개념이라고 한다.
저바스크립트는 전통적인 클래스 기반 언어와는 다르게 프로토타입 기반의 객체지향 언어였지만, ES6 이후 클래스 문법이 도입되면서 이 두 개념을 보다 명확히 표현할 수 있게 되었다고 한다. 따라서 JavaScript에서 캡슐화와 정보 은닉을 어떻게 구현하는지,
그리고 각각의 개념이 어떤 차이를 가지는지 구체적으로 공부해 보도록 하겠다.
🧩 캡슐화란?
- 캡슐화는 데이터와 그 데이터를 다루는 동작을 하나의 단위로 묶는 것이다.
목적
- 객체 외부에서 직접 데이터를 조작하는 것을 막고,
- 메서드를 통해서만 접근하거나 수정하도록 제한함으로써
- 데이터 일관성, 무결성, 책임 분리를 달성할 수 있다.
JavaScript에서의 캡슐화 구현 방법
캡슐화는 크게 클래스와 클로저를 통해 구현할 수 있다.
- 클래스 기반 캡슐화
class BankAccount {
#balance = 0; // private field
constructor(owner) {
this.owner = owner;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
}
}
getBalance() {
return this.#balance;
}
}
const account = new BankAccount("현지");
account.deposit(1000);
console.log(account.getBalance()); // 1000
console.log(account.#balance); //SyntaxError: Private field
- 클로저 기반 캡슐화
function createCounter() {
let count = 0; // 클로저로 은닉된 변수
return {
increment() {
count++;
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
console.log(counter.count); // undefined
🧩정보 은닉이란?
- 정보 은닉은 객체의 불필요하거나 민감한 내부 정보를 외부로부터 숨기는 것을 의미한다.
목적
- 사용자(또는 다른 객체)가 내부 구현에 의존하지 않도록 하여,
- 모듈 간 결합도를 낮추고 유연한 변경을 가능하게 만든다.
즉, 캡슐화는 구조적 개념, 정보 은닉은 그 구조 내에서 어떤 정보를 감출 것인지를 의미한다.
🧩 캡슐화 vs 정보 은닉 차이 정리
| 항목 | 캡슐화 | 정보 은닉 |
| 핵심 개념 | 데이터와 메소드를 객체 단위로 묶는 것 | 외부에 노출할 필요가 없는 내부 정보 숨기기 |
| 구현 방식 | 클래스,클로저,모듈 시스템 | private 필드,클로저,접근 제한 메소드 |
| 목적 | 객체를 하나의 독립적 단위로 만들기 | 구현 세부사항을 숨겨 유연한 수정 가능하게 |
| 관계 | 구조적 개념 | 설계 전략 |
🧩캡슐화와 정보 은닉이 중요한 이유
- 버그 예방 : 외부에서 상태를 임의로 변경할 수 없으므로 안정성 증가
- 유지보수 용이성: 내부 구현이 변경되더라도 인터페이스가 동일하면 외부에는 영향이 없다.
- 보안성 향상: 외부에 공개할 필요 없는 데이터를 안전하게 보호
좋은 설계는 데이터 구조보다 접근 방식이 더 중요하다는 것을 기억하며, 캡슐화와 정보 은닉을 적극 활용한다면 유지보수가 쉬운 코드와 유연한 시스템을 구축할 수 있다는 것을 배웠다.
본 후기는 [카카오엔터프라이즈x스나이퍼팩토리] 카카오클라우드로 배우는 AIaaS 마스터 클래스 (B-log) 리뷰로 작성 되었습니다.
'카카오클라우드 AIaaS 교육 > 클라우드 어플리케이션 개발' 카테고리의 다른 글
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 35 - react (0) | 2025.05.19 |
|---|---|
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY 34 - react (0) | 2025.05.19 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 8주차 DAY33 - react (0) | 2025.05.13 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 7주차 DAY31 - js 심화 (0) | 2025.05.09 |
| [스나이퍼팩토리] AIaaS 마스터 클래스 6주차 DAY2 - html (2) | 2025.04.30 |