[모던JS튜토리얼] 함수
함수
- 프로그램을 구성하는 주요 구성요소. 중복 없이 유사한 동작을 하는 코드를 반복 호출
함수 선언문
function name(parameters) {
...code...
}
name();
name();
function
키워드, 함수이름, 매개변수, 함수 본문으로 이뤄진다.- 호출은
함수이름()
으로 할 수 있다.
지역 변수
- 함수 내에서 선언한 변수를 의미.
function showMesage() {
let message = "test"; // 이 변수는 showMessage함수 내부에서만 사용할 수 있다.
}
외부 변수(전역변수)
- 함수 내부에서 함수 외부의 변수에 접근하고, 수정할 수 있다.
let message = "test1";
function showMessage() {
alert(message);
message = "test2";
alert(message);
}
- 외부 변수와 같은 이름의 내부변수가 있다면, 외부변수는 사용되지 않는다.
let message = "test1";
function showMessage() {
let message = "test2";
alsert(message);
}
매개변수(인수)
- 함수 안에 임의의 데이터를 전달.
function showMessage(from, to) {
alert(from + ":" + to);
}
showMessage("Ann", "hello");
showMessage("Ann", "whats up?");
- 함수에 매개변수를 전달하면 해당 값이 함수 내부에서 지역변수에 할당된다.
- 따라서 매개변수의 변경은 함수 외부에 영향을 주지 않는다.
function showMessage(from, text) {
from = "*" + from + "*"; // "from"을 좀 더 멋지게 꾸며줍니다.
alert(from + ": " + text);
}
let from = "Ann";
showMessage(from, "Hello"); // *Ann*: Hello
alert(from); // Ann
기본값
- 매개변수를 지정했으나, 값이 전달되지 않으면
undefined
이다. - 매개변수가 전달되지 않을때 사용될 기본값을 설정할 수 있다.
function showMessage(from, text = "no text given") {
alert(from + ":" + text); //text = no text given
}
showMessage("Ann"); //매개변수 1개만 전달
- JS는 함수를 호출할때마다 함수의 매개변수 기본값을 평가한다.
function showMessage(from, text = anotherfunction()) {
//anotherfunction은 text가 없을때 호출된다.
}
-
함수 내부에서 기본값 설정
- 조건문으로 설정
function showMessage(from, text) { if (text == undefined) { text = "빈문자열"; } }
- 논리 연산자로 설정
function showMessage(from, text) { text = text || "빈 문자열"; }
- nullish 병합 연산자로 설정
function showMessage(from, text) { text = text ?? "빈 문자열"; }
반환 값
-
함수 호출 시, 특정 값을 반환하게 할 수 있다.
return
을 만나면 함수는 즉시 중단, 값을 반환한다.return
값이undefined나 없는 경우
엔 undefined를 반환한다.return
문 끝에 세미콜론을 자동으로 넣어주므로, 반환값은 괄호로 묶어 사용해야한다.
function showMovie(age) {
if (!checkAge(age)) {
return; //undefined
} else {
alert("영화 상영");
}
}
함수 이름짓기
- 처음 코드를 보더라도, 함수가 어떤 역할을 하는지 확인할 수 있게 하기위함
- show… : 보여주는 역할
- get… : 값을 반환
- calc… : 계산
- create… : 생성
- check… : 확인하고 불린값 반환
- 함수 하나는 동작 하나만 할 수 있어야한다.
- 독립적인 동작은 다른 함수를 만들어서 호출하도록 해야한다.
함수 표현식
- 지금까지 표현한 함수는
함수선언식
function sayHi() { alert("Hello"); }
- 자바스크립트는 함수를 특별한 값으로 취급한다.
- 이에따라, 변수에 함수를 할당할 수 있다.
- 이렇게 만드는 함수를
함수표현식
이라고 한다.
let sayHi = function () {
alert("Hello");
};
이렇게 함수가 할당된 변수 sayHi
는 함수를 호출할 수도있고, 값을 가진 변수의 역할도 한다.
alert(sayHi); //함수 코드가 보임.
sayHi(); //함수가 실행됨.
let func = sayHi;
func(); //함수가 실행됨
콜백함수
-
함수를 함수의 인수로 전달하고, 인수로 전달한 그 함수를 나중에 호출하는 것.
function ask(question, yes, no) { if (confirm(question)) yes(); else no(); } function showOk() { alert("동의하셨습니다."); } function showCancel() { alert("취소 버튼을 누르셨습니다."); } // 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨 ask("동의하십니까?", showOk, showCancel);
- 더 명확하게 선언하려면
익명함수
를 사용한다. -
익명함수는 ask 바깥에서 접근할 수 없는 함수가된다.
function ask(question, yes, no) { if (confirm(question)) yes(); else no(); } ask( "동의하십니까?", function () { alert("동의하셨습니다."); }, function () { alert("취소 버튼을 누르셨습니다."); } );
함수표현식과 함수선언식의 차이
- 문법
//함수가 독자적인 구문형태로 존재
function sum(a, b) {
return a + b;
}
//함수가 표현식이나 구문 구성 내부에 생성된다.(한 블럭 아래단계에 있다는 의미)
//할당표현식 let sum = 우측에 존재한다.
let sum = function (a, b) {
return a + b;
};
-
JS엔진이 함수를 언제 생성하는가
- 엔진은 스크립트 실행 전, 전역에 선언된 함수 선언문을 찾아 해당 함수를 생성한다.
- 스크립트는 함수 선언문이 모두 처리된 다음에 실행되므로 스크립트 어디에서는 사용할 수 있다.
sayHi("John"); // Hello, John function sayHi(name) { //전역공간의 함수 alert(`Hello, ${name}`); }
sayHi("John"); // error! let sayHi = function (name) { // (\*) 스크립트가 여기까지 실행되어야 함수가 생성됨 alert(`Hello, ${name}`); };
-
스코프
- 함수선언문이 코드 블록 내에 위치하면 해당 함수는 블록 어디에서든 접근할 수 있다.
- 블록 외부에선 접근할 수 없다.
let age = 16; if (age < 18) { welcome(); //(실행) function welcome() { alert("안녕!"); } welcome(); //(실행) } else { function welcome() { alert("안녕하세요!"); } } welcome(); // Error: welcome is not defined
- 블록 외부에서 함수에 접근하려면 함수 표현식을 사용해야한다.
let age = prompt("나이를 알려주세요.", 18); let welcome = age < 18 ? function () { alert("안녕!"); } : function () { alert("안녕하세요!"); }; welcome(); // 실행
화살표함수
let 함수이름 = (인수1, 인수2, 인수3) => 함수코드;
- 화살표함수는 함수를 표현하는 또 다른 방식
- 함수 본문이 1줄인 (리턴값만 명시하는) 함수는 화살표함수가 편하다.
let mul = (a, b) => a * b;
- 함수가 여러 줄인 경우에, 중괄호 안에 실행할 코드를 넣어주고, 반환값을 명시해야한다.
let mul = (a, b) => { let result = a * b; return result; };
객체
- 객체 자료형은 자료형에 상관없이 다양한 데이터를 담을 수 있다.
-
중괄호로 만들고, 키 : 값으로 구성된 프로퍼티를 담는다.
- 객체 생성은 2가지 방법이 있다.
let user = new Object(); //객체 생성문법 let user = {}; //객체 리터럴문법
리터럴과 프로퍼티
let user = {
name: "john",
age: 30,
};
-
콜론을 기준으로
키 : 값
이다. -
키는 프로퍼티 이름, 식별자라고 불린다.
-
객체의 프로퍼티 값을 읽기 위해선
점 표기법
을 사용한다.alert(user.name); alert(user.age);
-
delete
연산자로 프로퍼티 삭제 가능.delete user.age;
-
프로퍼티 이름에 공백이 들어가면 따옴표로 묶어줘야한다.
let user = { "likes birds": true, };
-
const로 선언된 객체의 프로퍼티는 수정이 가능하다.
const user = { name: "John", }; user.name = "Anne";
대괄호 표기법
공백을 포함한 프로퍼티 키는 점 표기법이 아닌, 대괄호 표기법으로 값을 읽어야한다.
let user = {
"likes birds": true,
};
alert(user.["likes birds"])
계산된 프로퍼티
- 프로퍼티 키를 동적으로 할당할 수 있다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5,
};
alert(bag.apple);
단축 프로퍼티
- 프로퍼티 값을 변수에서 받아와서 할당할 때 사용한다.
function makeUser(name, age) {
return {
name, // name: name 과 같음
age, // age: age 와 같음
// ...
};
}
프로퍼티 이름
- 객체 프로퍼티 키에 특별한 제약이 없다.
- 단,
__proto__
는 사용할 수 없다. - 프로퍼티 키는 문자열로 자동 형 변환된다.
- 대괄호 표기법으로 접근하더라도 동일하게 자동형변환된다.
let obj = {
0: "test", // == "0" : "test"
};
alert(obj["0"]);
alert(obj[0]); //같음
in 연산자
- 객체는 존재하지 않는 프로퍼티에 접근하면
undefined
를 반환한다. - in 연산자로 객체에 프로퍼티가 존재여부를 판단할 수 있다.
let user = { name: "John", age: 30 };
alert("age" in user); // user.age가 존재하므로 true가 출력됩니다.
alert("blabla" in user); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.
for ~ in 반복문
for ~ in 반복문으로 객체의 키를 순회할 수 있다.
for (let key in obj) {
실행할 코드
}
객체 정렬 방식
- 객체 프로퍼티에선 정수 프로퍼티는 자동으로 정렬되고, 나머지는 추가한 순서대로 정렬된다.
- 정수 프로퍼티는 특별한 변형없이 정수에서 왔다 갔다할 수 있는 문자열을 의미한다.(“49”, “12312”, “-1234”, “0” 등…)
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
// ..,
"1": "미국",
};
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
정렬을 막기 위해서, “+49”, “+1” 등으로 프로퍼티 키를 수정하면된다.
참조에 의한 객체 복사
- 객체를 제외한 원시타입 자료형은 값이 복사되어 할당된다.
- 객체 그 자체가 아닌, 객체가 저장된 메모리 주소에 대한 참조값이 저장된다.
- 따라서 다른 변수에 객체를 할당하면, 그 변수를 수정하면 객체도 수정된다.
let user = { name: "John" };
let admin = user;
admin.name = "Pete"; // user.name = "Pete"가 된다.
alert(user.name); //"Pete"
객체간 비교
- 객체는 참조 값을 가지므로, 같은 객체를 참조하는 변수는 일치, 동등 연산자가 true를 반환한다.
- 내용이 같더라도, 다른 참조값이라면 false를 반환한다.
let a = {};
let b = a;
let c = {}; // 독립된 두 객체
alert(a == b); //true
alert(a == c); // false
객체 복사
-
참조값을 복사하는게 아닌, 내용이 같고 독립적인 객체를 만들기 위해선
Object.assign
을 사용하면 편하다.let user = { name: "John", age: 30, }; let clone = Object.assign({}, user);
- 단, 중첩 객체인 경우, 객체의 키 값을 복사해오므로, 독립적인 객체가 같은 참조값을 가지는 키를 가지게 되는 경우가 있다.
- 이를 위해서
깊은 복사
를 해야하는데, lodash의 _.cloneDeep 메서드를 사용하거나, 알고리즘을 사용해야한다.
댓글남기기