• Manipulating Elements, 요소 조종하기

 자바스크립트의 기본적인 목적은 웹사이트에 동적인 움직임을 주기 위함이다. 그러므로 요소를 선택해서 변화시킬 수 있어야 한다. 앞에서 요소를 선택하기 위한 방법으로 querySelector, querySelectorAll, getElementById, get ElementsByClassName, getElementsByTagName을 썼었다.(get을 쓸 때 id를 제외하곤 Element에 s가 붙는다)

 

 이번에는 선택된 요소에 class를 추가하거나 제거하고, text는 어떻게 추가하는지 등등, 요소를 조종하는 방법을 알아보겠다.

 class를 조종하는 방법에는 기본적으로 add, remove, toggle가 있다.

 

- add : class에 원하는 class name을 추가한다.

class에서 athing 다음에 world가 추가되었다.

- remove : class에 원하는 class name을 제거한다.

class에서 athing 다음에 world가 제거되었다.

- toggle : class에 원하는 class name이 없다면 추가하고, 원하는 class name이 이미 존재한다면 제거한다. 그리고 전자의 경우에는 true를 출력하고, 후자의 경우에는 false를 출력한다.

전자의 경우, class name에 world가 없었기 때문에 world라는 name이 class에 추가되고, true가 출력된다. 곧바로 다시 toggle을 실행할 경우, 이미 class name에 world가 존재하기 때문에 world라는 name이 class에서 제거되고 false가 출력된다.

 

 요소 자체를 추가하고 제거하는 방법은 다음과 같다.

 

- createElement : 요소를 생성할 수 있다.

menu라는 변수에 a 태그 요소를 담았다.

- setAttribute : 요소에 속성과 그 속성의 값을 부여할 수 있다.

하이퍼링크 속성을 추가했다.

- appendChild : 해당 태그의 맨 끝에 요소를 추가한다.

span이라는 부모 요소 안의 마지막에, menu라는 자식 요소를 추가했다.
menu 요소가 추가되었다.

- textContent : 요소의 text를 제어할 수 있다.

- style : CSS 요소를 제어할 수 있다.

CSS 속성이 추가되었다.

 

 Quiz

아래 두가지 예제 코드의 차이점을 분별하시오.

 

1.

const something = document.createElement("p");

for (let i = 0; i < 5; i++) {
  something.textContent = i;
  document.body.appendChild(something);
}

 

2.

for (let i = 0; i < 5; i++) {
  const something = document.createElement("p");
  something.textContent = i;
  document.body.appendChild(something);
}

 

 전자의 경우, something이 1번 선언된다. i가 0에서 4까지 5번 반복할 때마다 append는 되지만 반복될 때마다 추가되는 것이 아니라 text가 바뀔 뿐이다. 풀어 쓰면 다음과 같다.

const something = document.createElement('p');

something.textContent = 0;
document.body.appendChild(something);

something.textContent = 1;
document.body.appendChild(something);

something.textContent = 2;
document.body.appendChild(something);

something.textContent = 3;
document.body.appendChild(something);

something.textContent = 4;
document.body.appendChild(something);

 something은 1번 선언되었기 때문에 하나의 something만 추가된다. 처음에는 0이 추가되었겠지만, 0이 1로 바뀌고 2로 바뀌고 3으로 바뀌고 4로 바뀌는 것이다. 웹에는 4만 출력된다.

 

 이와 다르게 후자의 경우는 something이 5번 선언된다. 그리고 중요한 것은, for문 안에서 선언된 변수는 1번 끝날 때마다 사라지고 다시 새로운 메모리를 할당 받는다. 따라서 i가 0에서 4까지 5번 반복할 동안 새로운 something이 선언된다. 풀어 쓰면 다음과 같다.

const something = document.createElement('p');
something.textContent = '0';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '1';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '2';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '3';
document.body.appendChild(something);

const something = document.createElement('p'); // 기존 something은 사라지고 새로운 something
something.textContent = '4';
document.body.appendChild(something);

 something이 선언될 때마다 text가 바뀌고 body에 추가된다. 웹에는 0부터 4까지의 숫자가 출력된다.

  • 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을 사용하는 것이다.

아직은 푼 사람이 많은 문제부터, 내가 모르는 문법은 필요없을 듯한 문제부터 시간이 날 때 풀고 있다.

 

 - 문제 설명 : 두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 return하는 함수, solution을 완성하세요. 예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.

 

 - 제한 조건

 1. a와 b가 같은 경우는 둘 중 아무 수나 return하세요.

 2. a와 b는 -10,000,000 이상 10,000,000 이하인 정수입니다.

 3. a와 b의 대소 관계는 정해져 있지 않습니다.

 

 - 입출력 예

a b return
3 5 12
3 3 3
5 3 12

 

 - 나의 풀이

function solution(a, b) {
    if (Math.abs((a-b)%2) === 1) {
        var add = (a+b)*(Math.abs(a-b)/2+0.5);
        return add;
    } else if (Math.abs((a-b)%2) === 0) {
        var add = (a+b)*Math.abs(a-b)/2 + (a+b)/2;
        return add;
    } else if (a === b) {
        return a;
    }
}

단순하게 모든 경우의 수를 고려했고 이번엔 Math를 사용했다.

 

a와 b를 빼서 홀수가 나온다면, a와 b사이에는 짝수 갯수의 숫자가 존재한다는 것이다. 예를 들어 a=3, b=8일 때, a-b는 절대값으로 5이며 그 사이에는 4, 5, 6, 7와 같이 4개로 짝수 갯수의 숫자가 존재한다. 그러면 맨 끝자리 3과 8을 더해주고, 이를 전체 갯수를 2로 나눈 만큼 곱해주면 된다. 전체 갯수는 (a-b)/2+0.5로 구해주면 된다.

 

a와 b를 더해서 짝수가 나온다면, a와 b사이에는 홀수 갯수의 숫자가 존재한다는 것이다. 예를 들어 a=3, b=7일 때, a-b는 절대값으로 2이며 그 사이에는 4, 5, 6와 같이 3개로 홀수 갯수의 숫자가 존재한다. 그러면 맨 끝자리 3과 7를 더해주고, 이를 전체 갯수를 2로 나눈 만큼 곱해주면 된다. 전체 갯수는 (a-b)/2로 구해주면 된다. 그 이후 중간 숫자 5가 남게 되는데, 이는 (a+b)/2이다. 이를 마지막에 더해주면 된다.

중간 숫자인 5가 남는다.

 

그리고 a와 b가 같은 숫자일 때는 단순하게 a가 출력되도록 했다.

'프로그래밍 > 프로그래머스 코딩테스트' 카테고리의 다른 글

짝수와 홀수  (0) 2021.12.03

바닐라코딩 프렙 가이드로 프로그래머스에 입문했는데 매일 1문제씩이라도 풀어주면 좋을 것 같다.

 

- 문제 설명 : 정수 num이 짝수일 경우 "Even"을 반환하고 홀수인 경우 "Odd"를 반환하는 함수, solution을 완성해주세요.

 

- 제한 조건

1. num은 int 범위의 정수입니다.

2. 0은 짝수입니다.

 

- 입출력 예

num return
3 'Odd'
4 'Even'

 

- 나의 풀이

function solution(num) {
    if ((num%2 === 0) || (num%2 === -0)) {
        return 'Even';
    } else if((num%2 === 1) || (num%2 === -1)) {
        return 'Odd';
    }
}

처음엔 좀 raw하게 작성했다. Math를 처음엔 되도록 쓰지 않는게 좋다고 해서 그랬다. 그리고 int형이라서 -0과 -1이 나머지가 될 수 있다는 것을 간과하기도 했었다.

 

*int형 : 정수형이고 값의 범위는 –2,147,483,648 ~ 2,147,483,647까지이다.

 

function solution(num) {
    if (Math.abs(num)%2 === 0) {
        return 'Even';
    } else if (Math.abs(num)%2 === 1)  {
        return 'Odd';
    }
}

위는 Math.abs를 사용했다. 이는 괄호 안의 수를 절대값으로 치환해주는 함수이다.

 

console.log(Math.abs(0)); // 0
console.log(Math.abs('')); // 0
console.log(Math.abs([])); // 0 
console.log(Math.abs(null)); // 0
console.log(Math.abs({})); // NaN
console.log(Math.abs([1, 2])); // NaN
console.log(Math.abs('abc')); // NaN
console.log(Math.abs()); // NaN

특이점으로, Math.abs()에서 ()안에  null, '' 혹은 []과 같은 빈 배열이 오면 0을 반환한다. 그리고 [1, 2]과 같은 배열, 'abc'와 같은 문자열, {}과 같은 빈 객체(혹은 중괄호), ()과 같은 아예 빈 값이 오면 NaN을 반환한다.

'프로그래밍 > 프로그래머스 코딩테스트' 카테고리의 다른 글

두 정수 사이의 합  (0) 2021.12.07

알고리즘 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']

 

+ Recent posts