728x90
728x90

제어구문은 프로그램의 처리흐름을 제어하는 문장으로 알고리즘에 담긴 논리를 표현하고 본격적으로 프로그램을 만들 수 있습니다. 

 

 

 

 

1. 제어구문


순차적 실행

일반적으로 문장은 위에서부터 아래방향으로 순서대로 실행됩니다. 순차적 실행 흐름을 변화시키는 문장을 제어 구문이라고 하며, JS에서는 아래와 같은 제어 구문이 있습니다. 

 

분류 제어 구문 설명
조건문 if/else, switch, try/catch/finally 조건에 따라 처리를 분기
반복문 while, do/while, for, for/in, for/of 조건 만족 시 처리 반복 실행
점프문 break, continue, return, throw 프로그램의 다른 위치로 이동

 

 

 

2. 조건문


조건문은 조건식의 값에 따라 실행 흐름을 분기합니다.

 

if/else 문

true면 문장 1, false면 문장 2 를 실행합니다. 조건식의 소괄호는 꼭 입력해야 합니다. if 문 안에 if 문을 중첩해서 쓸 수 있고, if else if {} else if {} .... else {} 와 같이도 쓸 수 있습니다.

사용법 1 if (조건식) 문장
사용법 2 if (조건식) 문장 1 else { 문장 2 }

 

switch 문

if/else 문은 표현식의 값에 따라 실행을 분기할 때 사용합니다. 분기점 여러개를 구현하고자 할 때 switch 문을 사용하면 더 간결해집니다. 대괄호 안에 default : 실행문 + 1 (문장) 을 넣으면 어느 case 에도 속하지 않을 때 실행할 문장입니다. 

 

switch (표현식) { 
	case 표현식 1 : 실행문 1 ( 문장 ) 
	case 표현식 2 : 실행문 2 ( 문장 ) ... 
	case 표현식 n : 실행문 n ( 문장 ) 
	default: 실행문n + 1 (문장)
}

 

 

 

 

 

3. 반복문


반복문은 일정한 처리를 한 후 원래 위치로 돌아가 같은 처리를 반복합니다. for/of 문은 8단원에서 더욱 자세히 설명합니다.

 

while 문

조건만 맞으면 일정한 처리를 계속 반복해 실행합니다. 가장 먼저 조건식을 평가한 후 결과가 false면 문장을 나와 다음 처리를 시작하며 true이면 문장을 실행 후 다시 시작 부분으로 돌아가서 평가하기를 반복합니다. 문장 내에서 break 를 실행하면 문장에서 빠져나오며, continue를 실행하면 시작 부분으로 돌아갑니다.

 

while (조건식) 문장

 

예제 : 순차 검색 (배열 a에서 x값과 같은 요소를 찾아내기 = 선형검색)

function linearSearch(x, a) {
  var i = 0;
  var n = a.length;

  while (i < n && x > a[i]) i++;

  if (x == a[i]) return i;

  return null; // x와 같은 값이 없으면
}

var a = [2, 4, 7, 12, 15, 21, 34, 35, 46, 57, 70, 82, 86, 92, 99];
console.log(linearSearch(35, a));  // 7

 

선형검색 vs 이진검색

이진검색 : 정렬된 배열에서 가운데 요소의 값을 기준으로 반을 나눈 후 둘 중 어디에 검색할 값이 저장되어있는지 예측하는 것을 재귀적으로 반복해 나가는 방법. 

 

function binarySearch(x, a) {
	var n = a.length;
	var left = 0, right = n-1;
	while(left<right) {
		var middle = Math.floor((left+right)/2);
		if(x<=a[middle]){
			right = middle;
		}else{
		left = middle + 1;
		}
	}
	if(x==a[right]) return right;
	return null;
}

var a = [2, 4, 7, 12, 15, 21, 34, 35, 46, 57, 70, 82, 86, 92, 99];
console.log(binarySearch(35, a));  // 7

 

 

 

do/while 문

문장 먼저 실행한 후, 반복해서 실행할 지를 마지막 부분에서 판단합니다. break문과 continue 문을 사용할 수 있습니다.

 

do 문장 while (조건식);

 

 

 

for문

소괄호 안에서 반복 조건의 초기화, 반복문의 조건식, 반복조건 갱신 작업을 한번에 표기합니다. for문 안에 for문을 작성하여 중첩 반복문을 만들 수도 있습니다.

 

for (초기화 식; 조건식; 반복식) 문장
// 피타고라스의 수 구하기
var n = 20;
for(var a=1; a<=n; a++){
	for(var b=1; b<=n; b++){
		for(var c=1; c<=n; c++){
			if(a*a + b*b == c*c) {
				console.log(a + "^2+" + b + "^2=" + c + "^2");
			}
		}
	}
}

 

 

 

for/in 문

객체 안의 프로퍼티를 순회합니다. 실행되면 먼저 객체 표현식을 평가하고, null 또는 undefined로 평가되면 for/in문을 빠져나와 다음 작업으로 이동합니다. 객체표현식이 객체로 평가되면 객체의 프로퍼티 이름이 변수에 할당되고 각각의 프로퍼티에 대해 문장이 한 번씩 실행됩니다.

 

for (변수 in 객체표현식) 문장
var obj = {a:1, b:2, c:3};
for(var p in obj) {
	console.log("p=" + p);
}
// "p=a" "p=b" "p=c"

 

각 프로퍼티의 이름을 "a", "b", "c"라는 문자열로 바꾸어 변수 p에 대입하는 문장이 실행됩니다.  프로퍼티 이름이 아니라 프로퍼티 값을 가지고 오려면 괄호 연산자를 사용합니다. 반복문 내에서 문장을 여러개 실행하려면 여러 문장을 블록으로 묶어 블록문으로 만듭니다. for/in문 내에서도 break/continue 문을 쓸 수 있습니다. 

 

var obj = {a:1, b:2, c:3};
for(var p in obj) {
	console.log("obj." + p + "=" + obj[p]);
}
// "obj.a=1" "obj.b=2" "obj.c=3"

 

 

 

 

4. 점프문


프로그램의 다른 위치로 이동합니다. break, continue, return, throw 문이 있습니다. 문장에 라벨을 붙이면 break문이나 continue문 실행 후 점프할 수 있는 위치가 됩니다. 

 

라벨문

JS에서는 모든 문장에 라벨을 붙일 수 있습니다. 라벨 이름에는 모든 식별자를 사용할 수 있습니다. JS에서는 라벨로 점프할 수 있는 문장은 break, continue문 뿐입니다. break문은 switch문과 반복문 안에서만 사용할 수 있고 continue문은 반복문 안에서만 사용할 수 있습니다. --> 라벨을 붙여 사용할 수 있는 문장은 switch문과 반복문

 

라벨이름 : 문장
loop: while(true){
	if(confirm("종료할건가?")) break loop;
}

 

 

break 문

break문은 switch문과 반복문 안에서만 사용할 수 있습니다. 실행하면 가장 안쪽의 반복문이나 switch문에서 빠져나옵니다. 점프할 라벨을 지정할 수도 있습니다. 라벨을 지정한 break문을 실행하면 라벨이 붙은 문장 끝으로 점프하며, break문에서 지정한 라벨이 없으면 문법 오류가 발생합니다. 라벨을 지정한 breka문은 switch, 반복문에서 사용할 수 있으며 라벨을 지정한 모든 문장에서 사용할 수 있습니다.

 

break 라벨 이름;
// 두 배열에서 같은 값을 가진 요소를 발견하면 전체 반복문에서 빠져나오는 코드

var a = [2, 4, 6, 8, 10],  b = [1, 3, 5, 6, 9, 11];

loop: for (var i = 0; i < a.length; i++) {
  for (var j = 0; j < b.length; j++) {
    if (a[i] == b[j]) break loop; // 라벨을 지정하여 전체 반복문을 빠져 나옴
  }
}

console.log("a[" + i + "] = b[" + j + "]"); //"a[2] = b[3]"

 

라벨을 지정한 break문은 주로 중첩반복문의 안쪽 반복문에서 전체 반복문을 빠져나올 때 사용합니다.

또한 break문과 라벨 이름 사이에 줄 바꿈 문자를 넣지 않도록 유의합니다. 들어갔을 시 아래와 같은 오류가 납니다. (엔진이 자동으로 세미콜론을 추가하여 라벨을 지정하지 않은 break문으로 해석)

 

"<a class='gotoLine' href='#31:5'>31:5</a> Uncaught ReferenceError: loop is not defined"

 

 

 

continue 문

continue문을 실행하면 반복문 실행을 멈추고 반복을 새로 시작합니다. continue문에도 점프할 라벨을 지정할 수 있으며, continue 문은 라벨 지정 여부와 관계없이 반복문 안에서만 사용할 수 있는 것이 break문과 차이점입니다. 표와 같이 반복문에 따라 동작이 달라집니다.

 

continue;
continue 라벨 이름;

 

while 반복문의 처음으로 되돌아가서 조건식을 재평가. true면 처음부터 반복문 실행
do/while 중간을 건너뛰고 반복문의 마지막 조건식을 평가. true면 처음부터 반복문 실행
for 반복식 실행 후 조건식 평가. true면 반복문 이어서 실행
for/in문 반복문의 처음으로 되돌아가서 지정한 변수에 할당된 프로퍼티의 다음 프로퍼티를 대상으로 작업 시작

 

 

 

 

 

5. 응용예제 - 암호 원판 만들기


원판 암호는 알베르티의 발명품으로 바깥쪽 원판은 고정형, 안쪽 원판은 회전형으로 원판을 활용해서 암호문으로 치환할 수 있습니다. 예제로 암호 생성기 객체를 반환하는 함수 (객체 팩토리) 를 사용해서 만들어보겠습니다. 

 

객체 팩토리 Encryptor 함수

 

function Encryptor(){
	var obj = {}; return obj;
}

 

기본형은 위와 같고, 바깥쪽 원판의 문자 집합을 chars 프로퍼티에 배열로 저장합니다. 알파벳은 for문을 사용해서 배열에 추가합니다.

 

function Encryptor() {
  var obj = {};

  var N_ALPHABET = 26; //알파벳 문자 개수
  var extraCharactors = [" ", ".", "?", "!", "%", "#", "'", "&", "$", "@", ":", "/"]; //특수문자 배열

  obj.chars = []; //알파벳을 담을 배열

  // chars 배열에 알파벳 소문자 추가
  for (var c = "a".charCodeAt(0); c <= "z".charCodeAt(0); c++) {
    obj.chars.push(String.fromCharCode(c));
  }
	
  console.log(obj.chars); 
  // ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
  return obj;

}

Encryptor();

 

charCodeAt : index에 해당하는 문자의 unicode 값을 리턴. index - 0보다 큰 정수
fromCharCode :  UTF-16 코드 유닛의 시퀀스로부터 문자열을 생성해 반환

 

chars 배열에 소문자 추가한 것에 이어서 대문자와 숫자, 특수문자를 추가합니다.
nchars 프로퍼티에 문자 개수를 저장합니다. (62개)

 

function Encryptor() {
  var obj = {};

  var N_ALPHABET = 26; //알파벳 문자 개수
  var extraCharactors = [" ", ".", "?", "!", "%", "#", "'", "&", "$", "@", ":", "/"]; //특수문자 배열

  obj.chars = []; //알파벳을 담을 배열

  // chars 배열에 알파벳 소문자 추가
  for (var c = "a".charCodeAt(0); c <= "z".charCodeAt(0); c++) {
    obj.chars.push(String.fromCharCode(c));
  }

  // chars 배열에 알파벳 대문자 추가
  for (var c = "A".charCodeAt(0); c <= "Z".charCodeAt(0); c++) {
    obj.chars.push(String.fromCharCode(c));
  }

  // chars 배열에 알파벳 숫자추가
  for (var d = 0; d <= 9; d++) {
    obj.chars.push(d.toString());
  }

  // chars 배열에 알파벳 특수문자 추가
  for (var j = 0; j < extraCharactors; j++) {
    obj.chars.push(extraCharactors[j]);
  }

  // nchars 프로퍼티에 배열 chars에 저장된 문자 개수를 저장
  obj.nchars = obj.chars.length;
  return obj;

} 

 

 

암호화 메서드 추가

암호화할 문자 하나하나를 obj.chars 배열의 요소 번호(0~obj.chars-1 사이의 정수) 가 가리키는 문자로 바꾸는 numberOf(ch)메서드를 추가합니다. 이 메서드는 문자 ch에 있는 obj.chars 요소의 번호를 반환하며 obj.chars 안에 ch가 없다면 null을 반환합니다.

 

  // chars배열에서의 문자 ch의 요소 번호를 구하는 메서드 ( ch를 chars배열에서 찾을 수 없을 때에는 null을 반환함)
  obj.numberOf = function(ch) {
    var code = ch.charCodeAt(0);
    if (code >= "a".charCodeAt(0) && code <= "z".charCodeAt(0)) {
      return code - "a".charCodeAt(0);
    } else if (code >= "A".charCodeAt(0) && code <= "Z".charCodeAt(0)) {
      return N_ALPHABET + code - "A".charCodeAt(0);
    } else if (code >= "0".charCodeAt(0) && code <= "9".charCodeAt(0)) {
      return 2 * N_ALPHABET + code - "0".charCodeAt(0);
    } else {
      for (var k = 0; k < extraCharactors.length; k++) {
        if (ch == extraCharactors[k]) {
          return 2 * N_ALPHABET + 10 + k;
        }
      }
      return null;
    }
  };

 

원판 암호기의 암호문은 키워드가 가리키는 요소의 번호만큼 이동시켜 구합니다. shift메서드는 문자 ch를 정수 n만큼 이동시킨 문자를 반환합니다. 함수 안에서 this가 가리키는 것은 obj입니다.

numberOf 메서드를 사용해서 정수값 num을 구하고 chars 배열 안에서 num이 가리키는 문자를 구합니다. 
정수값을 n만큼 이동시킨 값이 0~obj.nchars-1의 범위 안에서 돌게끔 obj.nchars로 나눈 나머지를 구합니다. 복호화(암호화를 푸는 것)를 하면 n이 음수가 되므로 나머지를 구하기 전에 obj.nchars를 더합니다.

 

  // 문자ch를 n만큼 이동시킨 문자를 반환하는 메서드 ( ch를 chars배열에서 찾을 수 없을 때에는 null을 반환함)
  obj.shift = function(ch, n) {
    var num = this.numberOf(ch);
    
    if (num == null) return ch;
    num = (num + n + this.nchars) % this.nchars;
    
    return this.chars[num];
  };

 

encrypt 메서드는 문자열 text를 키워드 keyword로 encription값이 true면 암호화한 문자열을 반환하고 false면 복호화한 문자열을 반환합니다. 암/복호화 시 이동해야 하는 거리인 nshift를 keyword 문자로 구합니다. keyword의 몇 번째 문자를 가리키고 있는지 알려주는 숫자인 ikey 를 text 안의 문자를 하나 처리할 때마다 1씩 증가시키고, keyword의 길이인 nkey 로 나눈 나머지를 구해 0~nkey-1 안에서 돌게 합니다. encription이 true면 keyword 메서드로 구한 값 자체를 사용하고, false면 값에 -1을 곱해 반대로 돌게 합니다.

 

 

// 원판 암호기로 암호화를 하는 메서드
//   text: 암호화 / 복호화를 할 문자열
//   keyword: 키워드
//   encription: true 면 암호화, false면 복호화
            
obj.encrypt = function(text, keyword, encription) {
    var cipherText = "";
    var nkey = keyword.length;
    
    for (var i = 0, ikey = 0; i < text.length; i++, ikey++) {
      ikey %= nkey;
      var nshift = this.numberOf(keyword[ikey]);
    
    if (!encription) nshift *= -1;
      cipherText += this.shift(text[i], nshift);
    }
    
    return cipherText;
};

 

일반문과 암호문을 입력받는 html 폼을 만들어 JS와 연결합니다. 

 

 

 

완성본

 

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>원판 암호기</title>
	<script>
        window.onload = function() {
            var enscriptor = Enscriptor();
			// 평문을 암호화
            document.getElementById("cipher").onclick = function() {
                var keyword = document.getElementById("keyword").value;
                var plaintext = document.getElementById("plaintext").value;
                var ciphertext = document.getElementById("ciphertext");
                ciphertext.value = enscriptor.encrypt(plaintext,keyword,true);
            };
			// 암호문을 복호화
            document.getElementById("decipher").onclick = function() {
                var keyword = document.getElementById("keyword").value;
                var plaintext = document.getElementById("plaintext");
                var ciphertext = document.getElementById("ciphertext").value;
                plaintext.value = enscriptor.encrypt(ciphertext,keyword,false);
            };
        };
		/*
		 * 함호기 객체를 생성하는 팩토리 함수
		 *   obj.chars: 원판에서 사용할 문자 배열
		 *   obj.nchars: 원판에서 사용하는 문자 배열의 길이 ( chars의 길이 )
		 *   obj.numberOf(ch): 문자 ch가 배열 chars의 몇 번째 요소인지를 반환하는 메서드
		 *   obj.shift(ch,n): 문자 ch를 n만큼 이동시켰을 때 가리키는 chars 배열의 요소
		 *   obj.encrypt(text,keyword,encription): 원판 암호기로 암호화 / 복호화 하는 메서드
		 */
        function Enscriptor() {
            var obj = {};
            var N_ALPHABET = 26;	// 알파벳 문자의 개수
            var extraCharactors = [" ",".","?","!","%","#","'","&","$","@",":","/"];
			// 특수문자 배열
            obj.chars = [];
			// chars 배열에 알파벳 소문자와 대문자를 추가
            for(var c="a".charCodeAt(0); c<="z".charCodeAt(0); c++) {
                obj.chars.push(String.fromCharCode(c));
            }
            for(var c="A".charCodeAt(0); c<="Z".charCodeAt(0); c++) {
                obj.chars.push(String.fromCharCode(c));
            }
			// chars 배열에 숫자를 추가
            for(var d=0; d<=9; d++) {
                obj.chars.push(d.toString());
            }
			// chars 배열에 특수문자를 추가
            for(var j=0; j<extraCharactors.length; j++) {
                obj.chars.push(extraCharactors[j]);
            }
			// chars 배열의 길이
            obj.nchars = obj.chars.length;
			// chars배열에서의 문자 ch의 요소 번호를 구하는 메서드 ( ch를 chars배열에서 찾을 수 없을 때에는 null을 반환함)
            obj.numberOf = function(ch) {
                var code = ch.charCodeAt(0);
                if( code>="a".charCodeAt(0) && code<="z".charCodeAt(0)) {
                    return code - "a".charCodeAt(0);
                } else if(code>="A".charCodeAt(0) && code<="Z".charCodeAt(0)) {
                    return N_ALPHABET + code - "A".charCodeAt(0);
                } else if(code>="0".charCodeAt(0) && code<="9".charCodeAt(0)) {
                    return 2*N_ALPHABET + code - "0".charCodeAt(0);
                } else {
                    for(var k=0; k<extraCharactors.length; k++) {
                        if( ch == extraCharactors[k] ) {
                            return 2*N_ALPHABET + 10 + k;
                        }
                    }
                    return null;
                }
            };
			// 문자ch를 n만큼 이동시킨 문자를 반환하는 메서드 ( ch를 chars배열에서 찾을 수 없을 때에는 null을 반환함)
            obj.shift = function(ch,n) {
                var num = this.numberOf(ch);
                if( num == null ) return ch;
                num = (num + n + this.nchars)%this.nchars;
                return this.chars[num];
            };
			// 원판 암호기로 암호화를 하는 메서드
			//   text: 암호화 / 복호화를 할 문자열
			//   keyword: 키워드
			//   encription: true 면 암호화,false면 복호화
            obj.encrypt = function(text,keyword,encription) {
                var cipherText = "";
                var nkey = keyword.length;
                for(var i=0, ikey=0; i<text.length; i++, ikey++) {
                    ikey %= nkey;
                    var nshift = this.numberOf(keyword[ikey]);
                    if(!encription) nshift *= -1;
                    cipherText += this.shift(text[i],nshift);
                }
                return cipherText;
            };
            return obj;
        }
	</script>
	<style>
		p { font-size:
				smaller; }
		input { height:
				20px; }
		#plaintext,#ciphertext { width:
				500px; }
	</style>
</head>
<body>
    <h2>원판 암호기를 활용한 암호화</h2>
    <p>키워드 : <input type="text" id="keyword"></p>
    <p>평문 : <input type="text" id="plaintext"></p>
    <p>암호문 : <input type="text" id="ciphertext"></p>
    <input type="button" id="cipher" value="암호화">
    <input type="button" id="decipher" value="복호화">
</body>
</html>

 

 

gilbutITbook/006960

Contribute to gilbutITbook/006960 development by creating an account on GitHub.

github.com

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,

v