(웹소켓 공부 중)
참고중: https://developer.mozilla.org/ko/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
https://websockets.spec.whatwg.org/#the-websocket-interface
웹소켓 API docs https://developer.mozilla.org/ko/docs/Web/API/WebSocket
문제풀이 - 프로그래머스 [1차]비밀지도17681
문제풀이 - 프로그래머스 [1차]비밀지도17681
십진수 9를 이진수 01001(2)로 변환하려면 2로 나눈 나머지를 역순으로 늘어놓으면 된다.
문자열을 역순으로 뒤집기
‘10010’ → ‘01001’로 바꾸기:
let s = '10010'
s = s.split("").reverse().join("");
// 만약 multibyte 문자들이라면 (𝌆나 ñ같은 문자들)
s = [...s].reverse().join("");
내가 푼 코드:
function solution(n, arr1, arr2) {
const recovered = [];
// 두 지도의 같은 행(0~4)별로 비교 진행
for (let j in arr1) {
// 이진수로 변환
let binary1 = toBinary(arr1[j], n);
let binary2 = toBinary(arr2[j], n);
// 둘다 공백(' ')인 경우 해독된 지도에도 공백으로 기록하고
// 그게 아니라면 벽('#')으로 기록하기.
let tempRow = '';
for (let i = 0; i < n; i++) {
if (binary1[i] == 0 && binary2[i] == 0){
tempRow += ' ';
} else {
tempRow += '#';
}
}
console.log(binary1, binary2, tempRow);
recovered.push(tempRow);
}
// 최종 해독 지도 반환
return recovered;
}
// 십진수 num을 받아 n자리 이진수로 변환한 문자열을 반환.
function toBinary(num, n) {
let binary = '';
// 2로 나눈 나머지를 순서대로 적기.
while (num !== 0) {
binary += num % 2;
num = parseInt(num / 2);
}
// n자리수보다 적게 끝나면 필요한 만큼 끝에 0붙이기.
for (let i = binary.length; i < n; i++) {
binary += '0';
}
// 이진수 문자열을 뒤집어서 반환.
return binary.split('').reverse().join('');
}
=>
테스트 1 〉 통과 (2.40ms, 33.5MB)
테스트 2 〉 통과 (2.82ms, 33.7MB)
테스트 3 〉 통과 (2.22ms, 33.6MB)
테스트 4 〉 통과 (2.52ms, 33.5MB)
테스트 5 〉 통과 (2.21ms, 33.5MB)
테스트 6 〉 통과 (2.84ms, 33.6MB)
테스트 7 〉 통과 (2.30ms, 33.5MB)
테스트 8 〉 통과 (2.26ms, 33.5MB)
JSON parse와 stringify 쌍
JSON parse와 stringify 쌍
JSON.parse()
서버단이든 프론트단이든 웹으로부터(…) 배달되는 데이터를 받을 때 사용됨.
// 인수로 '객체처럼 생긴' 문자열이 들어갔을 때 => '객체'가 반환됨:
JSON.parse('{"name":"John", "age":30, "city":"New York"}');
=> {name: 'John', age: 30, city: 'New York'}
// 인수로 '배열처럼 생긴' 문자열이 들어갔을 때 => '배열'이 반환됨 :
JSON.parse('[ "Ford", "BMW", "Audi", "Fiat" ]');
=> ['Ford', 'BMW', 'Audi', 'Fiat']
웹 서버로부터 오는 데이터는 항상 문자열이다.
이걸 자바스크립트의 ‘객체’나 ‘배열’ 타입으로 변환해주는 역할.
JSON.stringify()
서버단에서든 프론트단에서든, 웹상으로 데이터를 실어보낼 때 사용됨.
// 자바스크립트 객체를 문자열로 변환:
JSON.stringify({name: "John", age: 30, city: "New York"})
=> '{"name":"John","age":30,"city":"New York"}'
// 자바스크립트 배열을 문자열로 변환:
JSON.stringify(["John", "Peter", "Sally", "Jane"])
=> '["John","Peter","Sally","Jane"]'
웹 서버로 보내는 데이터는 항상 문자열이어야 한다.
그래서 자바스크립트의 객체(또는 배열) 타입을 문자열로 변환해주는 역할.
활용 예시:
local storage같은 곳에 데이터를 저장해 놓을 때와 다시 빼올 때, 문자열(text)는 항상 유효한 데이터 타입이므로 이렇게 활용해볼 수 있다:
// 웹 local storage에 데이터 저장하기 :
const myObj = {name: "John", age: 31, city: "New York"};
const myJSON = JSON.stringify(myObj);
localStorage.setItem("testJSON", myJSON);
// 웹 local storage에서 데이터 꺼내오기 :
let text = localStorage.getItem("testJSON");
let obj = JSON.parse(text);
document.getElementById("demo").innerHTML = obj.name;
또 웹 소켓을 이용해 데이터를 보내고 받을 때도 이렇게 활용하게 된다:
// 폼에 있는 메세지 보내기
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
const obj = { "type": "message" , "params": { "value": outgoingMessage }}
socket.send(JSON.stringify(obj));
// => '{"type":"message","params":{"value":"메세지"}}'
return false;
};
// 들어오는 메세지를 div에 더하기
socket.onmessage = function(event) {
let incomingMessage = event.data;
const obj = JSON.parse(incomingMessage);
let messageElem = document.createElement('div');
messageElem.textContent = obj.params.value;
document.getElementById('messages').prepend(messageElem);
};
⇒ 두 예시를 보니…
데이터를 보내는 방향이 어느 쪽이든, 웹을 한 번 거쳐서(?) 데이터가 오가게 된다면 어쨌든 ‘문자열’로 변환돼서 왔다갔다 하게 된다는 것이 핵심인 듯하다. 즉 프론트 → 서버로 데이터를 보낼 때도 JSON.stringify()로 포장하고 JSON.parse()로 해석해서 읽고, 반대도 마찬가지다.
쉽게 말해 프론트 → 서버
라기보다는
프론트(자바스크립트 언어) → 웹 HTTP(플레인 텍스트) → 서버(자바스크립트 언어)
프론트(자바스크립트 언어) ← 웹 HTTP(플레인 텍스트) ← 서버(자바스크립트 언어)
이렇게 3단계라고 보는 게 더 이해하기 쉽겠다. 그래서 웹이라는 운송 장치를 지날 땐 JSON.stringify()
포장이 필요하고 다 배달돼서 다시 프로그래밍 언어로 해석되어야 할 때는 JSON.parse()
로 포장 해제되는 것이다.
Document.forms
Document.forms
문서에 포함되어 있는 모든 <form>요소를 HTMLCollection 타입으로 반환함. 여기에 담긴 <form> 요소 하나하나는 HTMLFromElement 타입이다. 아무런 <form> 태그도 없으면 빈 콜렉션으로 반환됨.
// form이 여럿 있을 때 인덱스로 Form(과 그 안의 요소)에 접근하기 :
<body>
<form id="robby">
<input
type="button"
onclick="alert(document.forms[0].id);"
value="robby's form" />
</form>
<form id="dave">
<input
type="button"
onclick="alert(document.forms[1].id);"
value="dave's form" />
</form>
<form id="paul">
<input
type="button"
onclick="alert(document.forms[2].id);"
value="paul's form" />
</form>
<script>
// const selectForm = document.forms[index];
// const selectFormElement = document.forms[index].elements[index];
</script>
// Form과 그 안의 요소들의 'name(이름)'으로 접근하기 :
<body>
<form name="login">
<input name="email" type="email" />
<input name="password" type="password" />
<button type="submit">Log in</button>
</form>
<script>
const loginForm = document.forms.login; // 혹은 document.forms['login']
loginForm.elements.email.placeholder = "test@example.com";
loginForm.elements.password.placeholder = "password";
</script>
</body>
Form을 제출하는 2가지 방법
Form을 제출하는 2가지 방법
- form 안에 달려 있는
<input type="submit">
나<input type="image">
버튼을 클릭한다.
- form 안의 input field 에 포커싱하고(커서 올린 채로)
Enter
를 누른다.⇒ 2번째 경우,
<input type="submit">
버튼에click
이벤트가 발생했다고 판단하게 됨.// 예시: <form onsubmit="return false"> <input type="text" size="30" value="Focus here and press enter"> <input type="submit" value="Submit" onclick="alert('click')"> </form>
submit 이벤트를 등록하는 3가지 방법
submit 이벤트를 등록하는 3가지 방법
: Form이 제출될 때(=<input type="submit">
버튼이 눌렸을 때) 실행될 메소드를 연결시켜줌.
서버로 form을 전달하기 전에 적절한 형식인지 검사하기 위한 용도로 사용한다.
- HTML 문서에 (인라인으로):
<element onsubmit="myScript"> // 예시: <form onsubmit="myFunction()"> ... </form> <form onsubmit="alert('submit!');return false"> ... </form>
⇒ 보아하니, 인라인 방식의 따옴표 안에 그냥 자바스크립트 코드를 그대로 넣어버릴 수 있는 듯 하다. 매번 함수 호출만 했었는데.
- 자바스크립트에 :
object.onsubmit = function(){myScript}; // 예시: // <form name="publish">...</form> document.forms.publish.onsubmit = function() { ... }
- 자바스크립트에서
addEventListener()
메소드로 이벤트 붙여주기 :object.addEventListener("submit", myScript);
⇒ 1번에서 3번으로 갈수록 더욱 현대적이고 추천하는 방식이라고 한다. (인라인 방식은 매우 비추)
submit 이벤트 핸들러로 Form 양식 검사하기 예시:
만약 텍스트 필드가 비었다면, 우리는 이벤트 객체에 있는 — 양식 제출을 멈추는 — preventDefault()
함수를 호출하고 그리고서 유저에게 무엇이 잘못되었는지를 말하기 위해 양식 아래에 있는 단락에 에러 메시지를 표시합니다.
// HTML
<form id='this-form'>
<div>
<label for="fname">First name: </label>
<input id="fname" type="text">
</div>
<div>
<label for="lname">Last name: </label>
<input id="lname" type="text">
</div>
<div>
<input id="submit" type="submit">
</div>
</form>
<p></p>
// JavaScript
const form = document.querySelector('form');
const fname = document.getElementById('fname');
const lname = document.getElementById('lname');
const para = document.querySelector('p');
form.onsubmit = function(e) {
if (fname.value === '' || lname.value === '') {
e.preventDefault();
para.textContent = 'You need to fill in both names!';
}
alert(e.target.id); // 'this-form'
// = this.id
}
⇒ e는 감지한 이벤트에 대한 정보를 담고 있는 이벤트 객체이다.
⇒ e.preventDefault()
로는 양식 제출을 그만두게 할 수 있다.
⇒ e.target
으로 이벤트가 발생한 문서 요소를 참조할 수 있으며 이는 this
와 같다..!
⇒ 이벤트 핸들러를 화살표 함수로 작성할 땐 this
키워드로 이벤트가 발생한 요소에 접근할 수 없고 꼭 e.target
을 써줘야 한다는 점 유의.
form.addEventListener("submit", (event) => console.log(event.target.value));
출처: https://developer.mozilla.org/ko/docs/Learn/JavaScript/Building_blocks/Events
참조: https://www.daleseo.com/js-dom-event-handling/
자바스크립트로 Form 처음부터 끝까지 만들어서 제출해버리기
자바스크립트로 Form 처음부터 끝까지 만들어서 제출해버리기
form.submit()
메소드를 이용한다.
특이사항: 이 방법으로 하면 submit 이벤트가 격발되지 않는다. 왜냐면 이미 프로그래머가 필요한 ‘Form 제출 전 사전 검사’를 다 하고서 수동으로 보내는 거라고 판단하기 때문에.
// 예시:
let form = document.createElement('form');
form.action = 'https://google.com/search';
form.method = 'GET';
form.innerHTML = '<input name="q" value="test">';
// the form must be in the document to submit it
document.body.append(form);
form.submit();
출처:
이벤트 전파 - 버블링과 캡처링
이벤트 전파 - 버블링과 캡처링
이벤트 전파: 이벤트가 발생했을 때 브라우저가 이벤트 리스너를 실행시킬 대상 요소를 결정하는 과정. 여러 개의 부모-자식 요소에 이벤트들이 겹쳐 있을 때 무슨 이벤트부터 실행시킬지를 결정하기 위함이다.
버블링 이벤트 전파(=바텀 업 전파)
: 이벤트가 발생한 요소에 걸린 리스너가 먼저 실행되고, 점차로 DOM 트리를 따라 위로 올라가면서 부모 리스너가 실행되고, 그 부모 리스너가 실행되고… 하는 식으로 전파되는 방식. Document 위의 Window 객체까지 간다.
예시)
빨간 div, 노란 p, 초록 span 박스에 각각 클릭 이벤트가 걸려 있을 때, 가장 하위 후손인 초록 span을 클릭하면 :
⇒ ‘클릭’ 단어를 클릭했을 때 실행되는 이벤트 순서를 잘 보면 span(자기자신) → p(부모) → div(조상) 순서임을 알수 있다.
⇒ 버블링 전파 방식의 용도: 어차피 부모의 부모까지 싹 훑어서 이벤트 리스너를 실행하게 되므로, 만약 여러 요소에 공통으로 적용되는 이벤트를 걸어주고 싶다면 여러 개에 일일이 이벤트 리스너를 등록할 필요 없이 공통 조상 요소에 한 번만 등록하면 된다는 이점이 있다.
캡처링 이벤트 전파(=탑 다운 전파)
: DOM트리의 최상위(Window 객체)에 걸린 리스너가 먼저 실행되고, 점차 아래로 내려가면서 이벤트가 실제로 발생한 요소까지 전파되는 방식.
사용방법: addEventListener() 메소드의 세 번째 인수에 true를 전달한다.
⇒ ‘클릭’ 단어를 클릭했을 때 실행되는 이벤트 순서를 잘 보면 div(조상) → p(부모) → span(자기자신 이벤트) 순서임을 알수 있다.
⇒ 캡처링 전파 방식의 용도: 실제 이벤트의 대상이 되는 요소에 이벤트가 전달되기 전에 상위 요소에 등록된 이벤트 리스너가 이를 가로채거나 잡아내는, 일명 ‘이벤트 취소 기법’을 구사할 수 있다.
이벤트 전파 막기와 기본 동작 막기
전파 막기는 event.stopPropagation()
으로, 기본 동작 막기는 해당 이벤트의 event.preventDefault()
로 할 수 있다.
예시)
빨간 div, 노란 p, 초록 span 박스에 각각 캡쳐링식(=탑다운 전파) 클릭 이벤트가 걸려 있을 때, 가장 상위 조상인 빨간 div에 전파 막기를 걸어놓은 경우 :
⇒ ‘클릭’ 부분을 다시 클릭해보면 예상대로 바깥 div 클릭 이벤트만 실행되고 안쪽의 p와 span에 걸린 이벤트는 실행되지 않음을 볼 수 있다.
- 의문점: ‘박스’ 부분에 걸린 링크를 ‘기본 동작 막기’하는
event.preventDefault()
메소드는 다른 조상 요소에 걸리는event.stopPropagation()
메소드와 충돌이 나는 듯하다.- 조상 요소에
event.stopPropagation
(O) + 본인 링크 태그에event.preventDefault
(O) ⇒ event.preventDefault()가 제대로 동작하지 않을 뿐만 아니라 event.stopPropagation()도 링크가 실행되는 것을 막지 못함. 다른 클릭 이벤트들은 다 잘 무시되는데 말이다.
- 조상 요소에만
event.stopPropagation
(O) + 본인 링크 태그에event.preventDefault
(X) ⇒ 역시나 조상 요소에 걸린event.stopPropagation
가 링크 실행을 막지 못한다.
- 조상 요소에
event.stopPropagation
(X) + 본인 링크 태그에만event.preventDefault
(O) ⇒ 이 경우에만 본인의 링크 이동이 막아진다.
- 조상 요소에
⇒ 종합해보면 ‘전파 방지’와 ‘기본 이벤트 막기’ 코드가 둘 다 있을 때, 전파 방지는 대강 잘 작동하지만 기본 이벤트 막기는 동작하지 않는 경우가 있다. 또 link 태그같이 유난히 기본 이벤트가 강한(?) 것들은 그 전 단계에서 이벤트 전파가 막혔어도 꾸역꾸역 실행되는 듯하다.
참고: https://www.tcpschool.com/javascript/js_event_eventListenerCall
이벤트 기본 동작을 취소하는 3가지 방법
이벤트 기본 동작을 취소하는 3가지 방법
1. inline 방식
이벤트의 이턴값이 false이면 기본 동작이 취소된다(..!!!!).
<form onsubmit="alert('submit!'); return false"> ... </form>
2. property 방식
역시나 리턴 값이 false이면 기본동작이 취소된다.
// 폼에 있는 메세지 보내기
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
const obj = { "type": "message" , "params": { "value": outgoingMessage }}
socket.emit('message' ,JSON.stringify(obj));
return false;
};
⇒ 아… 이래서 return false를 쓴 거구나. Form 태그에 있는 기본 동작(action과 method에 따라 서버로 데이터 보내기)을 막으려고!
3. addEventListener 방식
이벤트 객체의 preventDefault
메소드를 실행하면 기본 동작이 취소된다.
<p>
<label>prevent event on</label>
<input id="prevent" type="checkbox" name="eventprevent" value="on" />
</p>
<p>
<a href="http://opentutorials.org">opentutorials</a>
</p>
<p>
<form action="http://opentutorials.org">
<input type="submit" />
</form>
</p>
<script>
document.querySelector('a').addEventListener('click', function(event){
if(document.getElementById('prevent').checked) // 링크 동작 금지
event.preventDefault();
});
document.querySelector('form').addEventListener('submit', function(event){
if(document.getElementById('prevent').checked) // 폼 submit(페이지갱신) 동작 금지
event.preventDefault();
});
</script>
참고: https://inpa.tistory.com/entry/JS-📚-이벤트-기본-동작-취소-방법
Uploaded by N2T