Javascript 함수

김정훈·2024년 5월 4일

JavaScript

목록 보기
14/19

함수

1. 함수 정의

1) 함수 선언문으로 정의하는 방법

function square(x) {
  return x*x; 
}
  • 함수 ❌, 함수 객체 ⭕️
  • 함수명 = =변수명 / 함수명은 참조변수 / 전역변수 / window 객체의 하위 속성으로 추가
  • 함수도 객체, 함수명 , 변수명, 변수? 참조변수
  • 함수를 어디에 정의하든 호출은 상단이든 하단이든 어디에서든 호출 가능.
  • 함수는 객체, 함수명은 객체의 참조 변수, 함수 값으로 사용가능
  • 함수명은 참조 변수와 비슷한 방식으로 사용가능 👉 일급함수
    👉 함수형 프로그래밍 가능
  • function 키워드만 선언해도 Funciton 생성자로 만들어진 객체

참고)

객체를 사용하려면 참조변수(주소값이 담겨진 변수)가 필요.

2) 함수 리터럴로 정의하는 방법

const add = function(num1, nun2){
  return num1 + num2
};

함수 리터럴로 정의되는 경우에는 실행 과정중에 함수의 주소값이 참조변수에 대입된다.
그렇기 때문에 호이스팅이 되지않는다. 참조변수는 null값을 갖게됨.

3) Function 생성자로 정의하는 방법

var square = new Function("x", "return x*x");

상속과 관련

스크립트 상속 : 객체간의 프로토타입 체인의 연결로 상속이 이뤄진다.
function만 입력해도 👉 new Function(...) 객체화된다.
Function.prototype. 상속 받는 과정

4) 화살표 함수 표현식으로 정의하는 방법

  • 함수가 매개변수로 사용되는 경우 : 함수 내부에서만 제한적으로 사용
  • 형식을 단순화 해서 사용
    1) function 키워드와, 함수명을 생략
    2) 매개변수와 구현 코드 부분 사이에 =>
    3) 구현 코드가 1줄일때는 {} 부분도 생략 가능, return은 생략
    4) 변수명도 최대한 짧게 사용
    5) 매개변수가 1개 -> (..) 생략 가능
    6) 매개변수가 없는 경우는 (..) 생략 불가
const nums = [1,2,3,4,5,6,7,8,9];
const nums2 = nums.map(funciton(num){
  return num * num;
)};
const nums = [1,2,3,4,5,6,7,8,9];
const nums2 = num.map  (x => x * x);
const nums = [1,2,3,4,5,6,7,8,9];
function map(nums, callback) {
    const nums2 = [];
    for(let i = 0; i < nums.length; i++){
        const num = callback(nums[i]);
        nums2.push(num);
    }
    return nums2;
    
}

const nums2 = map(nums, function(num){
    return num * num;
});

const nums3 = map(nums, x => x * x);

참고)

입급 객체 / 일등 함수 : 함수형 프로그래밍 방식

  • 함수를 변수와 동일하게 취급
  • 함수가 객체 / 함수는 값
  • 함수가 매개변수로 사용 가능 : 사용자 정의 기능, 정의한 하나의 역할(단일기능), 짧은 식의 형태(화살표함수)
function outer(callback){ 
  callbakc();
}
function inner() { 
  console.log("inner 호출!")
}
outer(inner); //inner가 매개변수로 사용됨.
function outer(callback){ 
  callbakc();
}
outer(function(){
  //outer(매개변수); 호출했다. 매개변수로 사용된 함수는 일회용으로서 외부에서는 사용이 불가능하다.
  	console.log("inner 호출");
});
  • 함수가 반환값으로 사용 가능
    👉 클로저 : 고차함수
  • 함수형 프로그래밍

화살표 함수 this

함수 리터럴로 정의된 this 값은 함수를 호출할 때 결정.
화살표 함수의 this 값은 함수를 정의할 때 이미 결정된 this값으로 결정 즉, 화살표 함수 바깥의 this값이 화살표 함수의 this 값이 됩니다.

const person = {
  name : "이름",
  age : 40,
  showInfo: () =>{
    console.log(this);
  }
}
person.showInfo(); // This는 window

const person = {
  name : "이름",
  age : 40,
  showInfo: function() {
    console.log(this);
  }
}
person.showInfo(); //This는 person

inner는 showInfo 함수 호출시에 정의

const person = {
  name : "이름",
  age : 40,
  showInfo: function() {
    console.log('showinfo', this);
    const inner = () => {
      console.log('inner',this);
    }; //
    inner();
  }
}


person.showInfo(); //This는 person

    const inner = () => console.log("inner", this); // This는 person
    inner();
  }
}
showInfo();// 오류
const showInfo = person.showInfo;
person.showInfo(); // This는 person
showInfo(); //window
person.showInfo() === showInfo;


2. 중첩 함수

  • 함수 안에 함수가 정의된 구조
  • 함수명이 변수, 함수 안에 함수를 정의 👉 지역변수를 정의하는것과 동일
function norm(x) {
	var sum2 = sumSquare();
	return Math.sqrt(sum2);
	function sumSquare() {
		sum = 0;
		for(var i = 0; i < x.length; i++) sum += x[i]*x[i];
		return sum;
	}
}
var a = [2,1,3,5,7];
var n = norm(a);
console.log(n);

3. 함수 호출

1) 함수 호출

var s = square(5);

2) 메서드 호출

obj.m = function() { ... };
obj.m();

3) 생성자 호출

var obj = new Object();

4) call, apply를 사용한 간접 호출

funciton.prototype
함수를 실행하는 기능

  • func.apply(thisArg,[argsArray]);
    • 매개변수thisArg: call, apply를 호출할때 사용될 this의 값/ 값을 직접 설정이 가능하다.
function add(num1, num2){
  return num1+ num2;
}
add.apply
add.apply(this, [10,20])
// 1번째 매개변수는 this의 범위(현재는 window로 설정햇음)
// 2번째 매개변수는 매개변수의 값. 배열로 설정
const person = {name: "이름", age: 40}
function add(num1, num2){
  return num1+ num2;
}
add.apply(person, [10,20])
// 1번째 매개변수는 this의 범위(person), (person이 add를 호출한것은 아니다, 단순히 this값만 변경된 것 이다.)
// 2번째 매개변수는 매개변수의 값(인수). 배열로 설정
  • call
    apply와 동일하지만 매개변수를 가변적으로 적용할 수 있다.
const person = {name: "이름", age: 40}
function add(num1, num2){
  return num1+ num2;
}
add.apply(person, 10,20)
  • bind
    this와 매개변수를 고정함으로써 새로운 함수를 생성(클로저 팩토리함수랑 비슷)
function add(n1,n2){
  return n1 + nu2;
}
const add10 = add.bind(this,10); //add메서드의 매개변수 첫번째 n1이 10으로 고정된 함수가 생성되었다.
add10(20); //>num2가 20으로 되었고, 고정된 num1이 30 출력.

참고) 자바스크립트의 상속 : 객체간의 상속

  • Prototype 연결을 통한 객체간의 상속
  • 모든 객체의 프로토타입 체인 속성
  • [[Prototype]]
  • __proto__ : 프토로타입체인 연결
  • 모든 객체는 Object.prototype 상속을 받는다.
const objA = {a:1, b:2};
const objB = {c:3, d:4};
objB.__proto__ = objA; //B가 A의 자원을 상속받았다.

4. 즉시 실행 함수

(function(){
  //즉시 실행코드
})(//매개변수);
- - - - - - - - - - - - - - -
(function(){
  console.log("즉시실행");
})();
- - - - - - - - - - - - - - -
(function(num1,num2){
  return num1 + num2;
})(10,20);

5. 함수의 인수

1) 인수의 생략

arguments: 지역변수
참고
parameter : 인자(매개변수)
argument : 매개변수로 사용된 값

function add(num1, num2){
  console.log(arguments)
}

2) 가변 길이 인수 목록(Arguments 객체)

자바스크립트는 인수를 가변적으로 사용이 가능하다.

function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++){
    total+=arguments[i];
  }
  return total;
}
sum(10,20,30,40);

'...'

1) 가변인수

function sum(num1, num2, ...nums){
  console.log(nums);
}
sum(10,20,30,40,50); //> 30, 40, 50 만 출력된다.

2) 전개연산자

const nums = [10, 20];
function add(num1, num2){
  return num1 + num2;
}
add(...nums);

새로운 객체를 생성할 때 사용

const fruits = ["apple","orange", "mango"];
const fruits2 = [...furits];
fruits === fruits2 //false 새로운 객체를 생성했다.

3) 나머지연산자

const nums = [1,2,3,4,5,6,7,8,9];
const [a,b,c] = nums;  //비구조화 할당

const nums = [1,2,3,4,5,6,7,8,9];
const [a,b, ...rest] = nums; //나머지연산자

3) 재귀 함수

arguments.callee : 함수 객체의 주소값
같은 함수를 연속적으로 내부에서 호출하는 방법

function add(){
  	console.log(arguments);
  console.log(arguments.callee == add);
}
add(); //> true출력

팩토리얼 연산

!5 👉 54321

function factorial(num){
  if ( num < 1 ) {
    ruturn 1;
  }
  return num * factorial(num - 1) //함수내부에 같은 함수르 또 호출
}

메모제이션 기법

function factorial(num){
  factorial.cache = factorial.cache ?? {};
  const key = `num_${num}`;
  if(factorial.cache[key]){
    console.log("캐시 사용");
    return factorial.cache[key];
  }

  if ( num < 1 ) {
    ruturn 1;
  }

  const result = num * factorial(num - 1) //함수내부에 같은 함수를 또 호출
  factorial.cache[key] = result;
  console.log("캐시 저장");
  return result;
}

6. 프로그램 평가와 실행과정

함수객체 👉 함수 ❌ 👉 실행 ❌
함수객체 👉 번역, 평가 👉 실행 가능 객체(EC - Execution Context)(힙) 👉 스택에서 EC가 실행될때 필요한 자원 할당

var num1 = 10;
function outer() { 
  var num2 = 20;
  
  function inner(){
    var num3 = 30;
    return num1 + num2 + num3;
  }
  console.log(inner());
  console.dir(inner);
}
window: 

Global EC{
  변수 레코드 window 하위 속성으로 변수 레코드 구성
  window.num1 = 10;
}

Outer Ec{
  변수 레코드 :{
    num2 : 20
  }
  외부 EC 변수 레코드 참조 : Global Ex의 변수 레코드 참조 👉 window 객체 주소
}

Inner Ec{
  변수 레코드 : {
    num3 : 30 //속박변수, Inner Ec 입장에서는 num2, num1 은 자유변수
  }
  외부 EC 변수 레코드 참조 : Outer EC 변수 레코드 주소 👉 Outer의 num2값을 가져올수있음.
}

상위객체에 접근할수있는 이유가 유효범위 체인(Scope) 을통해 상위객체의 주소를 참조하기 때문에 상위객체로 한단계씩 접근이 가능하다.

1) 호이스팅

함수가 실행되는 시점에는 지역 변수 또는 함수 선언문으로 선언한 함수 이름이 함수를 평가하는 시점에 선언적 환경 레코드에 기록된 상태입니다. 따라서 변수 또는 함수 선언문이 함수 안의 어떤 부분에 위치하더라도 함수 전체에서는 사용할 수 있습니다.

2) this바인딩

함수를 호출한 객체의 주소.

window: 

Global EC{
  변수 레코드 window 하위 속성으로 변수 레코드 구성
  window.num1 = 10;
  this 바인딩 : window 객체의 주소
}

Outer Ec{
  변수 레코드 :{
    num2 : 20
  }
  외부 EC 변수 레코드 참조 : Global Ex의 변수 레코드 참조 👉 window 객체 주소
  this 바인딩 : 함수를 호출한 객체의 주소
}

Inner Ec{
  변수 레코드 : {
    num3 : 30
  }
  외부 EC 변수 레코드 참조 : Outer EC 변수 레코드 주소 👉 Outer의 num2값을 가져올수있음.
}

this는 호출할 때 this의 값이 결정된다
함수를 정의한다고 해도 this 값은 결정 ❌ 👉 실행 👉 EC 구성시 this값이 결정(호출한 객체의 주소값)
add는 전역변수이기 때문에 this의 값은 window이다.

function add(){
  console.log(this);
}
add();
const person = {name : "이이름", age : 40};
person.add = add;
person.add === add() // true
person; //? {{name : "이이름", age : 40, add:f};
add(); // this의 값은 window
person.add; // this의 값은 person

7. 자바스크립트는 싱글 스레드

  • 쓰레드 : 작업메서드 + 호출스택
  • 초기 자바스크립트는 부가적인 기능 수행을 위해서 만들어진 언어 (브라우저의 자원 소비 적게 설계)
  • 동시성 작업을 여러 쓰레드를 생성하여 진행 ❌
  • 이벤트 주도 비동기 방식 👉 동시성 작업 보완

8. 클로저

반환값이 함수객체이기 때문에
function(num2) 함수객체의 주소를 반환한다. 그렇기때문에 num2값에 20이 들어간다.
add2가 add(10)을 참조하기 때문에 힙영역에있는 10은 삭제가 되지않고 영역에 남아있다.
num1의 10이 function(num2)에 속박되어있기 때문에 클로저라고한다.

function add(num1) {
  return function(num2){
    return num1 + num2;
  };
}
const add2 = add(10); //add2 에는 function(num){return num1+ num2}의 주소값을 받는다.
add2(20); //> 30

고차원함수

고차원함수와 팩토리함수는 클로저가 있기 때문에 가능
클로저로 인해 값들이 계속 유지중이고 스코프를 통해 값들이 끊겨있지 않기 때문에 고차원으로 함수가 가능하다.

function add(num1){
  return function(num2){
    return function(num3){
      return num1 + num2 + num3;
    }
  }
} 

const add = num1 => num2 => num3 => num1+num2+num3;
add(10)(20)(30);
//>60

### 팩토리함수
>클로저로 인해 계속해서 함수를 생성할수있다.
```js
function add(num1) {
  return function(num2){
    return num1 + num2;
  };
}
const add2 = add(10); //새로운 함수 생성
const add3 = add(20); //새로운 함수 생성
const add4 = add(30); //새로운 함수 생성
add2(20); //> 30

9. 이름 공간

1) 전역 이름 공간의 오염

var : 지역 - 함수 지역
호이스팅으로 인해 전역 이름 공간 오염 👉 전역변수 사용 지양

var i = 100; //매우 중요한 숫자
var i = 10; 
i; //> 10으로 나옴
var i = 100; //매우 중요한 숫자
for( var i = 0 ; i < 10; i++){
  
}
i; // > 10

이를 해결하기 위해 let,const 탄생
let : 변수 선언자
const : 상수 선언자
👉 지역범위{...}로 변경

let i = 100;
{
  let i = 10;
}
console.log(i) //> 100
let i = 100;
for(let i = 0; i < 10; i++){
}
console.log(i); //> 100
const str = 'abc;
str = 'def'; //오류가 발생 const는 상수이기때문에 값 변경이 불가능.

변수는 const로 정의하고, 변경이 필요한 경우만 let으로 선언

2) 객체명 이름 공간으로 활용하기

kakao.maps ...

var chj = chj ?? {}
chj.popup = {
	show(){
    },
    close(){
    }
}

chj.popup.close();

3) 함수명 이름 공간으로 활용하기

즉시실행 함수, 모듈 패턴

const order = (function() {
  const orderNum = 100;
  
  return {
    getNum(){
      return orderNum;
    }
  };
})();

10. 생성자

상속

1) 객체간의 상속, 프로토타입 기반 상속(프로토타입 체인 연결)
2) 프로토타입 체인의 연결 관계로 상속을 나타낸다.
[[Prototype]] 프로토타입 체인
__proto__ : 프로토타입 체인 변경 👉 호환성문제가 존재 👉 Object.setPrototypeOf(...) 프로토타입 체인 연결

const objA = {a:1, b:2};
const objB = {c:3, d:4};
objB.setPrototypeOf(objB, objA);
objB; //{a:1, b:2} {c:3, d:4}

생성자 함수 객체 👉 객체 생성 과정은 함수 객체의 prototype 객체의 상속 과정!

function Person(){
  this.name = "이이름";
  this.age = 40;
}

const p1 = new Person(); //Person.prototype 상속관계

3) 생성자 함수의 this를 생성할 객체를 변경하고 호출함으로서, 값의 초기화

function Person(){
  this.name = "이이름";
  this.age = 40;
}

Person(); // this는 window
name; //window.name 
age; //window.age
function Person(){
  this.name = "이이름";
  this.age = 40;
}

const p1 = {}
Person.apply(p1);//Person의 this값을 p1으로 변경 (p1이 Person을 호출)
p1.name;
p1.age;
profile
안녕하세요!

0개의 댓글