오늘도 끄적끄적

느리더라도 꾸준하게

오늘은 기본값을 위해 많이 쓰던 논리 연산자인
||와 &&을 집중 탐구해보았다.
우선 위에 있는 녀석들은 어떨 때 쓰는지 알아보자.

사용 사례

  • 네임 스페이스 패턴(~ES5)
    웹팩을 사용하면 js 파일을 모듈 단위로 사용할 수 있지만,
    그럴 환경이 안 되면 아래와 같은 우회 방법을 통해서 전역 스코프를 최대한 덜 더럽힐 수 있다.
    ES6에는 모듈 import, export 기능이 있어서 ~ES5라고 써놓긴 했지만…
    아직 지원하는 브라우저가 없는 걸로 안다. (17년 2월 기준)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 전역 스코프에는 namespace와 namespace2 모듈만이 존재한다.
    // func라는 충돌나기 쉬운 네이밍이 전역에 존재하지 않으므로 충돌이 일어나지 않는다.
    // 즉 네이밍을 고민할 염려가 조금은 줄어들게 된다. 뭐 그 외에 장점도 많지만...
    // script src 태그를 통해 미리 namespace 모듈을 불러온 경우에는 전역에는 변수 namespace가 존재한다.
    // || 연산자를 써서 전역에 namespace라는 변수(모듈)가 존재하면 그 모듈을 변수에 할당하고,
    // 존재하지 않는다면 빈 객체를 변수에 할당하는 패턴이다.
    const namespace = namespace || {};
    namespace.func = function() {};

    const namespace2 = namespace2 || {};
    namespace2.func = function() {};
  • 함수의 매개변수 기본값 설정(~ES5)
    ES6를 통해서는 아래와 같은 게 가능하지만,

    1
    const func = (param1 = 0, param2 = '') => {};

    바벨을 사용할 수 없고, IE 하위 브라우저까지 크로스 브라우징을 하는 환경에서는
    아래와 같이 처리해줘야한다.

    1
    2
    3
    4
    5
    var func = function(param1, param2) {
    // || 뒤에 오는 애가 기본 값이다.
    param1 = param1 || 0;
    param2 = param2 || '';
    };
  • 함수의 인자로 기본값 설정
    위에서는 함수를 선언할 때 매개변수의 기본값을 설정한 경우지만
    이 경우는 함수를 호출할 때 인자의 기본값을 설정한 경우이다.
    둘의 차이는 뭐 없다고 봐도 무방하지 않을까…싶다.

    1
    2
    3
    4
    5
    const obj = {name: ''};
    const func = age => console.log(age);
    // obj 객체에 age라는 키가 없으므로 undefined를 반환한다.
    // undefined는 형변환 했을 때 false로 간주되므로 기본값인 1이 넘어간다.
    func(obj.age || 1); // 1
  • 함수의 기본 반환값 설정
    함수의 반환값이 매개 변수에 따라서 오류를 뿜는 경우가 존재한다.
    그런 오류를 방지하고자 기본값을 설정하곤 하는데 어떤 경우인지 보자.

    1
    2
    3
    4
    5
    6
    const cntOccurrences = (regExp, str) => (
    // 정규표현식과 매치되는 결과가 없어서 null을 반환할 경우
    // null.length는 오류를 반환하므로 기본값으로 빈 배열을 넣어줘서 오류를 방지함.
    (str.match(regExp) || []).length
    );
    console.log(cntOccurrences(/\d/g, 'asdf')); // 0, 기본값이 없었다면 오류가 난다.
  • 거짓 기본값 설정하기
    말이 이상한데…
    만약 해당 변수가 거짓이라면 더 이상의 판별을 하지 않고자 할 때 쓰면 된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const arr = [1, 2, 'q', 4];
    // 배열이 숫자로만 이루어진 건지 아닌지 판별하는 함수
    const isNumArr = arr => {
    let isNum = true; // 모든 값이 숫자인지 아닌지 판별하는 flag 변수
    arr.forEach(v => {
    // 만약에 한 번이라도 숫자가 아닌 값이 있었다면
    // 그 아래에 있는 구문들을 실행할 필요가 없으므로
    // return으로 함수를 조기 종료.
    if(!isNum) return;

    // 현재 값이 숫자인지 판단하여 변수에 저장.
    isNum = isNaN(v);
    });
    return isNum;
    }
    console.log(isNumArr(arr)); // false

위와 같은 코드가 있을 때 && 논리 연산자를 쓰면 코드를 줄일 수 있다.
퍼포먼스 측면에서는 맞는지 잘 모르겠다…

더 읽어보기 »

이 글은 Outsider 님의 블로그 포스트 중
forEach에 break문 대신 some 사용하기를 보고 큰 감명을 받아
내가 이해한 내용을 토대로 정리해 본 글이다.

for loop

for 반복문을 써서 배열을 순회하는 것은 할당, 프로퍼티 참조, 조건 분기 등등의 잡다한 일을 해야한다.
이러한 잡다한 일을 실수로 코딩을 잘못하면 원하지 않는 결과가 나오고, 귀찮음이 몰려오기 마련이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const arr = [
0, 1, 2, 3, 'q', 5, 6, 3.3, 5, 6, 3.3, 5, 6, 3.3,
5, 6, 3.3, 5, 6, 3.3, 5, 6, 3.3, 5, 6, 3.3
];

// 배열이 숫자로만 이루어져있는지 파악하는 함수
const isArrNum = arr => {
let isNum = true;

// 프로그래머가 실수로 let i = 1;이라고 초기화한다면?
// 실수로 i<arr.length+1; 이라고 조건식을 잘못 입력한다면?
// i+=2; 라고 증감식을 잘못 입력한다면?
// arr[i+1]로 잘못 참조한다면?
// 이렇게 일일이 초기화, 조건식 지정, 증감식 지정 등등을 일일이 해줘야하므로 귀찮다.
for(let i=0; i<arr.length; i++) {
console.log(arr[i]);
if(!isNaN(arr[i])) { // 숫자라면
// 아래 있는 코드는 실행할 필요 없이 다음 요소를 검사해야함.
// 즉 다음 반복문을 실행.
continue;
}
// 숫자가 아니라면
isNum = false;

// 바로 반복문을 종료해야함.
break;
}

return isNum;
};


// 0
// 1
// 2
// 3
// q
// false
console.log(isArrNum(arr));

// 사실은 아래와 같이 break와 continue를 쓸 필요도 없는 예제긴 하다.
const isArrNum2 = arr => {
for(let i=0; i<arr.length; i++) {
if(isNaN(arr[i])) { // 숫자가 아니라면
// 반복문 탈출이고 나발이고 return으로 바로 함수를 조기 종료 시키면서
// false를 반환하게 하면됨.
return false;
}
}
// 반복문이 무사히 끝났으면 모든 게 숫자였다고 판단하여 true를 반환.
return true;
};
더 읽어보기 »

자바를 공부하면서 느낀 것이다.

초반엔 내가 아는 내용이니 하루에 한 챕터씩 나가야지..

하지만 내가 아는 게 다가 아니었다.
다 안다고 생각했지만 그 속에는 모르는 내용들이 너무 많았다.
하루 한 챕터를 정리해가면서 연습문제까지 풀어가기에는 정말 힘들었다.
초반에는 재밌어서 그래도 거의 한 챕터씩 나갔다.
하지만 가면 갈 수록 그 양에 질리고, 시간은 더욱 오래 걸렸다.
공부를 하는 것도 매일 매일이 아니라 그냥 생각날 때, 시간 날 때만 했다.
오늘 공부를 하다보니 이제는 지쳐서 2시간이 되자 책장을 넘기면서

이 챕터는 도대체 언제 끝나나…
다음 챕터는 얼마나 될라나…

더 읽어보기 »

어제는 친구들이랑 노느라 공부를 조금 밖에 못 했다.
그만큼 오늘은 좀 빡시게 달려야겠다.

재귀함수(recursive function)

함수 내에서 자기 자신을 호출하는 것이다.
배열의 요소를 모두 더하는 메소드는 아래와 같이 작성이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class test {
static int sumArr(int[] arr) {
int sum = 0;
for(int num : arr) {
sum += num;
}
return sum;
}
public static void main(String[] args) {
int arr[] = {1, 2, 4, 5 , 8, 9};
int sum = sumArr(arr);
System.out.println(sum);
}
}
더 읽어보기 »

JVM의 메모리 구조

이 글을 보기 전에 아래 글을 참조하면 더 이해가 잘 간다.
(C/C++) 참고용 정리 - 메모리 영역(Code, Data, Stack, Heap)

  • Method Area
    클래스 데이터가 들어간다.
    즉 클래스 변수(static 변수)가 들어간다.
    프로그램 실행되자마자 적재되고 끝날 때까지 사라지지 않는 놈이다.
    기본적인 메모리 영역의 Data 영역에 해당한다.
  • Call Stack
    메소드가 호출되면 해당 메소드를 콜스택에 push한다.
    제어권이 이전에 실행 중이던 메소드에서 Stack의 top에 위치한 메소드로 이동하게 된다.
    이전에 실행 중이던 메소드는 대기 상태가 되고 호출한 메소드의 작업이 끝날 때까지 대기하게 된다.
    그러면서 해당 메소드 만의 스코프를 생성한다.
    별도의 스코프를 생성하므로 지역 변수가 이곳에 존재한다.
    해당 메소드 아래 있는 메소드가 해당 메소드를 호출한 메소드가 된다.
    JVM은 프로그램이 실행되면 일단 main 메소드를 찾아 콜 스택에 push하게 된다.
    그리고 메소드의 작업에 필요한 메모리 공간을 콜스택이 제공해주고,
    작업을 마치게 되면 할당 되었던 메모리 공간은 반한된다.
    기본적인 메모리 영역의 Stack에 해당한다.
  • Heap
    클래스의 인스턴스가 생성되는 공간.
    인스턴스 변수들이 들어간다.
    new 연산자를 쓰므로 동적 할당이라고 할 수 있다.
    메모리 상에서 해제는 가비지 컬렉터가 자동으로 수행한다.
    기본적인 메모리 영역의 Heap에 해당한다.

학교에서 클래스를 할당하는 한 가지 방법 밖에 배우지 않았다.
동적 할당에 대해서 배우지 않았기 때문인데…
왜 학교에서는 이런 심도있는 내용들은 1도 가르쳐주지 않는 걸까?
학교에서 이런 내용까지 알려준다면 좀 더 재미나게 수업에 임할 수 있을텐데…
정말 안타깝다 ㅠㅠ
이해를 돕기 위해 아래 포스트를 한 번 보는 걸 추천한다.
(C/C++) 참고용 정리 - 메모리 영역(Code, Data, Stack, Heap)

학교에서 배운 방법(정적 할당)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

class test {
private:
int num;
public:
void setNum(int n) {num = n;}
int getNum() {return num;}
};

int main() {
test t;
t.setNum(22);
cout << t.getNum() << endl;
cout << t; // 에러, t가 가지고 있는 순수 값은 못 본다. 왜일까? ㅠㅠ
return 0;
}

test 클래스의 인스턴스인 t는 스택 영역에 올라가게 된다.
사실 자바를 먼저 배우고 C++을 그 이후에 배워서…
자바에서는 저렇게 선언하면 참조변수만 선언한 격이라
클래스의 인스턴스가 생성되지 않아서 할 수 있는 게 1도 없었는데…
자바에서는 클래스의 정적 할당이 없어서 그랬나 보다.

더 읽어보기 »

드디어 오늘부터 객체지향 프로그래밍(OOP, Object Oriented Programming) 파트를 나가기 시작했다.
이전까지는 다른 언어에도 대부분 있는 개념이었는데,
이제부터는 자바의 특성을 배울 차례인 것 같다.
객체 지향 언어는 C++/Javascript 등등이 있으므로 다른 언어를 배울 때도 유익할 것 같다.

객체? 클래스? 인스턴스?

객체지향하면 사람들은 클래스를 먼저 떠오르기 마련인 것 같다.
하지만 객체 != 클래스이다.
객체지향 언어의 하나인 자바스크립트를 통해 보도록 하자.
출처: JavaScript : 프로토타입(prototype) 이해

JavaScript는 클래스라는 개념이 없습니다.
그래서 기존의 객체를 복사하여(cloning)
새로운 객체를 생성하는 프로토타입 기반의 언어입니다.
프로토타입 기반 언어는 객체 원형인 프로토타입을 이용하여 새로운 객체를 만들어냅니다.
이렇게 생성된 객체 역시 또 다른 객체의 원형이 될 수 있습니다.
프로토타입은 객체를 확장하고 객체 지향적인 프로그래밍을 할 수 있게 해줍니다.

더 읽어보기 »

개발 배경

예전부터 테이블 태그는 참 헷갈렸다.
어떤 게 행이고 어떤 게 열인지…
가끔은 행과 열 조차도 헷갈렸다.

  1. scope=”row”, scope=”col”
  2. rowspan, colspan
  3. row, col

그래서 그냥 내 맘대로 합치고 바꾸고 제목 설정하고 싶었다.
한글이나 엑셀에서는 가능한 것 같지만 HTML에서는 불가능 한 것 같았다.
그러한 불편함을 감수하고자 1년 전에 몇 시간동안 간단히 만든 적이 있다.
동적 테이블 생성 초기 버전

더 읽어보기 »

이 글을 읽기 전에 (ES6) ajax 위주의 promise 실습를 먼저 읽을 것을 권한다.
ajax(XMLHttpRequest)와 promise에 대한 기본적인 이해가 있다면 상관없긴 하다.
조현영 님의 제보에 의하면 ie에서 fetch가 안 되고,
async/await 크롬과 오페라에서만 된다고 한다.
아래 사이트에서 확인 가능하다.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Browser_compatibility
ECMAScript Next compatibility table

fetch

다시 공부하다보니 XMLHttpRequest와 Fetch는 ECMAScript가 아니라고 한다.
브라우저에서만 쓰이는 API이기 때문에 babel에서도 지원해주지 않기 때문에
크로스 브라우징을 위해선 window.fetch polyfill을 쓰자.
우선 기존에 우리가 ajax를 하기 위해서 어떻게 했는지 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const jsonURL = "https://perfectacle.github.io/mock/test.json";

const getDataAjax = url => {
const xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "json";
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) { // 4 means request is done.
if(xhr.status === 200) { // 200 means status is successful
for(let key in xhr.response) { // 받아온 json 데이터의 키와 값의 쌍을 모두 출력.
if(xhr.response.hasOwnProperty(key))
console.log(`${key}: ${xhr.response[key]}`);
}
} else { // 통신 상에 오류가 있었다면 오류 코드를 출력.
console.error(`http status code: ${xhr.status}`);
}
}
};
xhr.send();
};

getDataAjax(jsonURL);
더 읽어보기 »
0%