본문 바로가기

블록체인_9기/💛 JAVASCRIPT

22강(과제X)_230405_Javascript(prototypes, debugger, Closure, 즉시 실행 함수(IIFE), iterable & iterator, reduce,

728x90

 

 

 


prototype

  • Javascript에서는 객체를 상속하기 위해서 prototype이라는 방식을 사용한다.
    • 때문에 흔히 '프로토타입 기반 언어(prototype-based language)'라고 불리기도 한다.
  • 각 객체는 상속된 속성과 메소드를 메모리에 저장해놓고 동일한 메소드는 메모리에 저장을 하고 중복저장을 피한다.
  • 생성자 함수에 메소드를 정의하지 않고 생성자 외부에 별도의 메소드를 정의해서 사용하는 방식이 프로토타입이다.
  • 모든 객체들이 메소드와 속성들을 상속받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미이기도하다.
//---------------prototype을 쓰지 않고 각 객체에 할당했을 경우 ----------------------

function Car(model, color, speed){
    this.model = model;
    this.color = color;
    this.speed = speed;
    this.accel = function(){
        this.speed -= 10;
    }
}

//생성자 함수로 동적할당해서 생성

let temp = new Car("벤츠", "흰색", 200);
let temp2 = new Car ("모닝", "검정", 200);

console.log(temp);
console.log(temp2);


function Car1(m,c,s){
    this.model = m;
    this.color = c;
    this.speed = s;
    this.speedUP = function(){
        this.speed += 10;
        return this.speed;
        
    }
}

let temp3 = new Car1("마티즈", "레드", 150);
//batter키 true값 추가
temp3.batter = true;
temp3.speedUP = function(){			//객체 temp3에 직접 speedUP 객체 생성
    this.speed +=20;
    return this.speed;
}

console.log(temp3);
temp3.speedUP();
console.log(temp3);

//이런 방식은 객체에 새 속성을 추가 할 수 있는데
//생성자 함수 원형에는 추가는 할 수 없다.
//-----------------------------------------------------------------------------------



//---------------prototype을 사용하여 생성자 함수에 할당했을 경우 ----------------------
function Car2(m,c,s){
    this.model = m;
    this.color = c;
    this.speed = s;
}

Car2.prototype.speedUP = function(){
    this.speed += 20;
    return this.speed;

}
Car2.prototype.speedDown = function(){
    this.speed -= 20;
    return this.speed;
}


let temp4 = new Car2('봉고', '검정', 100);
let temp5 = new Car2('다마스', '검정', 100);
console.log(temp4.speedUP());    //결과: 120

//생성자 함수로 만든 객체들에게 전부 메서드를 추가해야 할 경우에
//프로토 타입으로 원형에 메소드를 추가해준다.


Car2.prototype.stop = function(){	//Car2의 생성자 함수에 stop 메소드 추가
    this.speed = 0;			// stop함수는 speed 메소드의 값에 0을 대입
    return this.speed;		//초기화한 speed 메소드 값을 생성자 함수의 speed메소드에 리턴
}

console.log(temp4.stop());    //결과: 0
//-----------------------------------------------------------------------------------



//---------------prototype을 사용하여 String객체에 할당했을 경우 ----------------------

String.prototype.replaceOf = function(){
    console.log("나는 프로토 타입으로 추가됐어");
    return;
}

//문자열의 원형은 String이고
"가나다".replaceOf();

//문자열 "가,나,다"에 replace 메소드 사용으로 "가" 대신 "나"가 출력
console.log("가나다".replace("가","나"))
  • 프로토타입 객체는 자신의 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수 있고, 상속해준 객체는 또 그 상위 프로토타입 객체로 부터 메소드와 속성을 받을 수 있다. 이를 프로토타입 체인(prototype chain)이라 부른다.
    • 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간이다.
  • 때문에 상속되는 속성과 메소드들은 각 객체가 아닌 객체의 생성자의 prototype 속성에 정의되어 있다.
//----------- 프로토타입 체인 예시 ------------------------------------------

function Person(first, last, age, gender, interests) {

  // 속성과 메소드 정의
  this.first = first;
  this.last = last;
//...
}

var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);

person1.valueOf()


/*  person1.valueOf() 를 호출하면 일어나는 일
1. 브라우저는 우선 person1 객체가 valueOf() 메소드를 가지고 있는지 체크한다.
2. 없으므로 person1의 프로토타입 객체(Person() 생성자의 프로토타입)에 
	valueOf() 메소드가 있는지 체크한다.
3. 여전히 없으므로 Person() 생성자의 프로토타입 객체의 프로토타입 객체
	(Object() 생성자의 프로토타입)가 valueOf() 메소드를 가지고 있는지 체크한다.
    여기에 있으니 호출하며 끝난다.
*/
  • 프로토타입 체인에서 한 객체의 메소드와 속성들이 다른 객체로 복사되는 것이 아니다.
    • 체인을 타고 올라가며 접근을 할 뿐이다.

 

 

 


debugger

  • 디버그 기능을 호출한다.
  • visual studio code에서  해당 키워드를 사용하여 브레이크 포인트를 설정할 수 있다.
function fun(){
    for (var i = 0; i < 5; i++) {
        debugger;   // vs코드상에서 해당 키워드로 브라우저에서 브레이크 포인트를 설정할 수 있다. 
        		//개발자모드에서 확인 가능하다.
        setTimeout(() => {
            console.log(i)
            debugger;
        }, i*1000);
    }
}

 

 

 


Closure

  • 함수와 함수가 선언된 어휘적 환경의 조합이다.
  • 내부 함수에서 외부 함수의 변수에 접근할 수 있다.
  • 클로저의 개념은 함수의 외부 변수와 변수 선언을 기준으로 어디까지 변수를 활용할 수 있는지 정도를 잘 숙지하면 된다.
function fun(){
    for (var i = 0; i < 5; i++) {	//for문에서 i는 0에서 부터 시작하여 1씩 증가한다. 
    							//5이상의 값이 나오면 for문을 빠져나온다.
        setTimeout(() => {
            console.log(i)		//비동기 함수로 for문이 다 돌고나서 가장 마지막에 동작한다.
            				//때문에 해당 값은 for문을 다 돌고나서 나오는 값인 5가 출력된다.
        }, i*1000);			//for문의 값을 돌면서 i에 0,1,2,3,4의 값이 들어간다.
        
    }

    //for문 안에서 비동기 처리 함수가 호출되고 for문은 이미 다 종료되고 
    //함수가 실행되기 때문에 전부 증가한 '5'가 전부 돌아가고
    //5로 증가가 이미 되었고, 함수 스코프라 접근이 가능하기 때문에 5가 나온다.
}   
fun();  //결과: 5 5 5 5 5

블록 스코프와 함수 스코프

함수 스코프 var

  • 변수가 선언된 함수 전역에서 유효하다.
  • 함수에서 선언된 변수는 함수가 호출되고 종료되면 해제된다.

블록 스코프 let

  • 변수가 선언된 블록에서 유효하며, 블록이 종료될 때 사라진다.
function fun2(){
    // for (let i = 0; i < 5; i++) {
    //     // 해당 영역은 블록스코프이다.
    // }
    if(true){
        //var는 함수 스코프
        //함수 스코프에 선언된 것.
        var a = 45;
        //let은 블록 스코프
        let b = 50;
    }
    console.log(a); //함수스코프로, 호출이 됨  결과: 45
    // console.log(b); //블록스코프로, 에러!
}

fun2();
function fun3(){
    let value = "";
    //내부 함수에서 외부 함수의 변수를 사용
    function fun4(){
        if(value == ""){
            value = "클로저";
            return value;
        }
    }
    return fun4;
}
let closure = fun3();

let a = closure();
console.log(a); //결과: 클로저

/*---------- 실행순서 ----------------------------------------------------
(해당 실행순서는 디버거를 참고하여 작성함)
1. 12행의 closuer객체에 대입한 fun3함수 실행
2. fun3합수의 value 값을 가지고 10행의 return fun4로 이동
3. fun3함수를 벗어나 14행의 a객체에 대입한 closure 함수 실행.
4. closure객체에 fun3함수를 대입할 때 실행한 return으로 fun4 실행
5. fun4함수에서 value 값이 ""이므로 if문 실행
6. value 값에 "클로저"값 대입 후 return
7. console로 a값 출력하여 "클로저" 출력
------------------------------------------------------------------------*/

 

 

 


즉시 실행 함수(IIFE)

  • 정의되자마자 즉시 실행되는 자바스크립트 함수를 말한다.
  • 한 번 실행시키고 사용하지 않을 것 같은 변수나 코드를 즉시 실행 함수로 만들고 호출하는 방식이다.
  • 변수나 함수명이 겹치지 않고 충돌하지 않도록 사용이 가능하다.
  • 즉시실행 함수 구조는 익명함수와 비슷하게 생겼다.
    • 차이점
      • 전역에서 선언이 가능하다.
      • 괄호( )안에 작성한다는 점이다.
(function("매개변수로 사용 할 이름"){

}("전달 할 매개변수"));
(function(){
    console.log("즉시 실행 함수");
    let a = 5;
}());
console.log(a);  //결과: error!     함수 안에서만 사용하는 변수이기 때문이다.

function temp(b){
    (function(c){
        console.log(c);	//결과: 안녕 매개변수
    }(b));
}

temp("안녕 매개변수");

순서는 이렇게 되는 것이 아닐까 하고 예상한다....

 

 

 


iterable & iterator

  • 이터러블과 이터레이터는 ES6에 추가되었다.

symbol.iterator?

  • 개체의 반복자를 반환하는 메서드를 지정하는 잘 알려진 기호를 나타낸다.
  • 이터러블 객체를 나타내는 메소드 이름으로 사용한다.
  • 해당 객체가 이터러블 이라는 것이다.
  • symbol.iterator 메소드가 이터레이터 객체를 반환한다.
  • symbol?
    • ES6에 추가된 원시타입이다.
    • 값이 겹치지 않고, 선언 시에 값을 지정해주어야 한다. 선언 후에는 변경이 불가능하다. (const와 비슷하다)
    • 객체의 속성에 접근하기 위해 사용한다.

이터러블(iterable)?

  • 반복 가능한 객체라는 뜻이다.
  • 객체의 'Symbol.iterator'속성에 특정 형태의 함수가 들어있으면 이를 반복 가능한 객체, 즉 이터러블이라 부른다.
  • 이터러블은 순회할 수 있는 모든 객체가 될 수 있다.
    • 예) 배열, 문자열, 객체 등
  • 이터러블을 반복하는 반복문의 예
    • forEach: 배열을 순회하면서 아이템의 갯수만큼 아이템을 반복 실행한다.
    • for of: 이터러블의 아이템을 반복 실행한다.
    • 이 외의 등등의 예시가 있다.

이터러블의 조건

  • 순회할 수 있는 데이터를 가지고 있어야 한다.
  • Symbol.iterator 를 메소드로 가지고 있어야 한다.
    • Symbol.iterator 객체는 'iterator' 객체를 반환해야 한다.
    • iterator 객체는 반드시 next를 메소드로 가져야한다.
      • next는 순회 할 수 있는 데이터에 접근할 수 있어야 한다.
  • “iterator” 객체인 iteratorObj를 iteratorObj.next()하면 {value:<stored data},done:false} 로 순회할 수 있는 데이터가 추출 되며 전부다 순회했을 경우 {done:false} 가 반환되도록 한다.

 

이터레이터(iterator)?

  • 이터러블 객체의 각 아이템에 접근하기 위한 기능
  • 이터레이터는 이터러블(반복 가능한 객체)를 순차적으로 접근할 수 있는 기능이다.
  •  next메소드를 호출하면 {value, done: boolean} 를 반환하는 오브젝트, 객체 그 자체이다.
    • next 메소드를 사용하면 {value, done} 객체를 반환한다.
      • value: 반복 중인 아이템을 value 값에 넣어준다.
      • done: 반복이 끝났는지를 알려준다. false이면 계속 반복 진행, true이면 반복 종료
//---------------Symbol.iterator 구조를 간단히 만들어 보자---------------------------------
const Arr = [1,2,3,4,5];

const objIter = {
    index : 0,
    //next는 value와 done값을 가지고 있다.
    //done은 false일때 계속 반복하고 true일 때 반복이 끝난다.
    next : function(){
    	//해당 함수의 index가 객체 Arr 배열의 길이보다 작을 때
        if(this.index < Arr.length){
            //객체 Arr의 인덱스는 1씩 증가하고, done은 flase값을 가져 계속 반복한다.
            return {value : Arr[this.index++], done: false}
        }
        else{	//해당 함수의 index가 객체 Arr 배열의 길이보다 작지 않을 때
            //반복을 종료한다.
            return {done: true};
        }
    }
}
// 객체 result는 객체objIter의 next함수를 실행시간다.
// result.value는 index 0의 값인 1을 출력하고, result.done은 false값을 가진다.
let result = objIter.next();
console.log(result.value, result.done);  //결과: 1  false 

// result.value는 index 1의 값인 2을 출력하고, result.done은 false값을 가진다.
result = objIter.next();    //next는 다음 인덱스를 가리킨다.
console.log(result.value, result.done);  //결과: 2  false

// result.value는 index 2의 값인 3을 출력하고, result.done은 false값을 가진다.
result = objIter.next();
console.log(result.value, result.done);  //결과: 3  false

// result.value는 index 3의 값인 4을 출력하고, result.done은 false값을 가진다.
result = objIter.next();
console.log(result.value, result.done);  //결과: 4  false

// result.value는 index 4의 값인 5을 출력하고, result.done은 false값을 가진다.
result = objIter.next();
console.log(result.value, result.done);  //결과: 5  false

// index의 값이 5이므로, Arr.length와 같은 값이므로 next함수의 else를 출력
//result.value는 값을 대입하지 않아 undefined출력, result.done은 true값을 가진다.
result = objIter.next();
console.log(result.value, result.done);  //결과: undefined true
//----------------------------------------------------------------------------------------



//--------------- 이터러블 사용 예 -------------------------------------------------------
// 결과 값을 객체 타입으로 보여준다.
const Arr2 = [1,2,3,4,5];
//Symbol은 객체의 속성에 접근하는데 사용한다 했음
//객체에 소성으로 접근하는데 Symbol.iterator

//Arr2[Symbol.iterator]() 이터레이터 객체를 반환해준다.
const iter2 = Arr2[Symbol.iterator]();

let result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: 1
*/
result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: 2
*/
result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: 3
*/
result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: 4
*/
result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: 5
*/
result2 = iter2.next();
console.log(result2);
/* 결과: 
Object
done: false
value: undefined
*/

 

 


reduce

  • 배열의 각 요소에 대해 주어진 reducer함수를 실행하고, 하나의 결과값을 반환한다.
  • reduce 메소드에는 누산기가 포함되어 있기 때문에, 배열의 각 요소에 대해 함수를 실행하고 누적된 값을 출력할 때 용이하다. 
arr.reduce(callback[, initialValue])
  • 문법
    • callback : 배열의 각 요소에 대해 실행할 함수이다. 4가지의 인수를 가진다.
      • accumulator: 누산기. 콜백의 반환값을 누적한다. 콜백의 이전 반환값 또는 콜백의 첫 번째 호출이 발생하면서 initialValue를 제공한 경우에는 initialValue의 값이다.
      • currentValue: 처리할 현재 요소이다.
      • currentIndex (Optional): 처리할 현재 요소의 인덱스이다. initialValue을 제공한 경우에는 0을, 아닌 경우에는 1부터 시작한다.
      • array (Optional): reduce()를 호출한 배열이다.
    • initialValue(Optional): callback의 최초 호출에서 첫 번째 인수에 재공하는 값이다. 초기값을 제공하지 않으면 배열의 첫 번째 요소(index 0번)를 초기값으로 사용한다.
      • 빈 배열에서 초기값 없이 reduce()를 호출하면 오류가 발생한다.

✏️initialValue에 초기값을 지정할 경우와 아닌 경우 비교

  • initialValue에 초기값을 지정한 경우
const temp3 = Arr3.reduce(function(acc, value){
    console.log("acc : ", acc);
    console.log("value : ", value);
    //console.log(acc + value);
    if(acc === 33){
        return 50
    }
    else{
        return acc + value;
    }
},0);		//reduce에 두 번째 매개변수로 초깃값을 '0'으로 지정

/* 결과
acc :  0	//두 번째 매개변수로 지정한 값이 노출된다.
value :  1	//Arr배열의 첫 번째 요소부터 순차적으로 사용한다.
acc :  1
value :  2
acc :  3
value :  30
acc :  33
value :  4
acc :  50
value :  5
...
*/
  • initialValue에 초기값을 지정하지 않은 경우
const temp3 = Arr3.reduce(function(acc, value){
    console.log("acc : ", acc);
    console.log("value : ", value);
    //console.log(acc + value);
    if(acc === 33){
        return 50
    }
    else{
        return acc + value;
    }
});		//reduce에 두 번째 매개변수로 acc의 초기값을 지정하지 않음

/* 결과
acc :  1	//두 번째 매개변수로 초기값을 지정하지 않아 Arr3배열의 첫 번째 요소를 사용한다.
value :  2	//Arr배열의 첫 번째 요소를 acc의 초기값으로 주었으므로, 
		Arr3 배열의 두 번째 요소부터 순차적으로 사용한다.
acc :  3
value :  30
acc :  33
value :  4
acc :  50
value :  5
acc :  55
value :  15
...
*/

 

 

//--------두 값을 더하면서 반환시키는 기능---------------------------------------------------
const temp3 = Arr3.reduce(function(acc, value){
    // acc는 return된 이전 결과 값
    console.log("acc : ", acc);
    console.log("value : ", value);
    console.log(acc + value);
    if(acc === 33){		//acc+value 값을 더하다가 acc값이 33이 되면 33의 경우의 식을 처리하고
        return 50		//다음의 acc값은 50이 된다.
    }
    else{
        return acc + value;
    }
}, 0);		// value 값을 0으로 정해주었으므로, acc의 첫 번째 값은 0이고, 
			//value의 첫 번째 값은 배열의 index 0의 값이다.
/*결과
acc :  0
value :  1
acc :  1
value :  2
acc :  3
value :  30
acc :  33
value :  4
acc :  50
value :  5
acc :  55
...
acc :  30
value :  15
acc :  30
value :  10
*/
        
//-------------------------------------------------------------------------------------------



//---------배열을 순회하면서 제일 큰 값을 반환 시켜주는 기능----------------------------------
const max = Arr3.reduce(function(acc, value){
    console.log("acc : ", acc);
    console.log("value : ", value);
    //두 개를 비교를 해서 값이 큰지 확인하고 큰 값을 반환
    return acc > value ? acc : value;   //acc와 value 값을 비교. 제일 큰 값을 acc로 반환시켜준다.
})

console.log(max);   //결과 30
//-------------------------------------------------------------------------------------------



//-----------배열을 순회하면서 제일 작은 값을 반환 시켜주는 기능------------------------------
const min = Arr3.reduce(function(acc,value){
    return acc < value ? acc : value;   //acc와 value 값을 비교. 제일 작은 값을 acc로 반환시켜준다.
})

console.log(min);		//결과: 1

 

 


👩‍🏫정규식 예시_회원가입 툴 제작

  • ID는 이메일 형식으로 작성하고, PW는 대소문자,숫자,특수문자 중 3개 이상이 포함되어야 한다.
  • 아이디와 비밀번호를 형식에 맞게 작성하면 로그인이 가능하도록 정규식 제작한 것이다.
  • 정규식은 작업할 때 만들어져 있는 식을 가져와서 사용해도 괜찮다.
    • 필요에따라 수정진행 하면 된다.
  • 로그인한 값을 서버에 보내는 작업은 Node.js에서 진행예정이다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>회원 가입</title>
</head>
<body>
    <label for="">이메일</label>
    <input type="text" class="user_id">
    <label for="">비밀번호</label>
    <input type="text" class="user_pw">
    <button class="sign_up">회원가입</button>
    <p class="text"></p>
</body>
<script>
    let signBtn = document.querySelector('.sign_up');

    //정규식은 작업할 때 가져와서 사용한다.
    // 해당 부분만 필요한 것이다. /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
    function isEmail(asValue) {
	var regExp = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i;
	//test메소드로 검사해서 정규식 형식이 맞으면 true. 아니면 false 반환
    return regExp.test(asValue);
    }

    function isPassword(asValue) {
	var regExp = /^(?=.*[a-zA-z])(?=.*[0-9])(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+]).{8,16}$/;
	return regExp.test(asValue); // 형식에 맞는 경우 true 리턴
    }

    signBtn.onclick = function(){
        console.log("클릭");
        let userId = document.querySelector('.user_id').value;
        let userPw = document.querySelector('.user_pw').value;
        console.log("이메일: ", isEmail(userId));
        console.log("비밀번호: ", isPassword(userPw));
        if(!isEmail(userId) || !isPassword(userPw)){
            document.querySelector('.text').innerHTML = "아이디와 비밀번호를 확인하세요.";
        }
        else{
            document.querySelector('.text').innerHTML = "여기는 nodejs때 할겁니다. 서버에 값으로 요청시키고 응답받는다.";

        }
    }
</script>
</html>
회원 가입

 

 

 

더보기

 

728x90