-
์๋ฐ์คํฌ๋ฆฝํธ์ ํจ์๋ ๊ฐ์ฒด์ผ๊น?์นดํ ๊ณ ๋ฆฌ ์์ 2023. 2. 18. 16:51
Function์ ๋ํ mdn ๋ฌธ์๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋์์๋ค.
In JavaScript, functions are first-class objects, because they can be passed to other functions, returned from functions, and assigned to variables and properties. They can also have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called.
"ํจ์๋ ์ผ๊ธ ๊ฐ์ฒด๋ค"๋ผ๋ ๋ด์ฉ์ด๋ฉฐ, ๋ค์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฒ์ ์ผ๊ธ๊ฐ์ฒด๋ผ๊ณ ํ๋ ๊ฒ์ ์ ์ ์๋ค.
- ๋ค๋ฅธ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํ ์ ์๊ณ ,
- ํจ์์ ๋ฐํ๊ฐ์ผ๋ก ์ฌ์ฉํ ์ ์์ผ๋ฉฐ,
- ๋ณ์๋ ์๋ฃ๊ตฌ์กฐ(๊ฐ์ฒด, ๋ฐฐ์ด ๋ฑ)์ ์ ์ฅํ ์ ์๋ค.
์ถ๊ฐ๋ก ํจ์๋ ๊ฐ์ฒด์ฒ๋ผ ํ๋กํผํฐ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ฉฐ, ์ผ๋ฐ ๊ฐ์ฒด์๋ ๋ค๋ฅด๊ฒ 'ํธ์ถ ๊ฐ๋ฅ'ํ๊ธฐ์ ํจ์๋ผ๊ณ ๋ถ๋ฅธ๋ค๊ณ ๋์์๋ค.
1. ํจ์ ๊ฐ์ฒด์ ํ๋กํผํฐ
ํจ์๋ ๊ฐ์ฒด์ด๊ธฐ์ ์ผ๋ฐ์ ์ธ ๊ฐ์ฒด์ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ธ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ
์ถ๊ฐ๋ก ํจ์๋ง์ ํ์ฆ ํ๋กํผํฐ
๋ฅผ ๊ฐ์ง๊ณ ์๋ค. console.dir๋ฅผ ์ด์ฉํ์ฌ ํจ์ ๊ฐ์ฒด์ ๋ด๋ถ๋ฅผ ๋ค์ฌ๋ค๋ณด์.๋ณผ ์ ์๋ฏ์ด, arguments, caller, length, name, prototype ํ๋กํผํฐ๋ ๋ชจ๋ ํจ์ ๊ฐ์ฒด์ ๋ฐ์ดํฐ ํ๋กํผํฐ๋ค. ์ด๋ค ํ๋กํผํฐ๋ ์ผ๋ฐ ๊ฐ
์ฒด์๋ ์๋ ํจ์ ๊ฐ์ฒด ๊ณ ์ ์ ํ๋กํผํฐ๋ค.
1-1. arguments ํ๋กํผํฐ
arguments ๊ฐ์ฒด๋ ํจ์ ํธ์ถ ์ ์ ๋ฌ๋ ์ธ์๋ค์ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ์ํ๊ฐ๋ฅํ(์ดํฐ๋ฌ๋ธ) ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ด๋ฉฐ, ํจ์ ๋ด๋ถ์์ ์ง์ญ ๋ณ์์ฒ๋ผ ์ฌ์ฉ๋๋ค.
arguments ๊ฐ์ฒด๋ ์ธ์๋ฅผ ํ๋กํผํฐ ๊ฐ์ผ๋ก ์์ ํ๋ฉฐ, ํ๋กํผํฐ ํค๋ ์ธ์์ ์์๋ฅผ ๋ํ๋ธ๋ค. ๋ํ callee ํ๋กํผํฐ๋ ํธ์ถ๋์ด arguments ๊ฐ์ฒด๋ฅผ ์์ฑํ ํจ์, ์ฆ ํจ์ ์์ ์ ๊ฐ๋ฆฌํค๊ณ , length๋ ์ธ์์ ๊ฐ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ์ ์ธ๋ ๋งค๊ฐ๋ณ์์ ๊ฐ์์ ํธ์ถํ ๋ ์ ๋ฌํ๋ ์ธ์์ ๊ฐ์๋ฅผ ํ์ธํ์ง ์๋ ํน์ฑ์ด ์๋๋ฐ, ์ด ๋๋ฌธ์ ํจ์๊ฐ ํธ์ถ๋๋ฉด ์ธ์ ๊ฐ์๋ฅผ ํ์ธํ๊ณ ์ด์ ๋ฐ๋ผ ํจ์์ ๋์์ ๋ฌ๋ฆฌ ์ ์ํ ํ์๊ฐ ์์ ์๋ ์๋ค. ์ด๋ arguments๊ฐ์ฒด๊ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋๋ค.
function sum() { let res = 0; // arguments๊ฐ์ฒด๋ lengthํ๋กํผํฐ๊ฐ ์๋ ์ ์ฌ๋ฐฐ์ด๊ฐ์ฒด์ด๋ฏ๋ก for๋ฌธ ์ํ๊ฐ ๊ฐ๋ฅํ๋ค. for(let i = 0; i < arguments.length; i++){ res += arguments[i] } return res } console.log(sum); console.log(sum(1,2)); console.log(sum(1,2,3));
์ ์ฌ๋ฐฐ์ด ๊ฐ์ฒด๋ ๋ฐฐ์ด์ด ์๋๋ฏ๋ก, ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋๋ฐ, ์ด ๋ call, bind๋ฑ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฐ์ด๋ก ๋ณํํ ์ ์์ผ๋ฉฐ, ๋ณํ์ ๋ฒ๊ฑฐ๋ก์์ ์ค์ด๊ธฐ ์ํด ES6์์ Rest ํ๋ผ๋ฏธํฐ๋ฅผ ๋์ ํ๋ค.
function sum(...args){ return args.reduce((pre, cur) => pre + cur, 0); }
1-2. caller ํ๋กํผํฐ
ํจ์์ caller ํ๋กํผํฐ๋ ํจ์ ์์ ์ ํธ์ถํ ํจ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
function foo(func){ return func(); } function bar(){ return 'caller: ' + bar.caller; } // ๋ธ๋ผ์ฐ์ ์์ ์คํํ ๊ฒฐ๊ณผ console.log(foo(bar)); // caller : function foo(func) {...} console.log(bar()); // caller: null
1-3. length ํ๋กํผํฐ
ํจ์๋ฅผ ์ ์ํ ๋ ์ ์ธํ ๋งค๊ฐ๋ณ์ ๊ฐ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
function bar(x){ return x; } console.log(bar.length); // 1 const x = (a,b) => a+b; console.log(x.length) // 2
1-3. name ํ๋กํผํฐ
ํจ์ ์ด๋ฆ์ ๋ํ๋ธ๋ค. ์ต๋ช ํจ์ ํํ์์ ๊ฒฝ์ฐ ES5 ์์๋ ๋น ๋ฌธ์์ด์ ๊ฐ์ก์ผ๋, ES6๋ถํฐ๋ ํจ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ์๋ณ์๋ฅผ ๊ฐ์ผ๋ก ๊ฐ๋๋ค.
const x = (a,b) => a+b; console.log(x.name); // x
1-4. prototype ํ๋กํผํฐ
prototype ํ๋กํผํฐ๋ ์์ฑ์ ํจ์๋ก ํธ์ถํ ์ ์๋ ํจ์ ๊ฐ์ฒด, ์ฆ constructor๋ง์ด ์์ ํ๋ ํ๋กํผํฐ๋ค. ์ผ๋ฐ ๊ฐ์ฒด์ ์์ฑ์ ํจ์๋ก ํธ์ถํ ์ ์๋ non-constructor์๋ prototype ํ๋กํผํฐ๊ฐ ์๋ค.
// ํจ์ ๊ฐ์ฒด๋ prototype ํ๋กํผํฐ๋ฅผ ์์ ํ๋ค. (function() {}).hasOwnProperty('prototype'); // true ({}).hasOwnProperty('prototype'); // false
prototype ํ๋กํผํฐ๋ ํจ์๊ฐ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ์์ฑ์ ํจ์๋ก ํธ์ถ๋ ๋ ์์ฑ์ ํจ์๊ฐ ์์ฑํ ์ธ์คํด์ค์ ํ๋กํ ํ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํจ๋ค.
2. ๋ฐ๋ผ์ ํจ์๋ ์ผ๋ฐ ๊ฐ์ฒด + a ๋ค.
ํจ์๋ ์ผ๋ฐ ๊ฐ์ฒด๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋๋ ๋ฌผ๋ก , ์์์ ์ดํด๋ณธ ํจ์๋ง์ ๋ด๋ถ ์ฌ๋กฏ๊ณผ ๋ด๋ถ ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ค.
ํจ์ ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ค์ ๋ด๋ถ ์ฌ๋กฏ์ผ๋ก ๋ด๋ถ์ ์ถ๊ฐ๋ก ์ ์ฅํ๋ค.
- ํด๋ก์ ๋ก ๋ฌถ์ด๋ ๋ ์์ปฌ ํ๊ฒฝ(Lexical Environment) -
[[Environment]]
- ํจ์ ์ฝ๋ -
[[ECMAScriptCode]]
- ํจ์ ์ข
๋ฅ -
[[FunctionKind]]
: "normal", "classConstructor", "generator", "async" - ์์ฑ์ ์ข
๋ฅ -
[[ConstructorKind]]
: "base", "derived" this
์ฐธ์กฐ ํํ -[[ThisMode]]
- strict mode ์ฌ๋ถ -
[[Strict]]
super
์ฐธ์กฐ -[[HomeObject]]
- ๊ธฐํ ๋ฑ๋ฑ
๋ํ ํจ์๊ฐ์ฒด๋
[[Call]]
,[[Constructor]]
๋ด๋ถ ๋ฉ์๋๋ฅผ ์ถ๊ฐ๋ก ๊ฐ์ง๋ค. ๋จ์ํ๊ฒ ํจ์๋ฅผ ํธ์ถํ๋ฉด ๊ฐ์ฒด ๋ด๋ถ์[[Call]]
์ด ํธ์ถ๋๊ณ , new ๋๋ super ์ฐ์ฐ์์ ํจ๊ป ํธ์ถํ๋ฉด[[Constructor]]
๊ฐ ํธ์ถ๋๋ค.๋ด๋ถ๋ฉ์๋
[[Call]]
์ ๊ฐ์ง๊ณ ์๋ ํจ์ ๊ฐ์ฒด๋ฅผcallable
์ด๋ผ๊ณ ํ๊ณ , Constructor๊ฐ ๊ตฌํ๋ ๊ฐ์ฒด๋ฅผ constructor๋ผ๊ณ ๋ถ๋ฅด๋๋ฐ, ์๋ฐ์คํฌ๋ฆฝํธ์ ํจ์๋ callable์ด๋ฉด์ contructor ์ผ ์๋ ์๊ณ ์๋ ์๋ ์๋ค.ํจ์๋ ํธ์ถํ ์ ์๋ ๊ฒ์ด ๋น์ฐํ๊ธฐ์, ๋ชจ๋ ํจ์ ๊ฐ์ฒด๋ callable์ด๋ค. ๊ทธ๋ฌ๋ ๋ชจ๋ ํจ์๊ฐ constructor๋ ์๋๋ค. ๋ํ์ ์ผ๋ก ํ์ดํ ํจ์๋ callable์ด๋ฉด์ non-constructor์ด๋ค. constructor๋ก ์ฌ์ฉํ๋ ค๋ฉด '์์ฑ์ ํจ์'๋ก ์ฌ์ฉ ๊ฐ๋ฅํด์ผ ํ๋ค.
- constructor : ํจ์ ์ ์ธ๋ฌธ, ํจ์ ํํ์, ํด๋์ค (ํด๋์ค๋ ํจ์์ด๋ค.)
- non-constructor : ๋ฉ์๋์ ์ถ์ฝ ํํ, ํ์ดํ ํจ์
// ํจ์ ์ ์ธ๋ฌธ, ํจ์ ํํ์ function foo(){} console.log(new foo()); // foo{} const bar = function foo(){} console.log(new bar()); // bar{} // ๋ฉ์๋ ์ถ์ฝ ๋ฐฉ์ ์๋๊ธฐ ๋๋ฌธ์ constructor const low = { x : function (){} } console.log(new low.x())); // x{} // ํ์ดํ ํจ์ const arrow = () => {}; console.log(arrow); // () => {} console.log(new arrow()) // Uncaught TypeError: arrow is not a constructor // ๋ฉ์๋ ์ถ์ฝ ํํ const obj = { x() {} } console.log(new obj.x()) // Uncaught TypeError: obj.x is not a constructor
์ฐธ๊ณ
- ์๋ฐ์คํฌ๋ฆฝํธ ๋ฅ๋ค์ด๋ธ 18์ฅ ํจ์์ ์ผ๊ธ ๊ฐ์ฒด
- https://ui.toast.com/weekly-pick/ko_20170630
- https://basemenks.tistory.com/189