모던 자바스크립트-Deep Dive 12,13

Gavri·2022년 3월 18일
0

DeepDive

목록 보기
6/12

함수

프로그래밍 언어의 함수는 일련의 과정을 문으로 구현하고 코드 블럭으로 감싸서 하나의 실행 단위로 정의한것이다.

함수를 사용하는 이유

  • 코드의 재사용 (중복방지)
  • 유지보수의 편의성을 높이고 실수를 줄여 코드의 신뢰성이 높아진다
  • 코드의 가동성 향상

js 함수또한 객체이다

함수 정의

//	함수 선언문
function add(x,y) {
  return x + y;
}

//	함수 표현식
function add(x,y) {
  return x + y;
}

//	Function 생성자 함수
var add = new Function('x','y','return x + y');

//	화살표 함수
var add = (x,y) => x + y;

함수 선언문

function (x,y) { // SyntaxError 함수 선언문은 함수 이름을 생략할 수 없다
  return x + y
} 
// 그리고 함수 선언문은 표현식이 아닌 문이다. 그러므로 표현식이 평가되어 생성된 함수가 아닌 undefined가 출력된다
function add (x,y) { 
  return x + y
} 
// -> undefined

function foo() { console.log('foo');}
foo() // 'foo'

(function boo() { console.log('foo');});
boo() // 'ReferenceError'

var add'식별자' = function add'함수이름'(x,y) {
  return x+y;
};
console.log(add'식별자'(2,5));

함수 표현식

js 함수는 객체 타입의 값이다.
js 함수는 값처럼 배열에 할당, 프로퍼티의 값, 배열의 요소가 될 수도 있다.
이처럼 값의 성질을 갖는 객체를 일급 객체라 한다.

var add = function(x,y) { // 익명함수
  return x + y;
}
console.log(add(2,5)); // 7
----
var add = function foo(x,y) { // 익명함수
  return x + y;
}
console.log(add(2,5)); // 7
console.log(foo(2,5)); // 에러 발생 / 함수 이름은 함수 몸체에서만 유효한 식별자이다.

함수 생성 시점과 함수 호이스팅

//	함수 참조
console.dir(add); // f add(x,y)
console.dir(sub); // undefined

//	함수 호출
console.log(add(2,5)) // 7
console.log(sub(2,5)) // TypeError: sub is not a function 해당 오류가 발생하는 이유는 위에서 undefined 이기에 뜬다.

//	함수 선언문
function add(x,y){return x + y};
var sub = function (x,y) { return x - y};

위처럼 동작 하는 이유는
함수 선언문의 경우 런타임(한줄씩 코드를 실행하는시점) 이전에 실행 되기 때문
이러한 특징을 호이스팅이라 하며 함수 선언문이 선두로 끌어 올려진 것처럼 동작하는 js 고유의 특징입니다.

화살표 함수 Function 생성자 함수

var add1 = (function () {
  var a = 10;
  return function (x,y) {
    return x + y + a;
  };
}());

console.log(add1(1,2)); // 13

var add2 = (function () {
  var a = 10;
  return new Function('x','y','return x + y + a;');
}());

console.log(add2(1,2)); // RefrenceError 
// 해당 에러가 뜨는 이유는 Function 을 통해 함수를 생성할 경우 클로저를 생성하지 않는 등 함수 선언문이나 표현식으로 생성한
// 함수와 다르게 동작하기 때문입니다.

// 화살표 함수
const add = (x,y) => x + y;
console.log(add(2,5)) // 7
//	화살표 함수 또한 기존의 함수 표현식,선언문을 완전히 대체하기 위해 디자인 된 것이 아닌 간략한 표현 및 내부 동작을 
//	가지고 있습니다. 특징으로는 생성자 함수 없음, 기존 함수와 thie 바인딩 방식 다름, prototype 프로퍼티 없음, arguments 객체 없음 

함수 호출


js 함수 특징

  • 매개변수 갯수,타입 제한이 없다. ( js 엔진마다 갯수 제한이 있을 수 있다.)
  • 매개변수보다 많이 입력해도 되고 작게 입력해도 된다.( 대신 예기치 않은 동작을 할 수도 있음)
  • 매개변수는 arguments 객체의 프로퍼티로 보관 된다.
  • 매개변수 타입을 사전에 지정할 수 없다.(js는 동적 타입언어 이기 때문)

매개변수 타입 체크

function add(x,y){
  if(typeof x !== 'number' || typeof y !== 'number'){
    throw new TypeError("인수는 모두 숫자 값 이어야 합니다.");
  }
  return x + y;
}

function add(x,y){
  x = x || 0;
  y = y || 0;
  return x + y;
}
add(2); // 2
add(2,3); // 5
add(); // 0

//	ES6에서 도입된 기본값
function add(x=0,y=0){
	return x + y;
}

참조에 의한 전달과 외부 상태의 변경

function changeVal(n,obj){
  n += 100;
  obj.name = "kim"
}
var num = 100;
var person = {name:"Lee"};
changeVal(num,person);
console.log(num,person); // num = 100 , person = {name:"kim"} 
// 원시값은 변경이 없다, 객체는 값이 변경된다.

다양한 함수 형태

즉시 실행 함수 , 재귀 함수

(function () {
  var a = 3;
  var b = 5;
  return a + b;
}());

function factorial(n) {
  if (n <= 1) return 1;	// 1이하일땐 탈출
  return n * factorial(n-1); // 재귀호출
}
console.log(factorial(3)); // 3! = 3 * 2 * 1  = 6;

중첩 함수(nested function or inner function)

function outer() {
	var x = 1;
  	function inner(){
      var y = 2;
      console.log(x + y);
    }
  	inner();
};
outer() // 3

콜백 함수(callback function)

function repeat(n,f) {
  for(var i = 0; i < n; i++){
    f(i);
  }
}
var logAll = function (i) {
  console.log(i);
}
repeat(5, logAll); // 0 1 2 3 4 
var logOdds = function (i) {
  if(i % 2) console.log(i);
};
repeat(5, logAll); //  1 3  

콜백 함수의 경우 함수형 프로그래밍 패러다임뿐만 아니라 비동기 처리에 활용되는 중요한 패턴이다.
고차 함수를 통해 공통된 기능을 해야하는 경우, 원하는 함수를 실행해야 되는 호출 시점을 정해야 하는 경우에 주로 사용 된다.

순수 함수와 비순수 함수

순수 함수 : 어떤 외부상태를 의존하지도 않고 변경하지도 않는 함수 즉 사이드이펙이 없는 함수
비순수 함수 : 순수 함수의 반대 사이드 이펙이 존재하는 함수 (지양)

//	순수 함수
var count = 0;
function increase(n){
  return ++n;
}
// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경
var count1 = increase(count); 
console.log(count1) // 1 
// 비순수 함수 -------
var count = 0;
function increase(n){
  return ++count;
}
// 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려워진다.
increase(); 
console.log(count) // 1 

스코프

스코프란?

var var1 = 1;
if(true){
 var var2 = 2;
  if(true){
    var var3 = 3;
  }
}
function foo(){
  var var4 = 4;
  function bar(){
    var var5 = 5;
  }
}
console.log(var1,var2,var3,var4,var5);
//	1,2,3,RefrenceError,RefrenceError

변수는 자신이 선언된 위치에 의해 자신이 유효한 범위(스코프),즉 다른 코드가 변수 자신을 참조할 수 있는 범위가 결정된다.
변수 뿐만 아니라 모든 식별자가 그렇다 다시 말해 **모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정된다,이를 스코프라 한다. 즉 스코프는 식별자가 유효한 범위를 말한다.

var x = 'g';
function foo(){
    var x = 'l';
    console.log(x); // l 
  //	글로벌 x 가 아닌 지역 스코프 안에 있는 x를 먼저 참조한다 ( 스코프 체인 )
  //	이것을 식별자 결정이라고 한다. js는 코드를 실행할 때 문맥을 고려한다 
}
foo();
console.log(x);	// g

스코프의 종류

  • 전역 : 코드의 가장 바깥영역에 존재하며 전역 스코프이다.
  • 지역 : 함수 몸체 내부 안에 존재하며 지역 스코프이다.

스코프 체인

함수가 계층적 구조를 가질때 스코프 끼리 계층적으로 연결 된 것을 스코프 체인이라고 한다.

변수를 참조할 대 js엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.

함수 레벨 스코프

지역은 함수 몸체 내부를 말하고 지역 스코프를 만든다고 했다 이는 코드 블럭이 아닌 함수에 의해서만 지역 스코프가 생성된다는 의미다. C나 Java 등을 비롯한 대부분의 프로그래밍 언어는 함수 몸체만이 아니라 if for while등 모든 코드 블럭이 지역 스코프를 만든다. 이러한 특성을 블록 레벨 스코프라 한다. 하지만 var 키워드로 선언된 변수는 오로지 함수의 코드 블럭(함수 몸체)만을 지역스코프로 인정한다.이러한 특성을 함수 레벨 스코프라 한다.

ES6에서 도입된 let,const는 블록 레벨 스코프를 지원한다.

var i = 10;
for(var i = 0; i < 5; i ++){
  console.log(i) // 0 ~ 4
}
console.log(i) // 5 함수 레벨 스코프
}

렉시컬 스코프

var x = 1;
function foo() {
  var x = 10;
  bar();
}
function bar() {
  console.log(x);
}
foo(); // 1
bar(); // 1

자바스크립트는 렉시컬 스코프를 따르므로 함수를 어디서 호출했는지가 아닌 어디서 정의 했는지에 따라 상위 스코프를 결정합니다. 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주지 않습니다. 이처럼 함수의 상위 스코프는 함수 정의가 실행될 때 결정됩니다.

profile
모든건 기록으로

0개의 댓글