• DOM, Document Object Model

DOM이라고 하면 실제로 화면에 표현된 것들, HTML은 이 DOM을 설계하기 위한 MarkUp 언어 혹은 설계도라고 보면 된다. 이 HTML 문서를 통해 화면에 보여지는 것이 DOM이다. 그리고 이 DOM은 트리구조로 이루어져 있다.

 

뒤집어 보면 나무처럼 생겼다. ^.^
위 그림을 코딩했을 때

 

  • 요소 선택

사용자가 버튼을 클릭하면 글자가 바뀌는 등, 상호작용이 필요한데 이러한 동적임을 제공해주는 것이 자바스크립트를 통해 가능하다. 일단 무언가를 바꾸려면 선택되는 것이 먼저이기 때문에, 요소를 선택하는 방법을 아는 것이 중요하다. 프렙 가이드에서는 다음 사이트를 통해 예시를 보여주고 있다.

 

https://news.ycombinator.com 

document.querySelector / document.querySelectorAll

간단하게, document.querySelector('CSS선택자')를 이용하면 요소를 선택할 수 있다. 위의 경우는 .이 붙었으니 class가 rank인 요소들을 선택한 것이다. 이 사이트에서 class가 rank인 요소는 총 30개가 중복되어 있는데, document.querySelector는 이럴 때 맨 처음 것을 보여준다.

 

document.querySelectorAll은 말 그대로 선택한 모든 요소를 보여준다. 동시에 배열에 담아서 보여준다.

 

위처럼 for문을 이용해서 rank의 text를 모두 999로 바꾸어보았다. 그러면 해당 사이트에 뜨는 rank들은 다음과 같이 바뀐다.

원래는 1, 2, 3 ... 순서대로 매겨져 있었다.

 

querySelector는 id이든 class이든 모두 가져올 수 있다. 그저 .을 붙이느냐, #을 붙이느냐의 차이이다. querySelector가 선택자의 종류와 상관없이 가져오는 반면, 종류에 따라 맞게 써야하는 선택 방법도 있다.

 

이들은 .이나 #이 붙지 않는다. 그럴 필요가 없으니까. getElementsByClassName의 class가 rank인 것들 모두, getElementsByTagName은 tag가 span인 것들 모두 가져와 배열 형태로 돌려준다. id의 경우는 용도에 걸맞게 1개만 출력시킨다.

 

개발자들은 주로 querySelector와 querySelectorAll을 사용하는 편이다.

 

내가 선택한 요소의 '부모 요소' 혹은 '형제 요소'(다음에 위치한)를 선택하는 방법도 있다.

자식의 입장에서 부모를 선택하는 것이 아니라, 부모 입장에서 자식 요소들을 선택하는 방법 또한 있다. children을 사용하는 것이다.

알고리즘 Step을 공부하기 전까진 솔직히 알고리즘이라는 말 자체로 쫄았었다;;;

 

근데 Level 1이라서 쉬운 것도 있겠지만 생각보다 어렵지 않고 로직을 생각하면서 가능한 많은 경우의 수에 실행되도록 최적화시키는 과정이 재미...가 있다. ㅎㅎㅎ 어려운 문제를 만나면 어떻게 될지 모르겠다. ^^

 

  • 김서방 찾기

 - 문제 설명 : String형 배열 seoul의 element중 "Kim"의 위치 x를 찾아, "김서방은 x에 있다"는 String을 반환하는 함수, solution을 완성하세요. seoul에 "Kim"은 오직 한 번만 나타나며 잘못된 값이 입력되는 경우는 없습니다.

 

 - 제한 조건 : 

 1. seoul은 길이 1 이상, 1000 이하인 배열입니다.

 2. seoul의 원소는 길이 1 이상, 20 이하인 문자열입니다.

 3. "Kim"은 반드시 seoul 안에 포함되어 있습니다.

 

 - 입출력 예

seoul return
["Jane", "Kim"] "김서방은 1에 있다'

 - 나의 풀이

function solution(seoul) {
    for (let i = 0; i < seoul.length; i++) {
        var name = seoul[i];

        if (name === 'Kim') {
        return '김서방은 ' + i + '에 있다';
        }
    }  
}

알고리즘 첫 문제라서 조금 헤맸다. 사실... 인터넷에 검색해서 풀이를 찾아봤다. 아예 이 프로그래머스 문제 풀이가 어떻게 작동하는지 몰라 감을 잡히는 데에 좀 오래 걸렸다.

 

indexOf로 쉽게 풀 수도 있고 위처럼 for문을 사용해서 문제를 풀 수도 있다.

 

전체를 샅샅히 뒤져본다고 생각해보자. 처음부터 끝까지 하나하나 다 찾을거라고 생각해보면 for문을 이용하면 된다.

for문이 seoul이라는 배열의 크기만큼 반복되도록 length를 이용했다.

이 때 if문을 넣어 seoul의 i번째 index의 값이 'Kim'이랑 같을 때만 return문으로 답을 반환하도록 했다.

 

  • 가운데 글자 가져오기

- 문제 설명 : 단어 s의 가운데 글자를 반환하는 함수, solution을 만들어 보세요. 단어의 길이가 짝수라면 가운데 두글자를 반환하면 됩니다.

 

- 제한 조건 : s는 길이가 1 이상, 100이하인 string입니다.

 

- 입출력 예

s return
"abcde" "c"
"qwer" "we"

- 나의 풀이

function solution(s) {
    var rest = s.length%2;
    
    if (rest === 1) {
        var center = s.length/2 - 0.5;
        
        return s[center];
    } else if (rest === 0) {
        var center = s.length/2;
        
        return s.slice(center - 1, center + 1);        
    }
}

가장 많은 시간을 쓴 것 같다. 대략 1시간 정도?

 

짝수일 때 2개를 반환한다고 생각해서 오래 걸렸다. 막상 2개를 반환하니 틀렸다고 하더라. s = 'qwer'일 때 'w', 'e'를 반환하는 것이 아니라 'we'를 반환하는 로직을 짰어야 됐기 때문이다. 2개를 반환하는 것이 아니라 2개를 붙여서 반환해야 한다. 

 

이러면 오히려 쉬워진다. slice로 양 옆을 잘라주면 된다. 참고로 slice(a, b)는 a부터 b 바로 앞까지만의 문자열을 반환해준다. b는 포함 안된다는 것을 주의해야 한다.

 

혹은 문자열끼리 더했을 때는 단순히 붙여진다는 것을 이용하면 다음과 같이 해도 된다.

function solution(s) {
    var rest = s.length%2;
    
    if (rest === 1) {
        var center = s.length/2 - 0.5;
        
        return s[center];
    } else if (rest === 0) {
        var center = s.length/2;
        
        return s[center - 1] + s[center];        
    }
}

 

  • 수박수박수박수박수박수?

- 문제 설명 : 길이가 n이고, "수박수박수박수...."와 같은 패턴을 유지하는 문자열을 리턴하는 함수, solution을 완성하세요. 예를들어 n이 4이면 "수박수박"을 리턴하고 3이라면 "수박수"를 리턴하면 됩니다.

 

- 제한 조건 : n은 길이 10,000이하인 자연수입니다.

 

- 입출력 예

n return
3 '수박수'
4 '수박수박수'

 

- 나의 풀이

function solution(n) {
    var rest = n%2;

    if (rest === 0) {
        return '수박'.repeat(n/2);
    } else if (rest === 1) {
        return '수박'.repeat(n/2 - 0.5) + '수';
    }
}

일단 n이 10,000 이하의 자연수로 주어지긴 하지만 짝수인지 홀수인지 알 수 없다.

그러므로 나머지가 0이라면 n은 짝수이다.

짝수일 때는 단순하게 '수박'을 n/2만큼 repeat하면 된다.(repeat은 문자열을 반복해서 붙여지도록 해준다)

나머지가 1이라면 n은 홀수이다.

홀수일 때는 수박이 n/2 - 0.5번만큼(ex. n=5일 때, 5/2 - 0.5 = 2번) repeat되게 하고 마지막에 나머지 1만큼인 '수'를 붙여주면 된다.(문자열에서 +는 더한다는 느낌보다 단순히 문자열끼리 붙인다는 느낌이다)

배열이랑 객체의 차이를 모르고 있었다... 정확히는 객체가 뭔지 몰랐던 것 같다.

 

객체는 key와 그 key에 따른 value를 저장할 수 있는 구조 혹은 하나의 집합을 말한다. 만약 나를 하나의 객체로 보고 예시를 들자면

 

 - 이름 : 신승준

 - 나이 : 27

 - 고향 : Busan

 - 현 직장 : Samsung

 - Github ID : DelightJun

 

위와 같은 나라는 객체를 각각의 분류로 나누고 그 분류에 값을 넣어 표현하는 것이 key와 value로 이루어진 객체라고 볼 수 있겠다.

 

이를 JavaScript로 나타내면 다음과 같을 것이다.

var me = {
	name : 'SeungJun Shin',
	age : 27,
	hometown : 'Busan',
	workplace : 'Samsung',
	GithubID : 'DelightJun'
};

console.log(me); // {name: 'SeungJun Shin', age: 27, hometown: 'Busan', workplace: 'Samsung', GithubID: 'DelightJun'}

배열은 [과 ]으로 표현되지만 객체는 {와 }으로 표현되며 key와 value가 존재한다.

 

  • 접근

우리는 다음과 같은 방법으로 객체 안의 value에 접근할 수 있다.

var me = {
	name : 'SeungJun Shin',
	age : 27,
	hometown : 'Busan',
	workplace : 'Samsung',
	GithubID : 'DelightJun'
};

console.log(me);

var myName = me.name;
var myAge = me.age;
var myHometown = me['hometown'];

console.log(myName, myAge, myHometown); // 'SeungJun Shin' 27 'Busan'

 

  • 객체에 정보 혹은 key/value 혹은 Data 추가
var me = {
	name : 'SeungJun Shin',
	age : 27,
	hometown : 'Busan',
	workplace : 'Samsung',
	GithubID : 'DelightJun'
};

me.future = 'developer';
me['country'] = 'Korea';

console.log(me);

 

  • 객체 정보 수정
var me = {
	name : 'SeungJun Shin',
	age : 27,
	hometown : 'Busan',
	workplace : 'Samsung',
	GithubID : 'DelightJun'
};

me.age = 28;
me['workplace'] = 'I dont know';

console.log(me);

 

  • 객체 정보 삭제
var me = {
	name : 'SeungJun Shin',
	age : 27,
	hometown : 'Busan',
	workplace : 'Samsung',
	GithubID : 'DelightJun'
};

delete me.workplace;

console.log(me);

 

  • 객체 순회
const sample = {
	one : 1,
	two : 2,
	three : 3
};

for (let i in sample) {
	console.log(i);
	console.log(sample[i]);
}

for문을 사용해 객체 안을 순회?할 수 있다. for로 반복문을 만들고 let i를 통해 변수를 선언한다. 그리고 in sample로 i에 sample의 각 속성(key)이 하나씩 담기게 된다.

 

 1. sample의 첫 번째 key값이 i에 담긴다. i 속성이 출력된다. i에 담긴 key의 value가 출력된다.

 2. sample의 두 번째 key값이 i에 담긴다. i 속성이 출력된다. i에 담긴 key의 value가 출력된다.

 3. sample의 세 번째 key값이 i에 담긴다. i 속성이 출력된다. i에 담긴 key의 value가 출력된다.

 

  • 변수나 함수도 value로 받을 수 있다.
const myName1 = 'Jun';

function age() {
    return 27;
}

const me1 = {
    name : myName,
    age : age(),
};

console.log(me);
const property = 'name';

const obj = {
    [property] : 'Jun'
};

console.log(obj['property']); // undefined
console.log(obj.name); // Jun

[]를 써서 다른 변수에 저장된 문자열도 속성으로 가져올 수 있다.

 

  • Bracket notation
const person = {}; // Empty

// Dot notation
person.name = 'Jun';
person.age = 26;
person.languages = ['Korean'];

console.log(person);
console.log(person.age);
console.log(person.languages);

// Bracket notation
// person.한국 나이 = 27 // Error
// console.log(person.'한국 나이'); // Error // Error
// console.log(person.['한국 나이'); // Error
person['한국 나이'] = 27;
// console.log(person.'한국 나이'); // Error
console.log(person['한국 나이']);

JavaScript에서 '한국 나이'와 같이 식별되지 않는 속성은 Bracket notation을 사용해줘야 데이터 추가 및 삭제, 접근이 가능하다. 일반적으로 Dot notation을 많이 사용하는 편이다.

 

  • 속성(key)의 값(value)로 함수(function) 또한 대입 가능하다.
const itsme = {
    greet : function () {
                return 'hello';
            }
};

person.greet; // 함수 코드 자체가 출력된다.
person.greet(); // hello

greet은 이미 function이 되었기 때문에 person.greet;을 하면 함수 코드가 출력되고, person.greet();을 하면 function이 실행되어 hello가 출력된다.

 

  • Quiz
function foo (a) {
	return a + 3;
}

const arr = [ foo(1), foo(2), foo(3), foo('a') ];

console.log(arr); // 출력값은?



// [4, 5, 6, 'a3']

 

배열이란 어떤 값들을 순서대로 저장하는, 수학에서 보면 집합과 비슷한 느낌이다.

var fruits = ['apple', 'mongo', 'orange', 'grape', 'banana'];
var array1 = [1 , '3', true];
var array2 = [undefined, "", '', 'undefined', null, false, NaN, 0];

배열 안에 존재하는 'apple'이나 'mongo'와 같은 값들을 element, 요소라고 일컫는다.

 

  • 배열의 길이, length
var array2 = [undefined, "", '', 'undefined', null, false, NaN, 0];

function valueOfLength(x) {
    return x.length
}

console.log(valueOfLength(array2));

전에 배운 length처럼, 배열에서도 length를 통해 배열의 길이(배열 안에 존재하는 요소의 갯수)를 알 수 있다.

 

  • 요소 접근, index
var food = ['pizza', 'burger', 'chicken']
var myFavoriteFood = food[1];

console.log(myFavoriteFood); // 'burger'

var fibonacci = [1, 2, 3, 5, 8, 13];
console.log(fibonacci[4]); // 8
fibonacci[4] = null;
console.log(fibonacci[4]); // null

index를 통해 정해진 위치에 존재하는 요소에 접근할 수 있다. 또한 대입 연산자 '='를 통해 값을 바꿀 수도 있다.

 

  • 요소 추가 및 제거
var arr1 = [];
arr1[0] = true;
console.log(arr1[0]); // true

arr1[2] = true;
console.log(arr1[2]); // true

console.log(arr1); // [true, undefined, true]

단순하게 index와 대입 연산자 '='를 이용해서 요소를 추가할 수 있다.

var arr2 = ['alone'];
console.log(arr2); // ['alone']

arr2.push(1);
console.log(arr2); // ['alone', 1]
arr2.push(NaN);
console.log(arr2); // ['alone', 1, NaN]

arr2.pop();
console.log(arr2); // ['alone', 1]
arr2.pop();
console.log(arr2); // ['alone']

push를 통해 요소를 순서대로 추가할 수도 있고, pop을 통해 요소를 순서대로 제거할 수도 있다.

 

 

 

 

Array Methods : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array#%EB%A9%94%EC%84%9C%EB%93%9C

수학에서 배운 함수는 대개 다음과 같다. f(x) = ax^2 + bx + c

 

자바스크립트도 비슷하다. 하지만 수식이 아닌 우리가 원하는 코드가 들어간다. 만약 내가 두 개의 숫자를 더하는 함수를 만들고 싶다면(a + b와 같은 함수)

function add(a, b) {
	var result = a + b;
	console.log(result);
	return result;
}

add(17, 7); // 24

이렇게 코드를 짜면 된다. 한 가지 눈 여겨 볼 점은 return이다. 앞 전의 학습 내용들에서는 return 구문을 찾아볼 수가 없다. 그래서 웹 브라우저의 console창을 이용해 함수를 실행시키면 마지막 값으로는 항상 undefined가 떴었다. 이는 function이 실행되고 나서 최종적으로 돌려받는 값이 정해져 있지 않았기 때문이다. 하지만 위처럼 return result;와 같이 return 구문을 넣어주면 최종값을 돌려받게 되고 console창도 24가 마지막 값으로 뜨는 것을 확인할 수 있다.

 

function add(a, b) {
	var result = a + b;
	console.log(result);
	return result;
}

위 코드를 실행시켰을 때는 아무런 값도 돌려받지 않는다. 단지 add라는 함수가 어떤 것인지 선언만 했기 때문이다. 함수를 실행시키고 싶다면 add(x, y);와 같이 실행문을 작성해야 한다.

 

  • 중복을 줄여보자
for (let i = 1; i <= 3; i++) {
	console.log(i);
}

for (let i = 1; i <= 5; i++) {
	console.log(i);
}

for (let i = 1; i <= 7; i++) {
	console.log(i);
}

function을 배웠으니 써먹어보자. 위 코드를 보면 비효율적으로 중복을 사용하고 있다. 이러한 중복을 줄여줄 수 있는 것이 function을 사용하는 이유 중 하나다.

 

function repeatLog(count) {
	for (let i = 1; i <= count; i++) {
    	console.log(i);
  	}
}

repeatLog(3);
repeatLog(5);
repeatLog(7);

 

  • Return, 반환
function doSomething() {
    var a = 3;
    var b = 2;
    
    if (a > b) {
        return;
    }

    return 3;
}

var a = doSomething();
console.log(a); // undefined

return은 함수를 종료시킴과 동시에 종료 시 어떤 값을 반환할지 결정해주는 구문이다. 위 코드를 보자면, var a = doSomething();에서 function doSomething이 실행된다. 코드는 기본적으로 위에서 아래로 읽혀 내려오는데 doSomething함수는 return 3;보다 if문을 먼저 만난다. 3 > 2로 조건을 만족해 return;이 실행되는데 이로 인해 return 3;은 실행되지 않고 doSomething 함수가 종료된다. 따라서 return;으로 아무런 값이 반환되지 않았기 때문에 a를 출력해보면 undefined가 나온다.

 

function foo(a, b) {
    if (a < b) {
        return a;
    }
}
const result1 = foo(10, 20);
const result2 = foo(20, 20);

console.log(result1); // 10
console.log(result2); // undefined

 1번. FizzBuzz

 - 1부터 100까지 console.log를 실행한다.

 - 3의 배수는 "fizz"라는 문자열을 로그한다.

 - 5의 배수는 "buzz"라는 문자열을 로그한다.

 - 3과 5의 공배수는 "fizzbuzz"라는 문자열을 로그한다.

 - 나머지 숫자들은 해당 숫자 자체를 로그한다.

for ( var i = 1; i < 101; i++) {
	if ((i%15) === 0) {
		console.log("fizzbuzz", "i의 값 : " + i);
	} else if ((i%3) === 0) {
		console.log("fizz", "i의 값 : " + i);
	} else if ((i%5) === 0) {
		console.log("buzz", "i의 값 : " + i);
	} else {
		console.log(i, "i의 값 : " + i);
	}
}

3과 5의 공배수엔 15 배수의 문자열일 때에는 fizzbuzz가 최우선으로 실행되어야 한다. 따라서 15일 때 조건문을 가장 위에 넣었다. 3과 5가 겹치지 않는 숫자일 때에는 알아서 각자의 경우를 찾아가기 때문에 3과 5의 조건문 위치가 바뀌어도 상관 없다.

 

2번. Biggest Number

 - 가장 큰 수가 출력되도록 해라.

var a = -Infinity;
var b = NaN;
var c = Infinity;

if (a >= b && a >= c) {
    if (a === b && a === c) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 b = ' + b);
        console.log('가장 큰 수 c = ' + c);
    } else if (a === c) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 c = ' + c);
    } else if (a === b) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 b = ' + b);
    } else {
        console.log('가장 큰 수 a = ' + a);
    }
}   else if (b >= a && b >= c) {
    if (b === a && b === c) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 b = ' + b);
        console.log('가장 큰 수 c = ' + c);
    } else if (b === c) {
        console.log('가장 큰 수 b = ' + b);
        console.log('가장 큰 수 c = ' + c);
    } else if (b === a) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 b = ' + b);
    } else {
        console.log('가장 큰 수 b = ' + b);
    }
}   else if (c >= a && c >= b) {
    if (c === a && c === b) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 b = ' + b);
        console.log('가장 큰 수 c = ' + c);
    } else if (c === b) {
        console.log('가장 큰 수 b = ' + b);
        console.log('가장 큰 수 c = ' + c);
    } else if (c === a) {
        console.log('가장 큰 수 a = ' + a);
        console.log('가장 큰 수 c = ' + c);
    } else {
        console.log('가장 큰 수 c = ' + c);
    }
}   else {
        console.log('Is this Number?')
}

가장 큰 수를 고르라면 누구나 당연하게 별 생각 없이 큰 수를 고를텐데, 나의 뇌가 어떻게 이 큰 수를 비교할까를 생각하며 코드를 짜니 조금 머리 아프다.

 

a, b, c 모두 같을 수 있지 않은가! 숫자가 아닌 것이 섞여 있을 수도 있다. a = b = c일 때가 가장 우선 순위로 와야 한다는 것도 생각해야 한다. 안그러면 a = b =c 상황에서 a랑 b만 출력될 수도 있다.

 

별거 아닌 것 같은데도 길게 쓰여졌다... Prep Guide보면 Math.max를 사용하면 간단하단다. 어쨋든 위의 경우는 어떤 수를 대입하더라도, 숫자가 아닌 값을 대입하더라도 적절한 결과를 도출해내는 것을 확인했다.

 

이 또한 중복이 많은데 더 좋은 방법이 있을 것 같습니다. 알려주시면 감사드리겠습니다!

 

3번. Word Position

 - 문장 속에서 단어를 찾고 단어의 처음 Index와 마지막 Index를 출력하라.

var word = ',';
var sentence = 'Hi guys, just call me SeungJun. How are you?';

var first = sentence.indexOf(word);
var second = first + word.length - 1;

if (first === -1) {
    console.log('Sorry, I cannot find it.');
} else if (isNaN(first) === false && isNaN(second) === false) {
    console.log(first, second);
}

찾을 수 없다면 'Sorry, I cannot find it'이라는 문구를 띄우게 했다. 숫자가 아닌 값이 대입되면 에러가 뜬다. 또한 한 자릿수의 글자를 대입하게 된다면 이 또한 적절하게 값이 출력된다. 위의 경우 처럼 ,를 대입하면 7 7이 뜬다.

 

안타깝게도 H를 대입했을 때 두번 째 H의 Index값은 출력되지 않는다...

 

 

 

누군가에겐 간단한 문제이지만 나에겐 조금 생각이 필요한데 풀어나가고 해답이 보이는 과정이 꽤 재밌다! 방해 요소가 없는 한 몰입해서 하게 되고 꼭 풀고 싶어진다. 시간도 엄청 잘 지나간다. 이러한 문제를 푸는 것도 알고리즘의 한 부분일까?

 

+ Recent posts