📌  콜백함수?

 

어느 함수에 인자로 넘겨주는 함수로 어떤 이벤트가 발생했거나 특정 시점에 도달했을 때 시스템에서 호출하는 함수이다. 쉽게 설명해서 다른 함수의 실행이 끝나고 실행하는 것이 콜백함수이다. forEach , setTimeout 등이 있다.

콜백함수는 다른 코드에게 인자로 넘겨줌으로써 제어권도 함께 위임한 함수이다. 콜백 함수를 위임 받은 코드는 자체적으로 내부 로직에 의해 콜백함수를 적절함 지점에서 실행한다.

function print(callback) {
    callback();
}

 

💡 익명함수

 

콜백함수는 일회성으로 사용하는 경우가 많아 코드의 간결성을 위해 익명함수를 사용한다. 함수 내부에서 매개변수로 실행되기 때문에 이름을 붙이지 않아도 되기 때문이다. 함수 이름 충돌을 방지하기 위함도 있다.

 


 

 

 

 

자바스크립트는 코드를 위에서 아래 순으로 실행하지만 순차적으로 실행되지 않을 때도 있다. 이걸 비동기 프로그래밍이라고 한다. 

아래 예시는 0.3초 후라는 적절한 시점에서 자신의 함수에서 적어놓은대로 실행하게된다. 0.3초 뒤 메세지 출력되는걸 확인 할 수 있다.

const message = setInterval(function(){
    console.log('3 second meassage');
    clearInterval(message);
},300);
var cbFunc = function () {
	console.log('3 second meassage');
    clearInterval(message);
};
var timer = setInterval(cbFunc, 300);

 

setTimeout(() => {
    console.log("3 second meassage");
}, 3000);

 

code 호출 주체 제어권
cbFunc() 사용자 사용자
setInterval() setInterval() setInterval()
setTimeout() setTimeout() setTimeout()

 

여기서 cbFunc의 호출 주체와 제어권은 모두 사용자에게 있고 setInterval과 setTimeout의 호출 주체와 제어권은 자기 자신이다.

화살표 함수는 자신만의 this를 가지지 않고 상위 스코프의 this를 참조하기 때문에 전역 객체를 무시하고 무조건 자신을 들고 있는 상위 객체를 가리킨다.

 

 

 

 

this와 콜백함수

이전 this 바인딩 포스팅을 할 때 콜백함수도 찍먹으로 글을 썼었는데 잊혀지지 않은 구문.. 콜백함수도 함수다. 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조한다.

// Array.prototype.map
Array.prototype.map = function (callback, thisArg) {
    var mappedArr = [];
    for (var i = 0; i < this.length; i++) {
        // call의 두 번째 인자는 this가 배열일 것(호출의 주체가 배열)이므로,
        // i번째 요소를 넣어서 인자로 전달
        var mappedValue = callback.call(thisArg || global, this[i]);
        mappedArr[i] = mappedValue;
    }
    return mappedArr;
};
const a = [1, 2, 3].map((item) => {
    return item * 2;
});
console.log(a);

 

여기서 call의 첫 번째 인자는 thisArg로 thisArg가 존재하는 경우는 그 객체, 없으면 전역객체를 가리킨다.

call/apply 메서드의 첫번째 인자에서 콜 백 함수 내부에서 사용될 this를 명시적으로 binding 하기 때문에 this에 다른 값을 넣을 수 있다.

 

 

 

콜백함수에서 this가 전역객체인 이유

콜백 함수는 다른 함수의 인자로 전달되는 함수다. 그래서 콜백 함수는 자신을 전달받은 함수에 의해 호출되는데, 이때 콜백 함수 내부에서의 this는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따르며, 정의하지 않은 경우에는 전역 객체를 참조하게 된다.

 

 

 

콜백함수 this 해결

 

✅ call() : 첫 번째 인자로 this 객체 사용, 나머지 인자들은 , 로 구분

✅ apply() : 첫 번째 인자로 this 객체 사용, 나머지 인자들은 배열 형태로 전달

 

참초할 객체를 추가로 함수의 매개변수로 전달하고, 콜백함수 내에서 call과 apply 메서드를 통해 콜백함수가 참조할 객체를 지정해주면 된다.

var mappedValue = callback.call(thisArg || global, this[i]);

 

 

 

 

이벤트 리스너와 콜백함수

document.queryselector("#callback-btn")
    .addEventListener("click", function() {
      console.log("User has clicked on the button!");
});

 

버튼에 id값을 사용해서 버튼을 선택하고 addEventListener 메서드를 사용하여 이벤트 리스너를 추가했다. 이때 이벤트 리스너 함수는 두개의 파라미터를 필요로 하는데, 첫번째 파라미터로는 이벤트 타입인 '클릭' 이고, 두번째는 버튼이 클릭되었을 때 메세지를 남기는 콜백함 수이다. 콜백함수는 이렇게 이벤트 정의를 위해 사용되기도 한다.

 

 

var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
//method로써 호출
obj.logValues(1, 2);
//callback => obj를 this로 하는 메서드를 그대로 전달 X
//단지, obj.logValues가 가리키는 함수만 전달
[4, 5, 6].forEach(obj.logValues);

📌 this 란

실행할 코드에 제공할 환경 정보들을 모아놓은 객체를 실행 컨텍스트(execution context) 라고 부른다. 자바스크립트 내부에서 이런 실행 컨텍스트를 스택(Stack)으로 관리하고 있으며, 실행되는 시점에서 자주 변경되는 실행 컨텍스트를 this 가 가리키고있다. 

 

스택 중 콜스택(Call Stack)에 쌓아올리며 가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경과 순서를 보장 할 수 있다.

 

 

객체 지향 언어에서 this는 클래스로 생성한 인스턴스를 말하지만, 자바스크립트에서 this는 언제 어디서나 사용할 수 있다.

this는 실행되는 코드의 실행 컨텍스트를 가리킨다!

💡 실행 컨텍스트 속 3가지
VariableEvironment
LexicalEvironment
ThisBinding 👉🏻 오늘 이해할 것

 

 

 

1. default binding

기본적으로 this는 전역 객체를 가리킨다. 브라우저 환경에서 this는 window를 가르키고, 노드 환경에서 this는 global을 가르킨다.

Browser

 

Node

 

 

 

2. 메서드 내부에서의 this

함수 함수는 호출의 주체가 없고 함수 그 자체로 독립적인 기능을 수행한다.
메서드 반대로 메서드는 호출 주체가 있으며 자신을 호출한 대상 객체에 대한 동작을 수행한다.

 

함수

함수명();
// CASE1 : 함수
// 호출 주체를 명시할 수 없기 때문에 this는 전역 객체를 의미
var func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1

메서드

객체.메서드();
// CASE2 : 메서드
// 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미
// obj는 { method: func }
var obj = {
method: func,
};
obj.method(2); // { method: [Function: func] } 2

 

 

예외

메서드 내부에서도 독립적으로 호출한다면 this는 전역 객체를 의미한다.

var obj1 = {
    outer: function () {
        console.log(this); // (1)
        var innerFunc = function () {
            console.log(this); // (2), (3)
        }
        innerFunc();
        var obj2 = {
            innerMethod: innerFunc
        };
        obj2.innerMethod();
    }
};
obj1.outer();
실행결과
(1) : obj1
(2) : 전역객체
(3) : obj2

 

 

 

3. this 우회

화살표(=>)함수는 실행 컨텍스트를 생성할 때 바인딩 과정이 없다. 일반함수와 화살표 함수의 가장 큰 차이점은 this binding 의 여부이다.

var obj = {
    outer: function () {
        console.log(this); // (1) obj
        var innerFunc = () => {
            console.log(this); // (2) obj
        };
        innerFunc(); //함수로 호출해도 전역객체가 아닌 호출객체를 가리킴
    }
}
obj.outer();

 

화살표 함수 예외

obj 객체 안 print 메서드를 화살표 함수로 선언할 경우 this는 전역 객체를 가리킨다. 

var obj = {
    names: ["seo"],
    text: "님 안녕하세요",
    print: () => { console.log(this.text) } // undefined
}
obj.print()

 

 

4. 콜백함수 this

콜백함수도 함수이기때문에 this가 전역 객체를 가리키지만 콜백함수를 넘겨 받은 함수에서 콜백함수에 별도로 this를 지정해준 경우 예외로 그 대상을 참조한다.

 

 

별도의 지정이 없어 전역 객체를 가리킨다.

setTimeout(function () { console.log(this) }, 300);
[1, 2, 3, 4, 5].forEach(function(x) {
	console.log(this, x);
});

 

addEventListener 메서드는 콜백함수 호출 시, 자신의 this를 상속. 따라서 this는 button 을 가리킨다.

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function (e) {
    console.log(this, e);
});

 

 

5. 명시적 this 바인딩

 

자동으로 부여되는 상황별 this의 규칙을 깨고 this에 별도의 값을 저장하는 방법

call, apply, bind
call 호출 주체인 함수를 즉시 실행 첫번째 인자로 실행 컨텍스트를 인자로 전달
apply call과 동일하되 배열 형태로 넘김
bind 즉시 호출하지 않고, 함수에 this를 미리 적용하거나 부분적으로 적용  

 

 

5-1. Call 메서드

var obj = {
    string : "free",
    value : function(){
        console.log(this.string);
    },
}

var obj2 = {
    string : "not free",
}

obj.value(); //free
obj.value.call(obj2); //not free
var func = function (a, b, c) {
    console.log(this, a, b, c);
};
// no binding
func(1, 2, 3); // Window{ ... } 1 2 3

// 명시적 binding
func.call({ x: 1 }, 4, 5, 6}; // { x: 1 } 4 5 6
var obj = {
    a: 1,
    method: function (x, y) {
        console.log(this.a, x, y);
    }
};
obj.method(2, 3); // 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 4 5 6

 

 

5-2. Apply 메서드

var func = function (a, b, c) {
    console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
var obj = {
    a: 1,
    method: function (x, y) {
        console.log(this.a, x, y);
    }
};
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6

 

 

5-3. Bind 메서드

call과는 다르게 즉시 호출하지는 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수 를 반환하는 메서드

var func = function (a, b, c, d) {
    console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // window ... 1, 2, 3, 4

// 함수에 this 미리 적용
var bindFunc1 = func.bind({ x: 1 }); // 바로 호출X
bindFunc1(5, 6, 7, 8); // { x: 1 } 5 6 7 8

// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // 4와 5를 미리 적용
bindFunc2(6, 7); // { x: 1 } 4 5 6 7
bindFunc2(8, 9); // { x: 1 } 4 5 8 9

 

구문

자바스크립트의 reduce함수는 배열의 각 요소를 순회하며 callback함수의 실행 값을 누적하여 하나의 결과값을 반환한다.

 

파라미터

callback function

- 다음 4가지의 인수를 가진다.

accumulator  (=acc) accumulator는 callback함수의 반환값을 누적
currentValue (=cur) 배열의 현재 요소
index(Optional) 배열의 현재 요소의 인덱스
array(Optional) 호출한 배열

 

- callback함수의 반환 값은 accumulator에 할당되고 순회중 계속 누적되어 최종적으로 하나의 값을 반환

 

nitialValue(Optional)

최초 callback함수 실행 시 accumulator 인수에 제공되는 값, 

초기값을 제공하지 않을경우 배열의 첫 번째 요소를 사용하고, 빈 배열에서 초기값이 없을 경우 에러가 발생

 

반환 값

배열을 순서대로 불러 각 요소에 대해 callback 함수을 실행한 결과를 누적한 값

 


 

✏️ 예제

 

👀  배열 값 전부 더하기

let arr = [55, 12, 65, 36];
const sum = arr.reduce((acc, cur) => acc + cur);

console.log(sum); //168
let arr = [55, 12, 65, 36];

function reduceFunc(acc, cur){
	return acc + cur;
}

const sum = arr.reduce(reduceFunc);
console.log(sum); // 168

 

👀  원하는 값만 더하기 

const users =  //배열 객체 생성
[ 
  {
    name: 'Anna',
    age: 25,
    job: 'student',
  },
  {
    name: 'Ori',
    age: 38,
    job: 'doctor',
  },
  {
    name: 'June',
    age: 33,
    job: 'ceo',
  }
];


const sum = users.reduce((acc, cur) => {
	acc + cur.age //현재 값에 age 만 가져오기
}, 0); // 초기값 필수!

console.log(sum); //96

 

👀 배열 비교하기

두 배열의 길이가 다르다면, 배열의 길이가 긴 쪽이 더 큽니다.
배열의 길이가 같다면 각 배열에 있는 모든 원소의 합을 비교하여 다르다면 
더 큰 쪽이 크고, 같다면 같습니다.

두 정수 배열 arr1과 arr2가 주어질 때, 위에서 정의한 배열의 대소관계에 대하여 
arr2가 크다면 -1, arr1이 크다면 1, 두 배열이 같다면 0을 return 하는 solution 함수를 작성해 주세요.
arr1 arr2 result
[49, 13] [70, 11, 2] -1
[100, 17, 84, 1] [55, 12, 65, 36] 1
[1, 2, 3, 4, 5] [3, 3, 3, 3, 3] 0

 

function solution(arr1, arr2) {
    const length1 = arr1.length;
    const length2 = arr2.length;
    if(length1 !== length2) return length1 > length2 ? 1 : -1 
    //삼항연산자
    //arr1.length와 arr2.length 길이가 다를 때 arr1.length 길면 1 반환 arr2.length 길면 -1 반환

    const sum1 = arr1.reduce((acc, cur) => acc+cur, 0) 
    const sum2 = arr2.reduce((acc, cur) => acc+cur, 0)
    //arr1, arr2 배열의 요소를 모두 합친 값을 각 변수에 저장
    if(sum1 === sum2) return 0 //각 배열의 합친 값이 같을 떄 0 반환
    return sum1 > sum2 ? 1: -1 //합친 값이 arr1이 더 클 경우 1 반환 아닐경우  -1 반환
}

 

 

 

🔥 정렬의 sort() 함수

배열을 상대로 sort()함수를 사용하면 오름차순으로 정렬된다.

[7,2,5,9].sort();
//[2,5,7,9]

 

배열 내 값들을 재배치하고 정렬된 배열을 다시 반환한다.

let num = [3,2,1,];
let sortNum = num.sort();
console.log(num, sortNum);
//[ 1, 2, 3 ] [ 1, 2, 3 ]

 

 

'-'(마이너스) 가 들어갔다고해서 음수가 아니라 배열 안에서는 그저 문자일 뿐이다.

그래서 정렬 전 내부적으로 문자열로 변환하곤하는데 이러한 부분때문에 숫자 배열을 정렬할 때 예상치 못한 결과 값이 나올 수 있다. 

[-3, 2, 0, 1, 3, -2, -1].sort();
// [-1, -2, -3, 0, 1, 2, 3]

 


 

구문

 

매개변수

compareFunction  정렬 순서를 정의하는 함수. 생략하면 배열은 각 요소의 문자열 변환에 따라 각 문자의 유니 코드 코드 포인트 값에 따라 정렬된다.
 

반환값

정렬한 배열. 원 배열이 정렬되는 것에 유의하세요. 복사본이 만들어지는 것이 아님.

 

 


 

sort()  규칙

첫 번째 인자가 두 번째 인자보다 작으면 음수를 반환
첫 번째 인자가 두 번째 인자보다 크면 양수를 반환
첫 번째 인자가 두 번째 인자와 같으면 0을 반환

 

오름차순으로 정렬하기 위해서는 첫번째 인자에서 두번째 인자를 빼준다.

[-3, 2, 0, 1, 3, -2, -1].sort((a, b) => a - b);
// [-3, -2, -1, 0, 1,  2,  3]

 

내림차순은 반대로 a-b 를 b-a로 바꿔주면 끝!

[-3, 2, 0, 1, 3, -2, -1].sort((a, b) => b - a);
// [3, 2, 1, 0, -1, -2, -3]

 


 

 

객체 배열 정렬

const user = [
  { no: 1, grade: "A", name: "July" },
  { no: 2, grade: "B", name: "Anna" },
  { no: 3, grade: "C", name: "Tom" },
  { no: 4, grade: "D", name: "May" },
  { no: 5, grade: "F", name: "Alice" },
];

 

user 배열을 하나 생성하고 오름차순 내림차순으로 정렬해보자.

 

no 기준으로 정렬

user.sort(function (a, b) {
    if (a.no > b.no) {
      return 1;
    }
    if (a.no < b.no) {
      return -1;
    }
    // a must be equal to b
    return 0;
  });

 

 


 

✏️ 예제

var stringArray = ["Blue", "Humpback", "Beluga"];
var numericStringArray = ["80", "9", "700"];
var numberArray = [40, 1, 5, 200];
var mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];

function compareNumbers(a, b) {
  return a - b;
}

console.log("Sorted:", stringArray.sort());
결과값 Sorted: [ 'Beluga', 'Blue', 'Humpback' ]

 

var stringArray = ["Blue", "Humpback", "Beluga"];
var numericStringArray = ["80", "9", "700"];
var numberArray = [40, 1, 5, 200];
var mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];

function compareNumbers(a, b) {
  return a - b;
}

console.log(
    "Sorted with compareNumbers:",
    numericStringArray.sort(compareNumbers),
  );
결과값 Sorted with compareNumbers: [ '9', '80', '700' ]

 

 

 

 

 

🔥 slice() 메서드로 특정 범위 요소 자르기

slice() 메서드는 어떤 배열의 begin 부터 end 까지(end 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환한다.

 

구문

 

매개변수

begin 0을 시작으로 하는 추출 시작점에 대한 인덱스를 의미, slice(-2) 는 배열에서
마지막 두 개의 엘리먼트를 추출하고

begin이 undefined인 경우에는, 0번 인덱스부터 slice 한다. begin이 배열의 길이보다 큰 경우에는, 빈 배열을 반환
end 추출을 종료 할 0 기준 인덱스, slice 는 end 인덱스를 제외하고 추출하고 end가 생략되면 
slice()는 배열의 끝까지(arr.length) 추출

 

반환값

추출한 요소를 포함한 새로운 배열

 


✏️ 예제

const colors = ["red", "green", "blue", "orange", "yellow"];
const slicedColors = colors.slice(1, 3);

//[green, blue, orange]
const numbers = [1, 2, 3, 4, 5];

// 배열의 처음 3개 요소를 추출합니다.
const firstThree = numbers.slice(0, 3);

console.log(firstThree); // 출력: [1, 2, 3]

// 배열의 마지막 2개 요소를 추출합니다.
const lastTwo = numbers.slice(-2);

console.log(lastTwo); // 출력: [4, 5]
const num_list = [5,4,3,7,2,9,1,8];

function solution(num_list){
    return num_list.sort((a,b) => a-b).slice(0, 5);
    // 배열 처음부터 5번째까지 출력
}

Map

배열을 순회하며 지정된 콜백 함수를 적용하여 각 요소를 변환하고, 그 변환된 값을 모아서 새로운 배열로 반환하는 역할을 수행합니다.

 

기본구문

arr.map(function(currentValue[, index[, array]]) {
    // 변환(mapping)할 로직: 변환된 결과를 반환해야 합니다.
}[, thisArg]);
function
각 배열 요소에 적용될 때 호출되는 콜백함수
  • currentValue (필수): 처리할 현재 요소. 이 매개변수를 통해 현재 요소에 접근할 수 있습니다.
  • index (옵션): 처리할 현재 요소의 인덱스. 이 매개변수를 사용하여 현재 요소의 인덱스에 접근할 수 있습니다.
  • array (옵션): map() 함수를 호출한 배열. 이 매개변수를 사용하여 원본 배열에 접근할 수 있습니다.
thisArg
function을 실행할 때 this로 사용할 객체. 이 매개변수는 필요에 따라 사용됩니다.

 

반환값

배열의 각 요소에 대해 실행한 function의 결과를 모은 새로운 배열을 반환합니다.

 

 

 


 

예제

해당 배열이 있을 때 각 요소에 곱하기 5를 해보자

let arr = [3, 4, 5, 6];

 

 

for문

for(let i = 0; i < arr.length; i++){
	arr[i] = arr[i]*3; 
}
console.log(arr); // [15, 20, 25, 30]

 

map()

각 배열에 있는 요소를 순회하며 매핑해준 값을 반환한다. 일반적으로 특정 숫자를 곱하거나, 애플리케이션에 필요한 다른 작업을 수행하는 등 요소에 어떤 변경 사항을 적용하는 데 사용된다고 한다.

let arr_map = arr.map((element, index) => element * 5 );

console.log(arr_map); // [ 15, 20, 25, 30 ]

 

 

 


 

map() 함수의 장점

  • 각 배열 요소를 변환하여 새로운 배열을 반환합니다.
  • 반환된 배열은 원본 배열과 길이가 같고, 각 요소는 변환된 값으로 구성됩니다.
  • 변환 작업을 통해 새로운 배열을 생성하기 때문에 원본 배열은 변경되지 않습니다.

 

map() 함수의 단점

  • 새로운 배열을 생성하는 과정에서 메모리를 사용하므로, 큰 크기의 배열에 대해서는 성능 이슈가 있을 수 있습니다.

 


 

 

✏️ 예제

function solution(arr, n) {
    var answer = [];
    
    if(arr.length % 2 === 1){
        return arr.map((element, index) => index % 2 == 0 ? element + n : element);
    }else{
        return arr.map((element, index) => index % 2 == 1 ? element + n : element);
    }
}

 

정수 배열 arr과 정수 n이 매개변수, arr의 길이가 홀수라면 arr의 모든 짝수 인덱스 위치에 n을 더한 배열을, 

arr의 길이가 짝수라면 arr의 모든 홀수 인덱스 위치에 n을 더한 배열을 return 하는 함수

 

코드를 자연어 그대로 나열하자면 아래와 같다.

if()문으로 배열의 길이가 홀수라면 / 반환한다 / 배열을 순회해서 / 인덱스가 짝수라면(홀수라면) / 각 요소에 + n / + n

 

//n = 27
//arr = [49, 12, 100, 276, 33]

입력값 〉[49, 12, 100, 276, 33], 27
기댓값 〉[76, 12, 127, 276, 60]

 

 


 

 

const myMap = new Map(); //맵 생성
myMap.set('one',1);
myMap.set('two',2);
myMap.set('three',3);

//반복을 위한 method -> keys, values, entries
for(const key of myMap.keys()){
    console.log(key);
}

// 결과
// one
// two
// three


for(const value of myMap.values()){
    console.log(value);
}

// 결과
// 1
// 2
// 3

for(const entries of myMap.entries()){
    console.log(entries);
}

// 결과
// ['one', 1]
// ['two', 2]
// ['three', 3]

 

반복을 위한 메소드로는 keys, values, entries가 있다.

Map 을 순회할 때는 for .. of 를 쓰거나 forEach문을 쓰면된다.

forEach 구문을 사용할 때에는 Key와 Value의 순서가 반대라는 것만 기억하면 된다.

for (let [key, val] of testmap.entries()) {
  console.log(key, ':', val); // 1:123, 2:345, 3: 789
}

for (let [key, val] of testmap) {
  console.log(key, ':', val);
}

testmap.forEach((val, key) => {
  console.log(key, ':', val);
})

 

 

Set

고유한 값을 저장하는 자료구조로 값만 저장하며 Key값은 저장되지 않는다.

값이 중복되지 않는 유일한 요소이다.

const mySet = new Set();
mySet.add('value1'); //key X value O
mySet.add('value2');
mySet.add('value2');

console.log(mySet);

 

중복되는 값은 저장되지 않으므로 결과로는 Set(2) { 'value1', 'value2' } 이 출력된다.

 

 

 

 

 

 

 

📌 동기와 비동기

동기(synchronous)란, 어떤 작업을 실행할 때 그 작업이 끝나기를 기다리는 방식을 의미한다. 
즉, 작업이 완료될 때까지 다음 코드의 실행을 멈추고 기다리는 것이다. 이러한 방식은 작업의 순서를 보장하고, 
작업이 끝날 때까지 결과를 기다리는 것이 가능하다.
비동기(asynchronous)란, 어떤 작업을 실행할 때 그 작업이 완료되지 않더라도 다음 코드를 실행하는 방식을 의미한다.
즉, 작업이 완료되지 않았더라도 결과를 기다리지 않고 다음 코드를 실행하는 것이다. 
이러한 방식은 작업이 오래 걸리는 경우 시간을 절약하고, 병렬적인 작업 처리가 가능하다. 
동기 방식으로 파일을 읽는다면 파일을 읽기 시작한 이후에 다음 코드를 실행하지 않고 파일이 읽혀지기를 기다린다. 
반면에 비동기 방식으로 파일을 읽는다면 파일을 읽는 작업이 실행되는 동안 다른 작업을 수행할 수 있다.

 

 

 

✅  비동기 처리가 필요한 이유

1. 웹페이지의 기능성 향상

- 사용자가 요청한 작업이 완료될 때까지 기다리는 것은 사용자 경험을 저해 시킨다.

따라서, 비동기 처리를 통해 사용자 경험을 빠르게 처리해야한다.

 

2. 네트워크 통신

- 동기적인 처리를 하게 되면 응답을 기다리는 동안 다른 작업을 수행할 수 없기 때문에 웹 페이지의 반응성이 떨어질 수 있다.

따라서, 비동기적으로 데이터를 받아오는 것이 웹 페이지의 성능을 향상시키는데 도움이 된다.

 

3. 병렬 처리

- 비동기 처리를 통해 여러 작업을 동시에 처리할 수 있다. 이를 통해 시간이 오래 걸리는 작업을 병렬적으로 처리할 수 있으며, 결과적으로 전체 작업 시간을 단축시킨다.

 

4. 에러 처리

- 비동기적으로 처리할 때 에러가 발생하면, 해당 에러를 쉽게 처리할 수 있다. 에러 발생 시, 에러를 처리할 수 있는 콜백 함수를 실행하거나, 에러를 캐치하여 처리할 수 있어 프로그램의 안정성을 높일 수 있다.

 

 

 


 

 

📌 async 와 await

async와 await는 ES2017(ECMAScript 8)부터 추가된 자바스크립트의 비동기 처리 방식 중 하나이다. 
async와 await를 사용하면 비동기 코드를 동기 코드처럼 작성할 수 있어, 가독성이 좋아지고 에러 처리가 간단해진다.

 

 

async는 함수의 앞에 붙여서 해당 함수가 비동기 함수임을 나타내며, await는 비동기 함수의 실행 결과를 기다리는 키워드이다.

async 함수 안에서 await 키워드를 사용하면, 해당 비동기 작업이 완료될 때까지 코드 실행을 일시 중지하고 결과를 기다린 다음,

해당 결과를 반환한다.

 

 

async function 함수명() {
  await 비동기_처리_메서드_명();
}

 

먼저 함수의 앞에 async 라는 예약어를 붙인다. 그러고 나서 함수의 내부 로직 중 HTTP 통신을 하는 비동기 처리 코드 앞에 await를 붙인다. 여기서 주의해야 할 점은 비동기 처리 메서드가 꼭 프로미스 객체를 반환해야 await가 의도한 대로 동작한다는 것이다.

일반적으로 await의 대상이 되는 비동기 처리 코드는 Axios 등 프로미스를 반환하는 API 호출 함수이다.

 

 

 

 

팀원을 소개하는 미니 프로젝트 중 좋아요 기능을 도맡아(?) 나름 머리 굴려가며 구현 중이다.

하트를 눌렀을 때 색이 채워지고 아래 카운트가 증가한다.

 

 

 


✏️ 구현하고 싶은 기능

  • 하트 클릭시 색 채워지기
  • 동시에 카운트 증가
  • 하트를 다시한번 누르면 디폴트로 돌아가고 카운트 감소
  • 카운트 누적 ❎

 

index.html

<ul class="icon-tab">
    <li>
    <!--❤️ 하트 svg-->
        <button id="likebtn" class="feed-icon-btn" value="좋아요" onclick="like()">
            <svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" stroke="black" width="60px"
                height="50px" fill="currentColor" class="bi-heart-fill feed-icon like-default"
                viewBox="0 -0.5 17 17">
                <path fill-rule="evenodd"
                    d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314" />
            </svg>
        </button>
    </li>
    <li>
        <a href="#">
        <!--말풍선 svg-->
            <svg height="45px" width="45px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
                xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 473 473" xml:space="preserve"
                transform="matrix(-1, 0, 0, 1, 0, 0)">
                <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
                <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
                <g id="SVGRepo_iconCarrier">
                    <g>
                        <g>
                            <path
                                d="M403.581,69.3c-44.7-44.7-104-69.3-167.2-69.3s-122.5,24.6-167.2,69.3c-86.4,86.4-92.4,224.7-14.9,318 c-7.6,15.3-19.8,33.1-37.9,42c-8.7,4.3-13.6,13.6-12.1,23.2s8.9,17.1,18.5,18.6c4.5,0.7,10.9,1.4,18.7,1.4 c20.9,0,51.7-4.9,83.2-27.6c35.1,18.9,73.5,28.1,111.6,28.1c61.2,0,121.8-23.7,167.4-69.3c44.7-44.7,69.3-104,69.3-167.2 S448.281,114,403.581,69.3z M384.481,384.6c-67.5,67.5-172,80.9-254.2,32.6c-5.4-3.2-12.1-2.2-16.4,2.1c-0.4,0.2-0.8,0.5-1.1,0.8 c-27.1,21-53.7,25.4-71.3,25.4h-0.1c20.3-14.8,33.1-36.8,40.6-53.9c1.2-2.9,1.4-5.9,0.7-8.7c-0.3-2.7-1.4-5.4-3.3-7.6 c-73.2-82.7-69.4-208.7,8.8-286.9c81.7-81.7,214.6-81.7,296.2,0C466.181,170.1,466.181,302.9,384.481,384.6z">
                            </path>
                        </g>
                    </g>
                </g>
            </svg>
        </a>
    </li>
    <li>
    <!--북마크 svg-->
        <svg fill="#000000" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
            <g id="SVGRepo_bgCarrier" stroke-width="0"></g>
            <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
            <g id="SVGRepo_iconCarrier">
                <path d="M416,480,256,357.41,96,480V32H416Z">
                </path>
            </g>
        </svg>
    </li>
    <!--좋아요 수 카운트-->
    <li class="cboth"><b id="likeCount">0</b>명이 좋아합니다.</li>
</ul>

 

 

 

 

script.js

function like() {
    const likebtn = document.getElementById('likebtn');
    const likePath = likebtn.getElementsByTagName('path')[0];

    const likeCount = document.getElementById("likeCount");
    let num = likeCount.innerText; //화면에 표시된 좋아요 값

    console.log("Like Button Clicked.")
}

 

먼저 좋아요 버튼을 눌렀을 때 실행하는 함수 like()를 만들어

버튼을 눌렀을 때 정상적으로 작동하는지 콘솔에서 확인해 보았다

 

제대로 작동하는지 확인 완료

 

 

 

/* 좋아요 toggle */
function like() {
    const likebtn = document.getElementById('likebtn');
    const likePath = likebtn.getElementsByTagName('path')[0];

    const likeCount = document.getElementById("likeCount");
    let num = likeCount.innerText; //화면에 표시된 좋아요 값

    console.log("Like Button Clicked.")


    if (likebtn.classList.contains('like-default')) {
        likebtn.classList.remove('like-default');
        likebtn.classList.add('like-active');
        likePath.setAttribute('fill', '#ffffff');
        likePath.setAttribute('stroke', '#000000');

        /* 좋아요 카운트 취소 */
        num = Math.floor(num) - 1;
        likeCount.innerText = num;

    } else {
        likebtn.classList.remove('like-active');
        likebtn.classList.add('like-default');
        likePath.setAttribute('fill', 'rgb(217,57,73)');
        likePath.setAttribute('stroke', 'rgb(217,57,73)');

        /* 좋아요 카운트 누적 */
        num = Math.floor(num) + 1;
        likeCount.innerText = num;
    }
}

 

좋아요를 눌렀을 때 like-active 클래스를 추가해 svg에 fill이 채워지고 좋아요 카운트 +1 

다시 좋아요 버튼을 눌렀을 땐 fill이 default값으로 되돌아오도록 하고 카운트는 -1 되도록 구현했다.

 

 

 

 

우여곡절 끝에 기본 완성했지만 서버를 활용해 카운트가 누적되는 것은 아직 구현하지 못했다.

firebase를 사용해서 하려고 하는데 아직 데이터 감은 좀처럼 잡기가 힘들다.

좋아요 기능은 아묻따 꼭 만들어보고싶다. 다시한번 머리 굴리러 가보자..

다시 공부하고 있는 자바스크립트를 기초부터 차근차근 정리하고자 합니다.

글로 정리하면 머리 정리도 되기때문에 일석이조에요!

 

 

01. 자바스크립트로 간단한 실행문 작성

우선 비주얼 스튜디오 코드로 마크업을 해주세요. "html:5" 를 입력하고 Enter/Tab을 누르면

body 영역을 제외한 부분이 자동으로 입력됩니다. 이제 코드를 작성해볼까요?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
</html>

 

 

✏️ 맛보기 예제:

질의응답 창을 사용하여 키보드로 나이를 입력 받고, 입력된 나이가 20세 이상인지 아닌지 검사하여

알맞은 문장을 출력하는 코드를 작성해봅시다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
	<script>
        var age = prompt("당신의 나이는? :","0");
        if(age >= 20){
            document.write("당신은 성인입니다.");
        }else {
            document.write("당신은 미성년자입니다.");
        }
    </script>
</body>
</html>

 

✏️ 결과:

당신은 미성년자입니다.

 

 

더보기

📌 코드 입력시 주의사항:

 

1. 자바스크립트는 대/소문자를 구분하여 작성합니다.

날짜 객체 생성 : New date(); (X)
날짜 객체 생성 : New Date(); (O)

 

2. 코드 한 줄을 작성한 후에는 세미콜론(;)을 쓰는 것이 좋습니다. 세미콜론을 사용하지않고 한 줄에 2개의 코드를 작성할 경우 오류가 발생합니다.

document.write("hi") document.write("bye") (X)
document.write("hi"); document.write("bye"); (O)

 

3. 코드를 작성할 때는 한 줄에 한 문장만 작성하는 것이 가독성을 위해 좋습니다.

document.write("hi");
document.write("bye");

 

4. 문자형 데이터를 작성할 때는 큰따옴표("")와 작은따옴표('')의 겹침 오류를 주의해야 합니다.

document.write("책 속에 "대소문자를 구분해야합니다"라고 나와있다.");
document.write("책 속에 \"대소문자를 구분해야합니다\"라고 나와있다.");

 

5. 코드를 작성할 때 중괄호{} 또는 소괄호()의 짝이 맞아야 합니다.

document.write("welcome!");

+ Recent posts