웹프로그래밍 : Functions

chanyeong yu ·2025년 4월 21일

웹프로그래밍

목록 보기
8/12

Functions

함수 선언과 호이스팅

console.log(`🔥 ${factorial(10)}`); 
//hoisting, 즉 라인 밑에 있어도 실행가능.
-
function factorial(x) {
  if (x <= 1) return 1;
  return x * factorial(x - 1);
} 
  • 즉 어디에서 선언하든 상관없이 호이스팅이 가능
  • 하지만 전통적인 방식으로 함수를 만들어줘야 가능하다.

함수 변수 선언 - 호이스팅 불가능

const square = function (x) {
  return x * x;
}; 
  • 다음과 같은 방식으로 변수에 함수를 선언하면 호이스팅이 불가능하다.

화살표 함수, 함수의 변형

functon square(x){
  return x * x ;
};
// 변수에 대입하는 꼴로 변형 
const square = function (x) {
  return x * x;
}; 
// function 생략, 화살표 꼴 사용 
const square = (x) => {
  return x * x;
}
// return, {}도 생략 
const square = (x) => x * x; //리턴이 두줄이면 {}를 꼭 사용한다. 
  • 이는 다 똑같은 함수 선언 방식이다. 다만 이처럼 화살표를 사용해서 식을 만들 수도 있다. 이는 Array에서 배웠던 Map이나 filter에도 축약해서 사용한다.

Nested Funtions(중첩 함수)

function hypotenuse(a, b) {
  function square(x) {
    return x * x + a * b;
  }
  return square;
}
let s1 = hypotenuse(10, 20); // a = 10, b = 20
let s2 = hypotenuse(5, 5); 	// a = 5, b = 5
console.log(s1(10)); // 10 * 10 + 10 * 20
console.log(s2(2));	// 2 * 2 + 10 * 20
  • 함수들은 함수 안에서 정의될 수 있다.
  • inner function은 콘솔에서 검색할 수 없다. private한 것.
    따라서 outer funtion에서만 접근할 수 있다.
  • 그리고 s1s2는 각각의 a,b를 가지는 독립적인 공간이다.

Invoking Funtions

let calculator = {
  operand1: 1,
  operand2: 1,
  add() {
    this.result = this.operand1 + this.operand2;
  },
};
calculator.add(); //함수 호출 
calculator.result; //calculater안에 새로운 result 프로퍼티 생성
  • 객체 안에서 add : function()add()로 생략할 수 있다.
  • this.result의 경우 원래 존재하지 않았던 프로퍼티므로 새로 생성이 된다.

this 사용법 = 그냥 함수

let o = {
  m: function () {
    let self = this; // this를 변수에 지정하고 중첩함수 내에서 사용가능하다.
    function f() {
      this === o; // 사용 불가능
      self === o; // 사용 가능하다.
    }
  },
};
  • 중첩된 함수 안에서는 외부함수의 this를 사용할 수 없다.
  • 따라서 변수에 this를 할당하고 사용한다.
  • 참고로 이렇게 선언하면 함수 내 호이스팅이 가능하다.

this 사용법 = 화살표 함수

let o = {
  m: function () {
    const f = () => { //대신 화살표 함수를 사용하면 this를 상속받아 바로 사용할 수 있다. 
      this === o; // 가능하다.
    };
  },
};
  • 화살표 함수의 경우 this를 사용할 수 있다.
  • 마찬가지로 내부함수의 호이스팅이 불가능하다.

bind()

let o = {
  m: function () {
    const f = function () {
      console.log(`👏 ${this === o}`); //true
    }.bind(this);
    f(); //호이스팅이 안된다
  },
};
-
let k = function (a) {
	return this.x + a;
};
let k_bind = k.bind({ x: 10, y: 20 }); //bind
console.log(`👏`, k_bind(5));
  • bind() 메소드를 사용하면 this로 미리 묶어서 지정해주는 것이다.
  • this를 굳이 따로 사용하지 않고 객체에 지정해놓는 것.

함수 인자에 spread operater 사용하기

max(1, 10, 100, 2, 3, 1000, 4, 5, 6); // => 1000
-
function max(first = -Infinity, ...rest) {
  let maxValue = first; 
  for (let n of rest) {
    if (n > maxValue) {
      maxValue = n;
    }
  }
  return maxValue;
}
  • ...rest를 사용하면 변수를 여러개 받겠다는 뜻이다.
  • 배열인 max를 넣어주면 첫번째 값인 1first에 들어가고,
    나머지는 rest에 들어가게 된다.

Array.sort()

let a = [33, 4, 1111, 222];
a.sort(); // a == [1111, 222, 33, 4];
-
a.sort(function (a, b) {
  return a - b; // Returns < 0, 0, or > 0, depending on order
});
-
  • return값이 음수면 a가 앞에, 0이면 위치 유지,양수면 b가 앞에로 정렬한다.
  • 기본적으로 오름차순으로 정리가 된다.

함수도 프로퍼티를 가질 수 있다.

uniqueInteger.counter = 0;
function uniqueInteger() {
  return uniqueInteger.counter++;
}
/
uniqueInteger(); //1
uniqueInteger(); //2
uniqueInteger(); //3
uniqueInteger(); //4
  • 함수도 일급객체이기 때문에 프로퍼티를 가질 수 있다.

함수 내에서 선언된 변수가 겹칠때 + 익명함수

let global = "hi";
function chunkNamespace() {
  let global = "hello"; // 🌟 주석달면 "incheon"
  function aaa() {
    console.log("🌟", global);
  }
  aaa();
}
chunkNamespace()
// 익명함수
(function () {
  let global = "Dweb"; // 🌟 주석달면 "incheon"
  function dweb() {
    console.log("🌟", global);
  }
  dweb();
})(); 
  • 함수 밖에서 선언된 변수와 함수 내부에서 선언된 변수명이 겹칠 수 있다.
  • 이 경우에는 함수 내부에 있는 변수를 사용한다. 내변수 ㅎㅎ

Closures1

let scope = "global scope"; // 전역변수
function checkscope() {
  let scope = "local scope"; // 지역변수, 자유변수.
  function f() {
    return scope; 
  }
  return f();
}
let v = checkscope(); //이제 v는 더 이상 바뀌지 않음.
  • lexical scoping.
  • 오직 전해진 매개변수 안에서만 정의되는 함수. 함수 밖에서 변수가 어떻게 정의되든 상관없이 아주 안정적인 함수라고 할 수 있다.

Closures2

let uniqueInteger2 = (function () {
  // Define and invoke
  let counter = 0; // Private state of function below
  return function () {
    return counter++;
  };
})();
uniqueInteger2.counter = 100; //해도 의미 없음 
uniqueInteger2(); // => 0
uniqueInteger2(); // => 1
  • 이렇게 내부에서 변수를 선언해놓으면 외부에서 절대 접근할 수 없기 때문에 안정적이다.

Closures3

function counter() {
  let n = 0;
  return {
    count: function () {
      return n++;
    },
    reset: function () {
      n = 0;
    },
  };
}
/
let c = counter(),
  d = counter(); // 두개는 독립적인 공간.
console.log(c.count(<)); // => 0
console.log(d.count()); // => 0
c.reset(); 
console.log(c.count()); // => 0
console.log(d.count()); // => 1
  • cd는 완전히 다른 독립적인 공간이다.
  • 따라서 메소드들도 독립적으로 작용한다.

get(), set()

function counter(n) {
  return {
    get count() {
      //게터
      return n++;
    },
    set count(m) {
      //세터
      if (m > n) n = m;
      else throw Error("count can only be set to a larger value");
    },
  };
}
  • get과 set이 문법적으로 정의 내려져있다.

loop를 통해 클로저 생성

function constfunc(v) {
  return () => v;
}
let funcs1 = [];
for (var i = 0; i < 10; i++) funcs1[i] = constfunc(i);
funcs1[5](); // => 5
funcs1[6](); // => 6
  • 루프를 통해서 리턴값으로 함수를 집어넣을 수 있다.
    그리고 그 함수의 리턴은 i가 될 것.

함수 프로퍼티

function func1() {}
-
function func2(a, b) {}
-
console.log(func1.length, func1.name);
// Expected output: 0
-
console.log(func2.length, func2.name);
// Expected output: 2
-
  • 함수도 프로퍼티를 가질 수 있다. 아규먼트의 갯수와 이름을 반환해준다.

call() 메소드

let obj = { class: "dweb", prof: "giseok" };
let fullname = function (name) {
  this.class = "incheon" + this.class;
  this.prof = this.prof + name; 
  console.log(name);
};
fullname.call(obj, "park");
  • call 메소드를 쓰면 fullname의 첫번째 프로퍼티에는 obj가 들어간다. 즉 객체를 전달.
  • 그리도 두번째 name에는 "park"이 들어가게 된다.

Constructor

const f = new Function("x", "y", "return x*y;");
  • 컨스트럭터를 사용해서 함수를 생성하면 런타임에 함수가 생성된다. 즉 그래서 LEXICAL SCOPING을 사용하지 않음.

0개의 댓글