Understanding Scope in JavaScript2 - Lee-hyuna/33-js-concepts-kr GitHub Wiki

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•œ ์ดํ•ด

์›๋ฌธ : https://scotch.io/tutorials/understanding-scope-in-javascript

์†Œ๊ฐœ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” Scope๋ผ๊ณ  ํ•˜๋Š” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž๋“ค์ด ์Šค์ฝ”ํ”„์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์‰ฝ๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์žˆ์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์Šค์ฝ”ํ”„์— ๋Œ€ํ•ด ์‹ฌํ”Œํ•˜๊ฒŒ ์„ค๋ช…์„ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. scope๋ฅผ ์ดํ•ดํ•˜๋ฉด ์˜ค๋ฅ˜๋ฅผ ์ค„์ด๊ณ  ๊ฐ•๋ ฅํ•œ ๋””์ž์ธ ํŒจํ„ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Scope๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€?

Scope๋Š” ์ฝ”๋“œ๊ฐ€ ๋Ÿฐํƒ€์ž„ ์ค‘์— ์ฝ”๋“œ์˜ ํŠน์ • ๋ถ€๋ถ„์— ์žˆ๋Š” ๋ณ€์ˆ˜, ํ•จ์ˆ˜, ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ฑ์ž…๋‹ˆ๋‹ค. ์ฆ‰, scope๋Š” ์ฝ”๋“œ ์˜์—ญ์—์„œ ๋ณ€์ˆ˜ ๋ฐ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค์˜ ์œ ํšจ๋ฒ”์œ„(=>visibility:๊ฐ€์‹œ์„ฑ์„ ์œ ํšจ๋ฒ”์œ„๋กœ ๋ฒˆ์—ญ)์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

์™œ Scope? ์ตœ์†Œ ์ ‘๊ทผ์˜ ์›๋ฆฌ(The Principle of Least Access)

๊ทธ๋ž˜์„œ, ๋ณ€์ˆ˜์˜ ์œ ํšจ๋ฒ”์œ„๋ฅผ ์ œํ•œํ•˜๊ณ  ์ฝ”๋“œ์˜ ์–ด๋Š ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ชจ๋“  ๊ฒƒ์„ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด ๋ฌด์Šจ ์˜๋ฏธ์ผ๊นŒ์š”? ํ•œ๊ฐ€์ง€ ์žฅ์ ์€ scope๊ฐ€ ์ฝ”๋“œ์— ์ผ์ • ์ˆ˜์ค€์˜ ๋ณด์•ˆ์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ปดํ“จํ„ฐ ๋ณด์•ˆ์˜ ํ•œ๊ฐ€์ง€ ๊ณตํ†ต๋œ ์›์น™์€ ์‚ฌ์šฉ์ž๊ฐ€ ํ•œ ๋ฒˆ์— ํ•„์š”ํ•œ ๋Œ€์ƒ(stuff:๋ฌผ๊ทผ์„ ๋Œ€์ƒ์œผ๋กœ ๋ณ€๊ฒฝ)์—๋งŒ ์ ‘๊ทผ์„ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ปดํ“จํ„ฐ ๊ด€๋ฆฌ์ž๋“ค์„ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. ์ปดํ“จํ„ฐ ๊ด€๋ฆฌ์ž๋“ค์€ ์ˆ˜ ๋งŽ์€ ์ปดํ“จํ„ฐ ์‹œ์Šคํ…œ์„ ์ œ์–ดํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋“ค์—๊ฒŒ ์™„์ „ํ•˜๊ฒŒ ์•ก์„ธ์Šค ์‚ฌ์šฉ์ž ๊ณ„์ •์„ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž๊ฐ€ ์„ธ๋ช…์ธ ํšŒ์‚ฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‹œ์Šคํ…œ์— ์™„์ „ํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ์ˆœ์กฐ๋กญ๊ฒŒ ์ž‘๋™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ‘์ž๊ธฐ ์‹œ์Šคํ…œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์•…์„ฑ ๋ฐ”์ด๋Ÿฌ์Šค์— ๊ฐ์—ผ๋˜๋Š” ๋‚˜์œ ์ผ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๊ทธ๊ฒŒ ๋ˆ„๊ตฌ ์‹ค์ˆ˜ ์˜€๋Š”์ง€ ๋ชจ๋ฅด์‹œ๋‚˜์š”? ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ๊ณ„์ •์„ ์ž…๋ ฅํ•ด์•ผํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์ „์ฒด ์•ก์„ธ์Šค ๊ถŒํ•œ๋งŒ ๋ถ€์—ฌ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ณ€ํ™”๋ฅผ ์ถ”์ ํ•˜๊ณ  ๋ˆ„๊ฐ€ ๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์„ค๋ช…์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒƒ์ด "์ตœ์†Œ ์ ‘๊ทผ์˜ ์›๋ฆฌ"๋ผ๊ณ  ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค. ์ง๊ด€์ ์œผ๋กœ ๋ณด์ด์‹œ๋‚˜์š”? ์ด ์›๋ฆฌ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ๋””์ž์ธ์—๋„ ์ ์šฉ์ด ์ฃ•๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ๋””์ž์ธ์€ ๋‹ค์Œ์— ํ•™์Šตํ•  Javascript์„ ํฌํ•จํ•œ ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ scope๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ณ„์†ํ•  ๋•Œ ์ฝ”๋“œ์˜ scope์„ ์ง€์ •ํ•˜๋ฉด ํšจ์œจ์„ฑ์„ ๋†’์ด๊ณ , ๋ฒ„๊ทธ๋ฅผ ์ถ”์ ํ•˜๋Š” ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊นจ๋‹ซ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. scope๋Š” ๋˜ํ•œ ์ด๋ฆ„์ด ๊ฐ™์ง€๋งŒ scope๊ฐ€ ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ๋„ค์ด๋ฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. scope์™€ context๋ฅผ ํ˜ผ๋ˆํ•˜์ง€๋งˆ์„ธ์š”. scope์™€ context ๋‘˜๋‹ค ๋‹ค๋ฅธ ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ scope

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋‘๊ฐ€์ง€ ํƒ€์ž…์˜ scope๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  • Global Scope
  • Local Scope

ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜๋Š”๋Š” local scope์ด๊ณ  ํ•จ์ˆ˜ ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜๋Š” global scope์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ๊ฐ ํ•จ์ˆ˜๋Š” ์ƒˆ scope์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Global Scope

document์— javascript์„ ์“ฐ๊ธฐ ์‹œ์ž‘ํ•  ๋•Œ, ์ด๋ฏธ ์ „์—ญ ๋ฒ”์œ„์— ์žˆ์Šต๋‹ˆ๋‹ค. Javascript document์—๋Š” ํ•˜๋‚˜์˜ global scope๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๊ฐ€ ํ•จ์ˆ˜ ์™ธ๋ถ€์—์„œ ์ •์˜๋œ ๊ฒฝ์šฐ Global Scope์— ์žˆ์Šต๋‹ˆ๋‹ค.

// the scope is by default global
var name = 'Hammad';

Global scope ๋‚ด์˜ ๋ณ€์ˆ˜๋Š” ๋‹ค๋ฅธ scope์—์„œ ์ ‘๊ทผํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var name = 'Hammad';

console.log(name); // logs 'Hammad'

function logName() {
    console.log(name); // 'name' is accessible here and everywhere else
}

logName(); // logs 'Hammad'

Local Scope

ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ •์˜๋œ ๋ณ€์ˆ˜๊ฐ€ local scope์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋ณ€์ˆ˜๋“ค์€ ๋ชจ๋“  ํ˜ธ์ถœ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ scope์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋ฅผ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒƒ์€ ๋ณ€์ˆ˜๊ฐ€ ๊ฐ ํ•จ์ˆ˜์— ๋ฐ”์ธ๋”ฉ๋˜๊ณ  ๊ฐ ํ•จ์ˆ˜๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฒ”์œ„์ด๋ฉฐ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

// Global Scope
function someFunction() {
    // Local Scope #1
    function someOtherFunction() {
        // Local Scope #2
    }
}

// Global Scope
function anotherFunction() {
    // Local Scope #3
}
// Global Scope

Block ๋ฌธ

ํ•จ์ˆ˜์™€ ๋‹ฌ๋ฆฌ if, switch ์™€ ๊ฐ™์€ ์กฐ๊ฑด๋ฌธ ๋˜๋Š” for, while์™€ ๊ฐ™์€ ๋ฐ˜๋ณต๋ฌธ์€ ์ƒˆ๋กœ์šด scope์„ ๋งŒ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Block ๋ฌธ ๋‚ด๋ถ€์— ์ •์˜๋œ ๋ณ€์ˆ˜๋Š” ์ด๋ฏธ ํฌํ•จ๋œ scope์— ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

if (true) {
    // this 'if' conditional block doesn't create a new scope
    var name = 'Hammad'; // name is still in the global scope
}

console.log(name); // logs 'Hammad'

ECMAScript 6์—์„œ let ์™€ const ํ‚ค์›Œ๋“œ๊ฐ€ ์†Œ๊ฐœ ๋˜์—ˆ๋‹ค. let ์™€ constํ‚ค์›Œ๋“œ๋Š” var ํ‚ค์›Œ๋“œ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var name = 'Hammad';

let likes = 'Coding';
const skills = 'Javascript and PHP';

var ํ‚ค์›Œ๋“œ์™€๋Š” ๋‹ฌ๋ฆฌ let ์™€ const ํ‚ค์›Œ๋“œ๋Š” Block ๋ฌธ ๋‚ด๋ถ€์˜ ๋กœ์ปฌ ๋ฒ”์œ„ ์„ ์–ธ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

if (true) {
    // this 'if' conditional block doesn't create a scope

    // name is in the global scope because of the 'var' keyword
    var name = 'Hammad';
    // likes is in the local scope because of the 'let' keyword
    let likes = 'Coding';
    // skills is in the local scope because of the 'const' keyword
    const skills = 'JavaScript and PHP';
}

console.log(name); // logs 'Hammad'
console.log(likes); // Uncaught ReferenceError: likes is not defined
console.log(skills); // Uncaught ReferenceError: skills is not defined
Global scope๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ Global scope๋Š” ๊ณ„์† ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. Local Scope๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ์‹คํ–‰์ด ๋˜๋Š” ํ•œ ๊ณ„์† ์œ ์ง€ ๋ฉ๋‹ˆ๋‹ค.

Context

๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ข…์ข… ๋™์ผํ•œ ๊ฐœ๋…์œผ๋กœ ์–ธ๊ธ‰ํ•˜์—ฌ ์ž์ฃผ scope์™€ context์„ ํ˜ผ๋ˆํ•ฉ๋‹ˆ๋‹ค. scope๋Š” ์œ„์—์„œ ๋…ผ์˜ํ•œ ๊ฒƒ์ด๊ณ  context๋Š” ์ฝ”๋“œ์˜ ํŠน์ • ๋ถ€๋ถ„์—์„œ this๊ฐ’์„ ๋งํ•ฉ๋‹ˆ๋‹ค. scope๋Š” ๋ณ€์ˆ˜์˜ ์œ ํšจ๋ฒ”์œ„๋ฅผ ๋งํ•˜๋ฉฐ context๋Š” ๊ฐ™์€ scope์—์„œ this์˜ ๊ฐ’์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ํ•จ์ˆ˜์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ context์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‚˜์ค‘์— ๋…ผ์˜ํ•  ๊ฒƒ ์ž…๋‹ˆ๋‹ค. global scope๋Š” ํ•ญ์ƒ window ๊ฐ์ฒด ์ž…๋‹ˆ๋‹ค.

// logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storageโ€ฆ}
console.log(this);

function logFunction() {
    console.log(this);
}
// logs: Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storageโ€ฆ}
// because logFunction() is not a property of an object
logFunction(); 

scope๊ฐ€ ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ์— ์žˆ์œผ๋ฉด, context๊ฐ€ ๋ฉ”์†Œ๋“œ์˜ ์ผ๋ถ€์ธ ๊ฐ์ฒด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

class User {
    logName() {
        console.log(this);
    }
}

(new User).logName(); // logs User {}
(new User).logName() ๋ณ€์ˆ˜์— ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•œ ๋‹ค์Œ logNameํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์งง์€ ๋ฐฉ๋ฒ• ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ƒˆ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. 

ํ•œ ๊ฐ€์ง€๋Š” ๊ฐ•์กฐ ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์€ newํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, context์˜ ๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ ์ž‘์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ context๊ฐ€ ํ˜ธ์ถœ๋œ ํ•จ์ˆ˜์˜ ์ธ์Šคํ„ด์Šค๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ์œ„ ์˜ ์˜ˆ์ค‘ ํ•˜๋‚˜๊ฐ€ new ํ‚ค์›Œ๋“œ๋กœ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ์ด ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

function logFunction() {
    console.log(this);
}

new logFunction(); // logs logFunction {}
strict mode์—์„œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ์ด ๋˜์—ˆ์„ ๋•Œ context์˜ ๊ธฐ๋ณธ๊ฐ’์€ undefined์ž…๋‹ˆ๋‹ค.

์‹คํ–‰ Context

๋ชจ๋“  ํ˜ผ๋ˆ๊ณผ ํ•™์Šตํ•œ ๊ฒƒ์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์‹คํ–‰ context์˜ context๋ผ๋Š” ๋‹จ์–ด๋Š” context๊ฐ€ ์•„๋‹Œ scope์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ด ๋„ค์ด๋ฐ ๊ทœ์น™์€ ์ด์ƒํ•˜์ง€๋งŒ Javascript์˜ ์ŠคํŽ™์œผ๋กœ ์ธํ•ด ์ด๋ ‡๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. (์ผ๋ถ€ ์˜์—ญ...)

JavaScript๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ ์–ธ์–ด์ด๋ฏ€๋กœ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€ ์ž‘์—…๋“ค์€ ์‹คํ–‰ context์˜ queue์— ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์—์„œ๋„ ๋งํ–ˆ๋“ฏ์ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•ด์„๊ธฐ๊ฐ€ ๋‹น์‹ ์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด, context(scope)์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด, context(scope)์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธ€๋กœ๋ฒŒ๋กœ ์„ค์ •์ด ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ธ€๋กœ๋ฒŒ context๋Š” ์‹คํ–‰ context๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ์ฒซ๋ฒˆ์งธ context์ธ ์‹คํ–‰ context์— ์ถ”๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ด ํ›„ ๊ฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ(invocation)์€ ์‹คํ–‰ context์— context์„ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•จ์ˆ˜๊ฐ€ ๊ทธ ํ•จ์ˆ˜ ๋‚ด๋ถ€ ๋˜๋Š” ๋‹ค๋ฅธ ์–ด๋”˜๊ฐ€์—์„œ ํ˜ธ์ถœ๋  ๋•Œ ๊ฐ™์€ ์ผ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ฐ๊ฐ์˜ ํ•จ์ˆ˜๋Š” ์ž์ฒด์ ์œผ๋กœ ์‹คํ–‰ context์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ด๋‹น context์—์„œ ์ฝ”๋“œ ์‹คํ–‰์ด ์™„๋ฃŒ ๋˜๋ฉด ํ•ด๋‹น context๊ฐ€ ์‹คํ–‰ context์—์„œ ๋ฒ—์–ด๋‚˜๊ณ , ์‹คํ–‰ context์˜ ํ˜„์žฌ context๊ฐ€ ๋ถ€๋ชจ์˜ context๋กœ ์ „์†ก์ด ๋ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ํ•ญ์ƒ ์‹คํ–‰ ์Šคํƒ์˜ ๋งจ ์œ„์— ์ด๋Š” ์‹คํ–‰ context๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. (์‹ค์ œ๋กœ ์ฝ”๋“œ์˜ ๊ฐ€์žฅ ์•ˆ์ชฝ ๋ฒ”์œ„ ์ž…๋‹ˆ๋‹ค.)

ํ•˜๋‚˜์˜ ์ „์—ญ context๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์—ฌ๋Ÿฌ๊ฐ€์ง€์˜ ํ•จ์ˆ˜ context๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ context์—๋Š” ์ƒ์„ฑ ๋ฐ ์ฝ”๋“œ ์‹คํ–‰์˜ ๋‘ ๋‹จ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ ๋‹จ๊ณ„

์ƒ์„ฑ ๋‹จ๊ณ„์ธ ์ฒซ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋˜์ง€๋งŒ ์ฝ”๋“œ๊ฐ€ ์•„์ง ์‹คํ–‰์ด ๋˜์ง€ ์•Š์„ ๋•Œ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ ์ผ์–ด๋‚˜๋Š” ์„ธ๊ฐ€์ง€ ์ฃผ์š”ํ•œ ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Variable (Activation) Object (Variable Object : ๋ณ€์ˆ˜ ๊ฐ์ฒด)์˜ ์ƒ์„ฑ
  • Scope Chain์˜ ์ƒ์„ฑ
  • context์˜ ๊ฐ’(this) ์„ค์ •

๋ณ€์ˆ˜ ๊ฐ์ฒด

ํ™œ์„ฑ ๊ฐ์ฒด๋ผ๊ณ ๋„ ํ•˜๋Š” ๋ณ€์ˆ˜ ๊ฐ์ฒด๋Š” ์‹คํ–‰ context์—์„œ ํŠน์ • branch์— ์ •์˜๋œ ๋ชจ๋“  ๋ณ€์ˆ˜, ํ•จ์ˆ˜ ๋ฐ ๊ธฐํƒ€ ์„ ์–ธ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ํ•ด์„๊ธฐ๋Š” ํ•จ์ˆ˜ ์ธ์ˆ˜, ๋ณ€์ˆ˜ ๋ฐ ๊ธฐํƒ€ ์„ ์–ธ์„ ํฌํ•จํ•œ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋“ค์„ ์Šค์บ”ํ•ฉ๋‹ˆ๋‹ค.

'variableObject': {
    // contains function arguments, inner variable and function declarations
}

Scope Chain

์‹คํ–‰ context์˜ ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ scope chain์€ ๋ณ€์ˆ˜ ๊ฐ์ฒด ๋‹ค์Œ์— ์ž‘์„ฑ ๋ฉ๋‹ˆ๋‹ค. scope chain์—๋Š” ๋ณ€์ˆ˜ ๊ฐ์ฒด๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. scope chain์€ ๋ณ€์ˆ˜๋ฅผ resolveํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๋ฅผ resolveํ•˜๋ผ๋Š” ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด Javascript๋Š” ํ•ญ์ƒ ์ฝ”๋“œ์˜ ๊ฐ€์žฅ ์•ˆ์ชฝ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๋ณ€์ˆ˜ ๋˜๋Š” ๋‹ค๋ฅธ ์ฐพ๊ณ  ์žˆ๋Š” ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋“ค์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๋ถ€๋ชจ ๋ฒ”์œ„๋กœ ๋‹ค์‹œ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. scope chain์€ ๋‹จ์ˆœํžˆ ์ž์ฒด ์‹คํ–‰ context์˜ ๋ณ€์ˆ˜ ๊ฐ์ฒด์™€ ๋ถ€๋ชจ์˜ ๋‹ค๋ฅธ ๋ชจ๋“  ์‹คํ–‰ context๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์Šต๋‹ˆ๋‹ค.

'scopeChain': {
    // contains its own variable object and other variable objects of the parent execution contexts
}

์‹คํ–‰ context ๊ฐ์ฒด

executionContextObject = {
    'scopeChain': {}, // contains its own variableObject and other variableObject of the parent execution contexts
    'variableObject': {}, // contains function arguments, inner variable and function declarations
    'this': valueOfThis
}

์ฝ”๋“œ ์‹คํ–‰ ๋‹จ๊ณ„

์‹คํ–‰ context์˜ ๋‘๋ฒˆ์งธ ๋‹จ๊ณ„์ธ ์ฝ”๋“œ ์‹คํ–‰ ๋‹จ๊ณ„์—์„œ ๋‹ค๋ฅธ ๊ฐ’์ด ํ• ๋‹น๋˜๊ณ  ์ฝ”๋“œ๊ฐ€ ๋งˆ์นจ๋‚ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

lexical Scope

lexical Scope๋Š” ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๊ทธ๋ฃน์—์„œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ๋ถ€๋ชจ ๋ฒ”์œ„์˜ ๋ณ€์ˆ˜ ๋ฐ ๊ธฐํƒ€ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ž์‹ ํ•จ์ˆ˜๊ฐ€ ๋ถ€๋ชจ์˜ ์‹คํ–‰ context์— lexicallyํ•˜๊ฒŒ ๋ฌถ์—ฌ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. Lexical scope๋Š” ๋•Œ๋กœ๋Š” ์ •์  scope๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.

function grandfather() {
    var name = 'Hammad';
    // likes is not accessible here
    function parent() {
        // name is accessible here
        // likes is not accessible here
        function child() {
            // Innermost level of the scope chain
            // name is also accessible here
            var likes = 'Coding';
        }
    }
}

lexical scope์— ๋Œ€ํ•ด ๊ฐ•์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•ž์œผ๋กœ ๋‚˜์•„ ๊ฐ€๋Š” ๊ฒƒ์ธ๋ฐ, ์ด๋Š” ์ž์‹๋“ค์˜ ์‹คํ–‰ context์˜ name์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ถ€๋ชจ์—๊ฒŒ ๋˜๋Œ์•„ ๊ฐˆ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€๋ชจ๊ฐ€ ์›ํ•˜๋Š” ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ๋„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. (์ผ๋ถ€ ์˜์—ญ)

์ด๊ฒƒ์€ ๋˜ํ•œ ๋‹ค๋ฅธ ์‹คํ–‰ context์—์„œ ๋™์ผํ•œ ์ด๋ฆ„์„ ๊ฐ–๋Š” ๋ณ€์ˆ˜๊ฐ€ ์‹คํ–‰ ์Šคํƒ์˜ ์œ„์—์„œ ์•„๋ž˜๋กœ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์–ป๋Š” ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ ค ์ค๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์•ˆ์ชฝ ํ•จ์ˆ˜(์‹คํ–‰ ์Šคํƒ์˜ ์ตœ์ƒ์œ„ context)์—์„œ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์™€ ๋น„์Šทํ•œ ์ด๋ฆ„์„ ๊ฐ–๋Š” ๋ณ€์ˆ˜๋Š” ๋” ๋†’์€ ์šฐ์„  ์ˆœ์œ„๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

ํด๋กœ์ €

ํด๋กœ์ €์˜ ๊ฐœ๋…์€ ์œ„์—์„œ ํ•™์Šตํ•œ lexical Scope์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ํ•จ์ˆ˜๊ฐ€ immediate lexical scope์˜ ์™ธ๋ถ€ ๋ณ€์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๋Š” ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ scope chain์— ์ ‘๊ทผ์„ ์‹œ๋„ํ•˜๋ ค ํ•  ๋•Œ, ํด๋กœ์ €๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ํด๋กœ์ €๋Š” ์ž์‹ ์˜ scope chain ๋ฐ global scope๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํด๋กœ์ €๋Š” ์™ธ๋ถ€ ํ•จ์ˆ˜์— ์ •์˜๋œ ๋ณ€์ˆ˜ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋กœ์ €๋Š” ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋œ ํ›„์—๋„ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ฐ˜ํ™˜๋œ ํ•จ์ˆ˜๊ฐ€ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜์—์„œ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด, ์™ธ๋ถ€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋ฐ˜ํ™˜๋œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋จผ์ € ์™ธ๋ถ€ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๋ณ„๋„์˜ ๋ณ€์ˆ˜์— ์ €์žฅํ•œ ๋‹ค์Œ ๋ณ€์ˆ˜๋ฅผ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

function greet() {
    name = 'Hammad';
    return function () {
        console.log('Hi ' + name);
    }
}

greet(); // nothing happens, no errors

// the returned function from greet() gets saved in greetLetter
greetLetter = greet();

 // calling greetLetter calls the returned function from the greet() function
greetLetter(); // logs 'Hi Hammad'

์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•ด์•ผํ•  ํ•ต์‹ฌ์€ that greetLetter์ด ๋ฐ˜ํ™˜๋œ ํ›„์—๋„ greet์˜ name๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜ ํ• ๋‹น ์—†์ด greet ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ()์„ ()()์ฒ˜๋Ÿผ ๋‘๋ฒˆ ์“ฐ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

function greet() {
    name = 'Hammad';
    return function () {
        console.log('Hi ' + name);
    }
}

greet()(); // logs 'Hi Hammad'

Public ๊ทธ๋ฆฌ๊ณ  Private Scope

๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ public scope, private scope, protected scope์„ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ ๋ฐ ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ์˜ ์œ ํšจ๋ฒ”์œ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. PHP language์˜ ์˜ˆ

// Public Scope
public $property;
public function method() {
  // ...
}

// Private Sccpe
private $property;
private function method() {
  // ...
}

// Protected Scope
protected $property;
protected function method() {
  // ...
}

public(global) scope์—์„œ ํ•จ์ˆ˜๋ฅผ ์บก์Šํ™”ํ•˜๋ฉด ์ทจ์•ฝํ•œ ๊ณต๊ฒฉ์œผ๋กœ ๋ถ€ํ„ฐ ๋ณดํ˜ธ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” public scope, private scope์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ํด๋กœ์ €์˜ ํŠน์ง•์„ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์„ global๊ณผ ๋ถ„๋ฆฌ ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๋จผ์ € ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜ ๋‚ด์—์„œ ์šฐ๋ฆฌ์˜ ๊ธฐ๋Šฅ์„ ์บก์ˆ ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

(function () {
  // private scope
})();

ํ•จ์ˆ˜์˜ ๋ ๋ถ€๋ถ„์— ์žˆ๋Š” ๊ด„ํ˜ธ๋Š” ํ•ด์„๊ธฐ๊ฐ€ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ์ฝ์œผ๋ฉด ์ฆ‰์‹œ ์‹คํ–‰ํ•˜๋„๋ก ์ง€์‹œ๋ฅผ ๋‚ด๋ฆฝ๋‹ˆ๋‹ค. ํ•จ์ˆ˜์™€ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์™ธ๋ถ€์—์„œ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” public ์ผ๋ถ€๋Š” private๋กœ ํ•ด์•ผํ• ๊นŒ์š”? ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ๊ฐ€์ง€ ์œ ํ˜•์˜ ํด๋กœ์ €๋ฅผ ๋ชจ๋“ˆ ํŒจํ„ด์ด๋ผ๊ณ  ํ•˜๋ฉฐ ์ด ํŒจํ„ด์€ ๊ฐ์ฒด์˜ public scope ๊ทธ๋ฆฌ๊ณ  private scope์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜์˜ scope์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ํŒจํ„ด

๋ชจ๋“ˆ ํŒจํ„ด์€ ์ด์™€ ๊ฐ™๋‹ค.

var Module = (function() {
    function privateMethod() {
        // do something
    }

    return {
        publicMethod: function() {
            // can call privateMethod();
        }
    };
})();

๋ชจ๋“ˆ์˜ ๋ฐ˜ํ™˜๋ฌธ์—๋Š” public ํ•จ์ˆ˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. private ํ•จ์ˆ˜๋Š” ๋ฐ˜ํ™˜๋˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ํ•จ์ˆ˜๊ฐ€ ์—†์œผ๋ฉด ๋ชจ๋“ˆ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ์˜ public ํ•จ์ˆ˜๋“ค์€ helper ํ•จ์ˆ˜, ajax ํ˜ธ์ถœ ๋ฐ ๊ธฐํƒ€ ๋“ฑ๋“ฑ ๋“ค์ด private ํ•จ์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š”๋‹ค.

Module.publicMethod(); // works
Module.privateMethod(); // Uncaught ReferenceError: privateMethod is not defined

ํ•˜๋‚˜์˜ ๊ทœ์น™์€ underscore์™€ ํ•จ๊ป˜ private ํ•จ์ˆ˜๋ฅผ ์‹œ์ž‘ํ•˜๊ณ , public ํ•จ์ˆ˜์ด ํฌํ•จ๋œ ์ต๋ช…์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

var Module = (function () {
    function _privateMethod() {
        // do something
    }
    function publicMethod() {
        // do something
    }
    return {
        publicMethod: publicMethod,
    }
})();

์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜ ํ‘œํ˜„ (IIFE)

ํด๋กœ์ €์˜ ๋‹ค๋ฅธ ํƒ€์ž…์ธ ์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜ ํ‘œํ˜„(IIFE)์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ window context์—์„œ ํ˜ธ์ถœ๋˜๋Š” self-invoked anonymous ํ•จ์ˆ˜๋กœ this์˜ ๊ฐ’์ด window์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ•˜๋‚˜์˜ global ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋…ธ์ถœ์‹œ์ผœ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•ฉ๋‹ˆ๋‹ค.

(function(window) {
    // do anything
})(this);

Changing Context - .call(), .apply() and .bind()

Call, Apply ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋™์•ˆ context๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒƒ์€ ๋†€๋ผ์šด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.(๊ทธ๋ฆฌ๊ณ  ์„ธ๊ณ„๋ฅผ ์ง€๋ฐฐํ•˜๋Š” ๊ถ๊ทน์ ์ธ ํž˜..) call ๋˜๋Š” applyํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์Œ์˜ ๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์ฒซ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ context๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋Œ€์‹  ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜์˜ ์ž์ฒด ์ธ์ˆ˜๋Š” context ์ดํ›„์— ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function hello() {
    // do something...
}

hello(); // the way you usually call it
hello.call(context); // here you can pass the context(value of this) as the first argument
hello.apply(context); // here you can pass the context(value of this) as the first argument

.call() ๊ทธ๋ฆฌ๊ณ  .apply()์˜ ์ฐจ์ด์ ์€ call์€ ๋‚˜๋จธ์ง€ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ธ์ˆ˜์˜ ๋ชฉ๋ก์„ ์ „๋‹ฌํ•˜๊ณ , apply๋Š” ๋ฐฐ์—ด๋กœ ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

function introduce(name, interest) {
    console.log('Hi! I\'m '+ name +' and I like '+ interest +'.');
    console.log('The value of this is '+ this +'.')
}

introduce('Hammad', 'Coding'); // the way you usually call it
introduce.call(window, 'Batman', 'to save Gotham'); // pass the arguments one by one after the contextt
introduce.apply('Hi', ['Bruce Wayne', 'businesses']); // pass the arguments in an array after the context

// Output:
// Hi! I'm Hammad and I like Coding.
// The value of this is [object Window].
// Hi! I'm Batman and I like to save Gotham.
// The value of this is [object Window].
// Hi! I'm Bruce Wayne and I like businesses.
// The value of this is Hi.
call์€ apply๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๋น ๋ฆ…๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” ๋ฌธ์„œ์˜ ํ•ญ๋ชฉ์˜ ๋ชฉ๋ก๋“ค์„ ๊ฐ€์ ธ์™€ ํ•˜๋‚˜์”ฉ ์ฝ˜์†”์— ์ฐ์Šต๋‹ˆ๋‹ค.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Things to learn</title>
</head>
<body>
    <h1>Things to Learn to Rule the World</h1>
    <ul>
        <li>Learn PHP</li>
        <li>Learn Laravel</li>
        <li>Learn JavaScript</li>
        <li>Learn VueJS</li>
        <li>Learn CLI</li>
        <li>Learn Git</li>
        <li>Learn Astral Projection</li>
    </ul>
    <script>
        // Saves a NodeList of all list items on the page in listItems
        var listItems = document.querySelectorAll('ul li');
        // Loops through each of the Node in the listItems NodeList and logs its content
        for (var i = 0; i < listItems.length; i++) {
          (function () {
            console.log(this.innerHTML);
          }).call(listItems[i]);
        }

        // Output logs:
        // Learn PHP
        // Learn Laravel
        // Learn JavaScript
        // Learn VueJS
        // Learn CLI
        // Learn Git
        // Learn Astral Projection
    </script>
</body>
</html>

HTML์—๋Š” ์ •๋ ฌ๋˜์ง€ ์•Š์€ list์˜ item๋งŒ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ Javascript๋Š” DOM์—์„œ ๋ชจ๋“  ๊ฒƒ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. list๋Š” list์˜ item ๋๊นŒ์ง€ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. loop ๋‚ด๋ถ€์—์„œ list์˜ item์˜ ๋‚ด์šฉ์„ ์ฝ˜์†”์— ์ฐ์Šต๋‹ˆ๋‹ค.

์ด log๋ฌธ์€ ๊ด„ํ˜ธ ์•ˆ์— ์‹ธ์—ฌ ์žˆ์œผ๋ฉฐ, ๊ทธ ์œ„์—๋Š” call ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น list์˜ item์ด call ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ์ „๋‹ฌ๋˜์–ด ์ฝ˜์†”๋ฌธ์— ์žˆ๋Š” this(the์„ this๋กœ ๋ณ€๊ฒฝ) ํ‚ค์›Œ๋“œ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด์˜ innerHTML๊ฐ’์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. (์ผ๋ถ€ ์˜์—ญ)

๊ฐ์ฒด์—๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ์ฒด์ธ ํ•จ์ˆ˜๋„ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค, Javascript ํ•จ์ˆ˜์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋„ค๊ฐ€์ง€ ๋‚ด์žฅ ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Function.prototype.apply()
  • Function.prototype.bind() (Introduced in ECMAScript 5 (ES5))
  • Function.prototype.call()
  • Function.prototype.toString()
Function.prototype.toString() returns a string representation of the source code of the function.

์ง€๊ธˆ ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” .call(), .apply(), ๊ทธ๋ฆฌ๊ณ  toString()์— ๋Œ€ํ•ด ์„ค๋ช…์„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. (toString์„ ...์„ค๋ช… ํ–ˆ์—ˆ๋˜๊ฐ€...) Call๊ณผ Apply์™€ ๋‹ฌ๋ฆฌ Bind๋Š” ์ž์ฒด์ ์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— ์ปจํ…์ŠคํŠธ ๋ฐ ๊ธฐํƒ€ ์ธ์ˆ˜์˜ ๊ฐ’์„ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๋ฐ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ ์ค‘ ํ•˜๋‚˜์—์„œ Bind์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

(function introduce(name, interest) {
    console.log('Hi! I\'m '+ name +' and I like '+ interest +'.');
    console.log('The value of this is '+ this +'.')
}).bind(window, 'Hammad', 'Cosmology')();

// logs:
// Hi! I'm Hammad and I like Cosmology.
// The value of this is [object Window].

Bind๋Š” callํ•จ์ˆ˜์™€ ๊ฐ™์œผ๋ฉฐ ๋‚˜๋จธ์ง€ ์ธ์ˆ˜๋ฅผ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฐฐ์—ด๋กœ ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์ด๋Ÿฌํ•œ ๊ฐœ๋„˜์€ Javascript์— ๊ธ‰์ง„์ ์ด๋ฉฐ ๊ณ ๊ธ‰ ์ฃผ์ œ์— ์ ‘๊ทผํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ์ค‘์š” ํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ scope์™€ scope์™€ ๊ด€๋ จ๋œ ๊ฒƒ๋“ค์„ ๋” ์ž˜ ์ดํ•ดํ•ด ์ฃผ์…จ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ