Understanding Scope in JavaScript2 - Lee-hyuna/33-js-concepts-kr GitHub Wiki
์๋ฌธ : https://scotch.io/tutorials/understanding-scope-in-javascript
์๋ฐ์คํฌ๋ฆฝํธ๋ Scope๋ผ๊ณ ํ๋ ํน์ง์ด ์์ต๋๋ค. ๋ง์ ์๋ก์ด ๊ฐ๋ฐ์๋ค์ด ์ค์ฝํ์ ๋ํ ๊ฐ๋ ์ ์ฝ๊ฒ ์ดํดํ๊ณ ์์ง ์๊ณ ์์ต๋๋ค. ์ค์ฝํ์ ๋ํด ์ฌํํ๊ฒ ์ค๋ช ์ ํ๋ ค๊ณ ํฉ๋๋ค. scope๋ฅผ ์ดํดํ๋ฉด ์ค๋ฅ๋ฅผ ์ค์ด๊ณ ๊ฐ๋ ฅํ ๋์์ธ ํจํด์ ๋ง๋ค ์ ์์ต๋๋ค.
Scope๋ ์ฝ๋๊ฐ ๋ฐํ์ ์ค์ ์ฝ๋์ ํน์ ๋ถ๋ถ์ ์๋ ๋ณ์, ํจ์, ๊ฐ์ฒด์ ๋ํ ์ ๊ทผ์ฑ์ ๋๋ค. ์ฆ, scope๋ ์ฝ๋ ์์ญ์์ ๋ณ์ ๋ฐ ๋ค๋ฅธ ๋ฆฌ์์ค์ ์ ํจ๋ฒ์(=>visibility:๊ฐ์์ฑ์ ์ ํจ๋ฒ์๋ก ๋ฒ์ญ)์ ๊ฒฐ์ ํฉ๋๋ค.
๊ทธ๋์, ๋ณ์์ ์ ํจ๋ฒ์๋ฅผ ์ ํํ๊ณ ์ฝ๋์ ์ด๋ ๊ณณ์์ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋ชจ๋ ๊ฒ์ ๊ฐ์ง์ง ์๋๋ค๋ ๊ฒ์ด ๋ฌด์จ ์๋ฏธ์ผ๊น์? ํ๊ฐ์ง ์ฅ์ ์ scope๊ฐ ์ฝ๋์ ์ผ์ ์์ค์ ๋ณด์์ ์ ๊ณตํ๋ค๋ ๊ฒ์ ๋๋ค. ์ปดํจํฐ ๋ณด์์ ํ๊ฐ์ง ๊ณตํต๋ ์์น์ ์ฌ์ฉ์๊ฐ ํ ๋ฒ์ ํ์ํ ๋์(stuff:๋ฌผ๊ทผ์ ๋์์ผ๋ก ๋ณ๊ฒฝ)์๋ง ์ ๊ทผ์ ํด์ผ ํ๋ค๋ ๊ฒ์ ๋๋ค.
์ปดํจํฐ ๊ด๋ฆฌ์๋ค์ ์๊ฐํด๋ด ์๋ค. ์ปดํจํฐ ๊ด๋ฆฌ์๋ค์ ์ ๋ง์ ์ปดํจํฐ ์์คํ ์ ์ ์ดํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ค์๊ฒ ์์ ํ๊ฒ ์ก์ธ์ค ์ฌ์ฉ์ ๊ณ์ ์ ๋ถ์ฌํ๋ ๊ฒ์ ๊ด์ฐฎ์ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์์ต๋๋ค. ๊ด๋ฆฌ์๊ฐ ์ธ๋ช ์ธ ํ์ฌ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ด ๋๋ค. ๋ชจ๋ ์์คํ ์ ์์ ํ ์ ๊ทผํ ์ ์๊ณ ๋ชจ๋ ๊ฒ์ด ์์กฐ๋กญ๊ฒ ์๋ํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ์๊ธฐ ์์คํ ์ค ํ๋๊ฐ ์ ์ฑ ๋ฐ์ด๋ฌ์ค์ ๊ฐ์ผ๋๋ ๋์ ์ผ์ด ๋ฐ์ํฉ๋๋ค. ์ด์ ๊ทธ๊ฒ ๋๊ตฌ ์ค์ ์๋์ง ๋ชจ๋ฅด์๋์? ๊ธฐ๋ณธ ์ฌ์ฉ์ ๊ณ์ ์ ์ ๋ ฅํด์ผํ๊ณ , ํ์ํ ๊ฒฝ์ฐ์๋ ์ ์ฒด ์ก์ธ์ค ๊ถํ๋ง ๋ถ์ฌ ํด์ผ ํฉ๋๋ค. ์ด๊ฒ์ ๋ณํ๋ฅผ ์ถ์ ํ๊ณ ๋๊ฐ ๋ฌด์์ ํ๋์ง์ ๋ํ ์ค๋ช ์ ํ ์ ์๊ฒ ํ๋๋ฐ ๋์์ด ๋ฉ๋๋ค. ์ด ๊ฒ์ด "์ต์ ์ ๊ทผ์ ์๋ฆฌ"๋ผ๊ณ ๋ถ๋ฆฝ๋๋ค. ์ง๊ด์ ์ผ๋ก ๋ณด์ด์๋์? ์ด ์๋ฆฌ๋ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ๋์์ธ์๋ ์ ์ฉ์ด ์ฃ๋๋ค. ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ๋์์ธ์ ๋ค์์ ํ์ตํ Javascript์ ํฌํจํ ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ scope๋ผ๊ณ ํฉ๋๋ค.
ํ๋ก๊ทธ๋๋ฐ์ ๊ณ์ํ ๋ ์ฝ๋์ scope์ ์ง์ ํ๋ฉด ํจ์จ์ฑ์ ๋์ด๊ณ , ๋ฒ๊ทธ๋ฅผ ์ถ์ ํ๋ ์๊ฐ์ ์ค์ผ ์ ์๋ค๋ ์ฌ์ค์ ๊นจ๋ซ๊ฒ ๋ ๊ฒ์ ๋๋ค. scope๋ ๋ํ ์ด๋ฆ์ด ๊ฐ์ง๋ง scope๊ฐ ๋ค๋ฅธ ๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์์ ๋ ๋ค์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. scope์ context๋ฅผ ํผ๋ํ์ง๋ง์ธ์. scope์ context ๋๋ค ๋ค๋ฅธ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋๊ฐ์ง ํ์ ์ scope๊ฐ ์กด์ฌํฉ๋๋ค.
- Global Scope
- Local Scope
ํจ์ ๋ด๋ถ์์ ์ ์๋ ๋ณ์๋๋ local scope์ด๊ณ ํจ์ ์ธ๋ถ์์ ์ ์๋ ๋ณ์๋ global scope์ ๋๋ค. ํจ์๊ฐ ํธ์ถ๋ ๋ ๊ฐ ํจ์๋ ์ 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์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ณ์๋ค์ ๋ชจ๋ ํธ์ถ์ ๋ํด ๋ค๋ฅธ scope์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ฆ, ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง ๋ณ์๋ฅผ ๋ค๋ฅธ ํจ์์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๊ฒ์ ๋ณ์๊ฐ ๊ฐ ํจ์์ ๋ฐ์ธ๋ฉ๋๊ณ ๊ฐ ํจ์๊ฐ ์๋ก ๋ค๋ฅธ ๋ฒ์์ด๋ฉฐ ๋ค๋ฅธ ํจ์์์๋ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
// Global Scope
function someFunction() {
// Local Scope #1
function someOtherFunction() {
// Local Scope #2
}
}
// Global Scope
function anotherFunction() {
// Local Scope #3
}
// Global Scope
ํจ์์ ๋ฌ๋ฆฌ 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๋ ํจ์๊ฐ ํธ์ถ๋๊ณ ์คํ์ด ๋๋ ํ ๊ณ์ ์ ์ง ๋ฉ๋๋ค.
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ข
์ข
๋์ผํ ๊ฐ๋
์ผ๋ก ์ธ๊ธํ์ฌ ์์ฃผ 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๊ฐ ์๋ 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
}
์คํ 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
}
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๋ ์ค์ฒฉ๋ ํจ์ ๊ทธ๋ฃน์์ ๋ด๋ถ ํจ์๊ฐ ๋ถ๋ชจ ๋ฒ์์ ๋ณ์ ๋ฐ ๊ธฐํ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฆ, ์์ ํจ์๊ฐ ๋ถ๋ชจ์ ์คํ 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 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)์ด ์์ต๋๋ค. ์ด๊ฒ์ window context์์ ํธ์ถ๋๋ self-invoked anonymous ํจ์๋ก this
์ ๊ฐ์ด window
์ผ๋ก ์ค์ ๋์ด ์์์ ์๋ฏธํฉ๋๋ค. ์ด๊ฒ์ ํ๋์ global ์ธํฐํ์ด์ค๋ฅผ ๋
ธ์ถ์์ผ ์ํธ ์์ฉ์ ํฉ๋๋ค.
(function(window) {
// do anything
})(this);
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์ ๊ด๋ จ๋ ๊ฒ๋ค์ ๋ ์ ์ดํดํด ์ฃผ์ จ์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.