5주차 총 정리

5주차 즈음되서 과제를 4개나 끝내고 나니 나태해졌다...😅
총 복습을 한 번하고, 트위틀러 과제를 블로깅하기로 결정...!
꽤 잘 만든 편이니 하면서 복습도 해야겠다~


모던 자바스크립트 입문

복습은 모던자바스크립트 도서를 이용하였다 :)


CH01

factorial

함수는 이렇게 사용하는겁니다~하고 시작한다!

/* factorial */
function fact(n) {
  if(n <= 1) return n;
  return n * fact(n-1);
}

CH03

Symbol

심볼은 유일한 값으로 설정된다.

/* Symbol의 비교 */
var sym1 = Symbol();
var sym2 = Symbol();
console.log(sym1 === sym2) // false

심볼을 사용할 때는 다음 처럼 유일무이한 값으로 설정할 수 있다.
오목을 만든다면, 아래와 같이 변수를 둘 수 있다.

var NONE = Symbol("none");    // 돌이 없는 상태
var BLACK = Symbol("black");  // 흑돌
var WHITE = Symbol("white");  // 백돌

심볼과 문자열을 연결할 수 있다.

// Symbol.for()
var sym1 = Symbol.for("club");
var sym2 = Symbol.for("club");
console.log(sym1 === sym2) // true

// 연결된 문자열은 Symbol.keyFor() 로 확인한다.
var sym3 = Symbol("club");
var sym4 = Symbol.for("club");
console.log(Symbol.keyFor(sym3));  // undefined
console.log(Symbol.keyFor(sym4));  // club

Ch04

객체

자바스크립트는 원시 타입을 제외한 모든 값이 객체이다.

var card = {suit: '하트', rank: 'A'};
card.suit     // 하트
card['rank']  // A
card.color    // undefined

var obj = {};
console.log(obj) // Object{}

card.value = 10;
console.log(card) // {suit: '하트', rank: 'A', value: 10}

delete card.rank;
console.log(card) // {suit: '하트', value: 10}

인수 여러개를 우아하게 전달하는 방법

function setBallProperties(x, y, vx, vy, radius) { ... }
// setBallProperties(0, 0, 10, 15, 5); -> 인자 개수와 의미를 헷갈릴 수 있음.
var parameters = {
  x: 0,
  y: 0,
  va: 10,
  vy: 15,
  radius: 5
};
setBallProperties(parmeters);

객체의 메서드

객체 안에 프로퍼티로 함수를 추가할 수 있다.

var circle = {
  center: {x: 10, y: 10},
  radius: 2.5,
  area: function() {
    return Math.PI * this.radius * this.radius;
  }
};
circle.area // 19.6348540...

함수 사용의 장점

  1. 재사용 할 수 있다.
  2. 만든 프로그램을 이해하기 쉽다.
  3. 프로그램 수정이 간단해진다.

생성자

// 생성자의 사용
function Card(suit, rank) {
  this.suit = suit;
  this.rank = rank;
}
var card = new Card("하트", "♥︎");
console.log(card); // Card {suit: "하트", rank: "♥︎"}

생성자의 역할

생성자를 사용하면 이름은 같지만 프로퍼티 값이 다른 객체(인스턴스)를 여러 개 사용할 수 있다.

var card1 = new Card('하트', '♥︎');
var card2 = new Card('클로버', '♣︎');
var card3 = new Card('스페이드', '♠︎');

희소 배열

생각과는 다르게 동작해서 신기한 배열이다.

var a = ['A', 'B', 'C'];
a[4] = 'E';
console.log(a); // ["A", "B", "C", empty, "E"]
console.log(a.length); // 5
for(var i in a) console.log(i) // 0 1 2 4 -> 인덱스3의 자리가 비어있다. 길이는 5이지만 존재하지않는다.

Ch06

대화상자

브라우저에서 사용할 수 있다.

window.alert    // 경과 대화상자 표시
window.prompt   // 입력폼 대화상자 표시
window.confirm  // 확인/취소 버튼이 있는 대화상자 표시

console

흔히 사용하는 log, dir, error 외에도 유용한 것들이 있다.

console.dir     // 객체의 대화형 목록을 출력
console.error   // 오류 메세지 출력
console.info    // 메세지 타입 로그 출력
console.log     // 일반 로그 출력
console.time    // 처리 시간 측정용 타이머 시작
console.timeEnd // 처리 시간 측정용 타이머 출력.(밀리초)
console.trace   // 스택 트레이스 출력
console.warn    // 경고 메세지 출력

이벤트 처리기

함수를 이벤트 처리기로 등록하는 방법은 총 3가지이다.

  1. HTML 요소의 속성으로 등록
  2. DOM 요소의 프로퍼티로 등록
  3. addEventListener 메서드를 사용하여 등록

주요 이벤트 처리기 이름

다 중요한 것 같아서 다 표시한다. 모르면 찾아보면 된다 :)

onclick     // 클릭
ondblclick  // 더블 클릭
onmousedown // 마우스 버튼을 눌렀을 때
onmouseup   // 마우스 버튼에서 손가락을 뗐을 때
onmousemove // 마우스 포인터가 HTML 요소 위에서 움직였을 때
onmouseout  // 마우스 포인터가 HTML 요소를 벗어났을 때
onmouseover // 마우스 포인터가 HTML 요소 위에 놓여있을 때
onkeydown   // 키보드의 키를 눌렀을 때
onkeypress  // 키보드의 키를 누르고 손가락을 뗐을 때
onkeyup     // 키보드의 키에서 손가락을 뗐을 때
onchange    // input 요소의 값이 바뀌었을 때
onblur      // input 요소가 포커스를 잃었을 때
onfocus     // input 요소에 포커스를 맞추었을 때
onselect    // 텍스트 필드 드으이 텍스트를 선택했을 때
onsubmit    // 폼 제출 버튼을 눌렀을 때
onload      // HTML을 모두 읽어 들였을 때
onunloadWeb // 웹 페이지가 메모리에서 내려갈 때(예 : 다른 페이지 전환 시 )
onabort     // 페이지나 이미지 읽어 들이기가 중단될 때
onerror     // 페이지가 이미지를 읽어 들이는 동안 오류가 발생했을 때
onresize    // HTML 요소의 크기가 바뀌었을 때

DOM 요소에서 이벤트 리스너를 추가할 때, 함수 리터럴에 이름을 붙이면 디버깅에 도움이 된다.
아래 displayTime 처럼.

button.onclick = function displayTime() {
  var d = new Date();
  console.log('현재 시간은' + d.toLocaleString() + ' 입니다.');
}

Ch07

윤년 체크

// 400으로 나누어 떨어지거나, 4로 나누어 떨어지면서 100으로 나누어 떨어지지 않는...이라고 해석할 수 있다...
function isLeapYear(year) {
  if ( (year % 400 === 0) || ((year % 4 === 0) && (year % 100 != 0)) ) return true;
  return false;
}

순차 검색

하나씩 순차대로 검색하는 느린 방식.

function linearSearch(num, array) {
  let i = 0;
  let n = array.length;
  while(i < n && num > array[i]) i++;
  if(x === array[i]) return i;
  return null;
}
let a = [2, 4, 7, 12, 15, 21, 34, 35, 36, 46, 57, 70, 82, 86, 92, 99];
console.log(linearSearch(35, a)); // 7

이진 검색

반 나눠서 있는지 없는지 검사하는 꽤 빠른 방식.
아래에서 count로 조사해보니 고작 4번만에 발견한다.

function binarySearch(num, array) {
  let n = array.length;
  let left = 0, right = n - 1, count = 0;
  while(left < right) {
    count++;
    let middle = Math.floor((left + right) / 2);
    if(num <= array[middle]) {
      right = middle;
    } else {
      left = middle + 1;
    }
  }
  if(num == array[right]) {
    console.log('count: ' + count);
    return right;
  }
  return null;
}
let a = [2, 4, 7, 12, 15, 21, 34, 35, 36, 46, 57, 70, 82, 86, 92, 99];
console.log(binarySearch(35, a)); 
// count: 4 
// 7

Ch08

IIFE

즉시 실행함수를 활용한 factorial

(function fact(n) {
    if(n <= 1) return n;
    return n * fact(n - 1);
})(5)
// 120

rest

arguments가 불편한 나로서는 rest가 참 좋다 :)
유사배열이 싫다...

function conc(sep, ...rest) {
    let s = '';
    for(let i = 0; i < rest.length; i++) {
        s += rest[i];
        if(i < rest.length-1) s += sep;
    }
    return s;
}
console.log(conc(' / ', 'apple', 'banana', 'carrot')) // "apple / banana / carrot"

this

함수가 호출되어 실행되는 시점에 this 값이 결정된다.
이 this 값은 '함수가 호출되었을 때그 함수가 속해 있던 객체의 참조'이며,
실행 문맥의 디스바인딩 컴포넌트가 참조하는 객체이다.

var tom = {
  name: "Tom",
  sayHello: function() {
    console.log("Hello!" + this.name);
  }
}
tom.sayHello(); // Hello! Tom
// sayHello 메서드가 호출되는 실행 문맥의 디스 바인딩 컴포넌트가 가리키는 객체가 tom이다.
// 따라서 다음처럼 다른 객체의 프로퍼티에 대입할 수도 있다.
var huck = {name: 'Huck'};
huck.sayHello = tom.sayHello;
huck.sayHello(); // Hello! Huck

this의 상황별 객체

  1. 최상위 레벨의 this : 전역
  2. 이벤트 처리기 안의 this : 이벤트가 발생한 요소 객체
  3. 생성자 함수 안의 this : 그 생성자로 생성한 객체
  4. 생성자의 prototype 메서드 안의 this : 그 생성자로 생성한 객체
  5. 직접 호출한 함수 안의 this
// 함수를 호출 할 때 함수 앞에 아무것도 붙이지 않으면 전역 객체를 가리킴.
function  f() {console.log(this)}
f() // window 

// 붙여서 호출하면 디스 바인딩 컴포넌트가 그 객체를 가리킴.
var a = {};
a.f = f;
a.f(); // Object {f: f}
  1. apply와 call 메서드로 호출한 함수 안의 this : 디스 바인딩 컴포넌트가 가리키는 객체를 명시적으로 설정.

클로저(closure)

클로저 : 자기 자신이 정의된 환경에서 함수 안에 있는 자유 변수의 식별자 결정을 실행한다.

// ex: counter function
function makeCounter() {
  var count = 0;
  return function() {
    return count++;
  }
}
var counter = makeCounter();
console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2

모듈 패턴

즉시실행 함수의 내부에 작성한 함수나 변수는 프로그램 바깥에서 사용할 수 없다.
그래서 즉시 실행 함수에 객체로 구현한 이름 공간을 전역 변수로 넘겨서 공개할 함수를 이름 공간에 추가한다.
이를 이용해 모듈의 내부 구조는 은폐하고 원하는 함수만 공개 할 수 있다.

var Module = Module || {};
(function(_Module) {
  var name = 'NoName';            // 프라이빗 변수
  function getName() {            // 프라이빗 함수
    return name;
  }
  _Module.showName = function() { // 퍼블릭 함수
    console.log(getName());
  }
  _Module.setName = function(x) { // 퍼블릭 함수
    name = x;
  };
})(Module);
Module.showName(); // NoName
Module.setName('Tom');
Module.showName(); // Tom
// Module.getName => error

apply & call

this값과 함수의 인수를 사용하여 함수를 실행하는 메서드이다.
apply의 인수는 배열이고, call의 인수는 쉼표로 구분한 값의 목록이다.
첫번째 인수는 함수의 this, 두번째 인수는 함수의 인수를 순서대로 넣는다.
이때, 실제 배열 객체 대신 유사 배열 객체를 넘겨도 동작한다.
즉, 실행중인 함수의 arguments를 apply메서드에 넘겨도 실행할 수 있다.

function say(greetings, honorifics) {
  console.log(greetings + " " + honorifics + this.name);
}
var tom = {name: "Tom Sawyer"};
var becky = {name: "Becky Thatcher"};
say.apply(tom, ["Hello!", "Mr."]); // Hello! Mr.Tom sawyer
say.apply(becky, ["Hi!", "Ms."]);  // Hi! Ms.Becky Tahtcher
say.call(tom, "Hello!", "Mr.");    // Hello! Mr.Tom sawyer
say.call(becky, "Hi!", "Ms.");     // Hi! Ms.Becky Tahtcher

bind

say.bind(tom)은 tom객체를 함수 say의 this로 설정한 새로운 함수를 만들어서 반환한다.

function say(greetings, honorifics) {
  console.log(greetings + " " + honorifics + this.name);
}
var tom = {name: "Tom Sawyer"};
var sayToTom = say.bind(tom);
sayToTom('Hello!', 'Mr.');    // Hello! Mr.Tom Sawyer

일단 여기까지 공부했고, 나머진 차차 더 공부하면서 업로드해야겠다아 👨🏻‍💻