연습문제(18-1) 출석부 인사 함수

18강에서 goodMorningAllArray 함수와 마찬가지로 출석부의 이름들에게 인사를 하는 함수를 만들어 봅시다. 단, 이번에는 출석부의 마지막 이름을 먼저 인사하고, 출석부의 첫번째 이름을 제일 마지막으로 인사합니다.

출석부의 이름은 다음과 같습니다.

var studentNames = ["이수현", "김수민", "아무개3", "아무개4", "아무개5", "아무개6", "아무개7", "아무개8", "아무개9", "아무개10"];

18강의 goodMorningAllArray 함수를 참고하지 않고 위 함수 만들기에 도전해 보세요.

변수를 사용하여 어떠한 데이터를 기록하고 사용할 수 있음을 우리는 이미 배웠습니다. 어떠한 출석부가 있는데, 여기에 있는 첫번째 학생의 이름인 '이수현'을 변수에 저장해 봅시다.

var studentName = "이수현";

두번째 학생의 이름은 '김수민'입니다. 이 이름도 변수를 선언하여 대입해봅시다.

var studentName2 = "김수민";

studentName이라는 변수는 이미 사용했으므로, 뒤에 2를 붙여 새로운 변수를 만들었습니다.

출석부에는 총 10개의 이름이 있습니다. 그럼 총 10개의 변수를 사용해야겠네요.

아래와 같이 학생들에게 인사를 하는 함수가 있습니다.

function goodMorning(name){
  console.log("Good Morning, "+name+"!");
}

위 함수를 써서 출석부의 모든 학생에게 인사를 하는 함수를 작성해 봅시다.

function goodMorningAll(){
  goodMorning(studentName);
  goodMorning(studentName2);
  goodMorning(studentName3);
  goodMorning(studentName4);
  goodMorning(studentName5);
  goodMorning(studentName6);
  goodMorning(studentName7);
  goodMorning(studentName8);
  goodMorning(studentName9);
  goodMorning(studentName10);
}

이렇게 만들어진 함수는 유지 보수에 치명적인 결함이 있는데, 출석부 상의 학생 수가 변경되면 위 함수는 재사용할 수 없게 되어 버립니다. 코드를 수정해서 사용하여야 하죠.

예를들어 학생 수가 12명으로 늘어난다면 goodMorningAll함수에 goodMorning함수를 2번 더 작성해야 합니다.

이러한 문제를 해결하기 위해 나온 것이 배열입니다.

배열(Array)

데이터를 모아 하나의 변수에 담을 수 있는 것이 배열입니다. 변수가 데이터를 하나만 담을 수 있다면, 배열은 여러개의 데이터, 혹은 한개의 데이터 혹은 0개의 데이터를 담을 수 있습니다.

문자열, 숫자, Boolean등과 마찬가지로, 배열도 데이터타입(자료형)의 한 종류입니다. 다만, 다른 데이터들을 담고 좀 특별한 데이터타입이죠. 배열은 대괄호([])를 써서 나타내고, 배열안의 데이터들은 쉼표(,)를 사용해 구분합니다. 위 출석부의 이름들을 배열로 나타내면 아래와 같이 나타낼 수 있습니다.

["이수현","김수민","아무개3","아무개4","아무개5","아무개6","아무개7","아무개8","아무개9","아무개10"]

변수에 대입

배열 역시 데이터이므로 변수에 담겨져야지만 재사용할 수 있습니다. 위 출석부 이름들을 변수에 담아봅시다.

var studentNames = ["이수현", "김수민", "아무개3", "아무개4", "아무개5", "아무개6", "아무개7", "아무개8", "아무개9", "아무개10"];

studentNames은 변수지만 배열을 담고 있으므로, 배열이라고 부르기도 합니다. 정확히는 배열이 대입된 변수라고 할 수 있지만, 일반적으로 그냥 배열이라고 부릅니다.

console.log를 사용해서 studentNames 데이터를 출력해 봅시다.

console.log(studentNames);
// (10) ["이수현", "김수민", "아무개3", "아무개4", "아무개5", "아무개6", "아무개7", "아무개8", "아무개9", "아무개10"]

배열 전체 데이터가 출력됩니다. 왼쪽에 (10)이라고 표시되는 부분은 해당 배열 속 데이터의 수입니다.

아래와 같은 형태로 배열속 데이터 중 하나의 값만 선택할 수 있습니다.

배열_이름[배열_번호]

이때 배열 번호는 0번부터 시작합니다. 첫번째 데이터인 "이수현"을 선택하고 싶다면, student[0]을 사용합니다.

console.log(studentNames[0]);
// 이수현

첫번째 데이터를 선택할 때 1이 아닌 0을 선택하는 것에는 이유가 있습니다. 배열이 처음 도입되었을 때 데이터는 메모리에 아래와 같은 형태로 저장되었습니다.

  0          1          2          3          4                  
  |----------|----------|----------|----------|----------|
  | data1    | data2    | data3    | data4    | data5    |
  |----------|----------|----------|----------|----------|
  ^
  배열 데이터의 시작 주소

studentNames이라는 변수는, 배열 데이터의 시작 주소이자 동시에 배열의 첫번째 데이터의 주소인 곳을 표시하게 되고, 그곳에서 몇 번째 떨어진 곳인지를 나타내는 숫자를 []안에 적은 것입니다.

즉 studentNames[1]은 studentNames의 1번째 데이터를 나타내는 것이 아닌, 메모리상의 studentNames 주소에서 1번째 떨어져 있는 곳의 데이터 - studentNames의 2번째 데이터를 뜻합니다.

이 부분은 제대로 이해하려면 내용이 꽤 복잡하기 때문에 최대한 단순하게 설명하였습니다. 정 이해가 안되시면 그냥 변수를 선택할 때 n번째 데이터는 n-1로 선택한다고 외우시면 되겠습니다.

배열의 길이

배열_이름.length

를 사용하여 배열의 길이를 알 수 있습니다.

console.log(studentNames.length);
//10

배열의 1번째 데이터는 [0]를 사용해서 선택할 수 있고, 배열의 마지막 데이터는 [배열_길이-1]를 사용하여 선택할 수 있으므로, studentNames의 마지막 데이터를 선택하려면

studentNames[studentNames.length-1]

를 사용하면 됩니다. 물론 길이가 10인 것을 알고 있으면 studentNames[9]라고 하면 되지만, 위와 같이 작성하면 studentNames데이터의 길이가 바뀌더라도 언제나 마지막 값을 가질 수 있습니다.

지금까지 배운 배열에 대한 내용과 반복문을 사용하여 길이가 일정하지 않은 학생 이름 배열의 모두에게 인사를 하는 함수를 만들어 봅시다.

function goodMorningAllArray(names){
  for(var i=0; i<names.length; i++){
    goodMorning(names[i]);
  }
}

i의 초기값은 배열의 첫번째 값을 선택하기 위해 0이고, 배열의 다음 값을 선택하기 위해 반복후 매번 i++를 실행하며, for문의 조건은 i<names.length 로 하여 i의 마지막 값이 names.length-1이 되도록 하였습니다.

goodMorningAllArray(studentNames)

로 모든 학생들에게 인사를 할 수 있습니다.

함수 선언(Function Declarations)

지금까지 함수를 선언할 때 아래와 같은 방식으로 선언했었습니다.

function sayHello(){
  console.log("hi!");
}

이 방식을 함수 선언(Function Declarations)이라고 합니다.

함수 표현(Function Expressions)

첫번째 방식과는 다르게 아래와 같이 함수를 선언할 수도 있습니다.

var sayHello2 = function(){
  console.log("hi!2");
}

변수에 함수를 담는 모양이 되었는데, 이 방식을 함수 표현(Function Expressions)이라고 합니다.

함수 선언과 함수 표현의 차이점

함수 선언으로 생성된 함수든, 함수 표현으로 생성된 함수든, 함수의 호출 방법은 같습니다. 둘의 차이점은 브라우저가 코드를 받아드리는 방식에 차이인데, 아래 코드를 복사해서 실행해봅시다.

sayHello();

function sayHello(){
  console.log("hi!");
}

함수 선언전에 함수를 먼저 호출했으므로 실행이 안될 것 같지만, 실행이 됩니다! 이는 코드 해석기가 함수 선언부를 찾아서 먼저 적용한다음 나머지 코드들을 실 행시키기 때문입니다.

반면에 함수 표현은 반드시 함수 호출 전에 이루어져야 합니다.

sayHello2();

var sayHello2 = function(){
  console.log("hi!2");
}

위 코드를 실행하면 sayHello2함수를 찾을 수 없다는 에러가 납니다.

아래 코드를 실행하면 어떤 값이 나올 지 생각해 봅시다.

var a=1;

function printA(){
  console.log(a);
}

printA();

변수 a를 선언하여 1을 대입하였고, printA함수는 a를 출력하므로 1이 출력됩니다.

하지만 아래와 같이 변수 선언을 함수 안에서 했다면, 함수 밖에서는 해당 변수를 호출할 수 없습니다.

function printB(){
  var b=2;
  console.log(b);
}

printB();
console.log(b);

위 함수를 실행하면 printB에 의해서 2가 출력되지만, 함수 밖의 console.log(b)는 'b is not defined'라는 에러를 냅니다.

b는 함수 안에서 선언되었으므로, 함수 밖에서 b를 호출하려고 하니 b가 뭔지 모르겠다 라고 하는 에러입니다.

만약 변수가 함수 안에도 있고 밖에도 있으면 어떨까요?

var c=3;

function printC(){
  var c=4;
  console.log(c);
}

printC();
console.log(c);

printC()는 함수 안의 c의 값인 4를 출력하고, console.log(c);는 함수 밖의 c의 값인 3을 출력합니다.

이것은 함수 밖의 c와 함수 안의 c의 스코프(scope)가 다르기 때문입니다. scope는 범위라는 뜻으로, 여기에서는 변수의 적용 범위라는 뜻으로 생각하면 되겠습니다. 함수 안에서 생성된 변수는 지역 변수(local variable)이라고 하고 적용범위가 함수 안으로만 한정이 됩니다. 함수 밖에서 생성된 변수 전역 변수(global variable)이라고 하며 어디서든 호출할 수 있습니다. 변수 이름이 전역 변수에도 해당하고 지역 변수에도 해당하는 경우, 지역 변수가 우선 호출됩니다.

var d=5;

function someFunc1(){
  var e=6;
  // 어떤 일을 하는 코드
}

function someFunc2(){
  var f=7;
  // 어떤 일을 하는 코드
}

위와 같은 코드가 있을 때, d는 전역변수로 someFunc1안이나, someFunc2안에서도 호출될 수 있습니다. 하지만 e는 someFunc1 함수의 스코프에 있기 때문에, 자신의 스코프 밖인 함수 밖이나 someFunc2에서는 호출될 수 없습니다. 마찬가지로 f도 같은 이유로 함수밖이나 someFunc1에서 호출될 수 없습니다.

+ Recent posts