나만 몰랐던 JS 상식 100가지_1편

Goody·2021년 1월 22일
2

자바스크립트

목록 보기
4/13

들어가며

자바스크립트에 기초 없이 입문하면서
헷갈리거나, 새롭게 알게 된 사실들을 정리한 글입니다.



표현식(expression) VS 문장(statement)

  • 표현식 : 값으로 평가될 수 있는 문.



리터럴(literal) VS 값(value)

  • 리터럴: 값을 프로그램 안에서 직접 지정한다는 의미. 리터럴은 값을 만드는 방법이다.
const room1 = "conference_room_a";
// room1은 변수를 가리키는 식별자,
// "conference_room_a" 는 문자열 리터럴인 동시에 room1의 값.



식별자(Identifier)

변수, 상수, 함수 이름을 부르는 용어.



객체 타입의 종류

  • Array
  • Date
  • RegExp
  • Map과 WeakMap
  • Set과 WeakSet



원시 타입들 대응하는 객체 타입

  • 숫자 : Number
  • 문자열 : String
  • 불리언 : Boolean

이들 객체에는 두 가지 목적이 있다. 하나는 Number.INFINITY 같은 특별한 값을 저장하는 것이고, 다른 하나는 함수 형태로 기능을 제공하는 것이다.

  • 일시적인 String 객체가 만들어지고, 그 안에 toUpperCase 함수가 들어 있다. JS는 함수를 호출하는 즉시 임시 객체를 파괴한다.
const s = "hello";
s.toUpperCase();	// "HELLO"
s.rating = 3;		// 에러가 뜨지 않는다!	(임시 String 객체 생성)
s.rating		//undefined	(임시 객체 파괴)



JS의 기본 숫자 형식은 더블(double) 이다.



JS는 10진수, 2진수, 8진수, 16진수의 네 가지 숫자형 리터럴을 인식한다.

  • 다만 어떤 리터럴 형식을 사용하더라도 결국 숫자는 더블 형식으로 저장된다.



16진수 표기에는 대문자와 소문자 둘 다 쓸 수 있다.



문자열을 여러 행에 나눠 써야 할 때는 문자열 병합이 가독성이 좋다.

const multiline = "line1\n" +
		  "line2\n" +
		  "line3\n";



웬만하면 Undefined 보다 NULL을 쓰자. (강제는 아님)



객체의 프로퍼티나 배열의 원소를 나타낼 때, 마지막 원소 뒤에 쉼표는 붙이지 않는 것이 좋다.

크게 상관은 없지만, IE버전 호환성, JSON 표기법에 따른 권장사항이다.

const arr = [1,2,3];
const arr2 =[1,2,3,];

const o = {one : 1,
	   two : 2,
	   three : 3};

const o = {one : 1,
	   two : 2,
           three : 3,};



날짜 객체에서는 월과 요일이 0부터 시작한다.

const halloween = new Date(2016, 9, 31);	// 9는 10월이다



parseIntparseFloat 은 기수(radix) 를 넘길 수 있으며, 변환 이전의 문자열이 엉망진창이어도 숫자만 인식해서 변환해준다.

const a = parseInt("16 volts", 10);		// 10진수 16
const b = parseInt("3a", 16);			// 10진수 58
const c = parseFloat("15.5 kph");		// 10진수 15.5



불리언 값을 1이나 0으로 바꾸고 싶을 때

const b = true;
const n = b ? 1 : 0;



배열을 문자열로 빠르게 전환하는 방법

const arr = [1, true, "hello"];
arr.toString();		// "1,true,hello"



값을 불리언으로 변환하는 방법

const n = 0;				// 거짓 같은 값
const b1 = !!n;				// false
const b2 = Boolean(n);		// false



같은 if 문 안에서 블록 문과 블록 없는 문을 섞어 쓰는 건 좋지 않다.



배열 내 원소 랜덤 출력하기

function rand(m,n) {
    return m + Math.floor((n-m+1)*Math.random());
}

function randFace() {
    return ["crown", "anchor", "heart", "spade", "club", "diamond"][rand(0,5)];
}

randFace();		// "anchor" or "heart" or ...



for 루프에는 다양한 패턴이 존재한다.

for(let temp, i=0, j=1; j<30; temp = i, i = j, j = i + temp)
	console.log(j);

// 무엇이 출력될까요?





for 루프의 다양한 패턴

for(let temp, i=0, j=1; j < 30; temp = i, i = j, j = i+temp) {
    console.log(j);
}
for(;;) console.log("I am forever!");
let s = '3';
let s = '3';
for(; s.length < 10; s = ' ' + s);
// s = "        3"
for(let x=0.2; x<3.0; x += 0.2) {
	console.log(x);
}

for(; !player.isBroke;) {
	console.log("Still playing!");
}



break 없는 case절은 동료에게 실수처럼 보일 수 있다.

switch(totalBet) {
	case 7:
		totalBet = funds;
		break;
	case 13: funds = funds - 1;	// totalBet이 13이면 case 11로 넘어가서 0으로 바꿈.
	case 11 : 
		totalBet = 0;
		break;
	case 21:
		totalBet = 21;
		break;
}

break 가 없는 case 13 에 대한 주석을 남겨 실수가 아님을 알린다.



switch 문의 defaultbreak 는 optional 이다.

하지만 웬만하면 쓰자.

switch 문의 간결한 표현법

switch(totalBet) {
	case 7 : totalBet = funds;	break;
	case 11: totalBet = 0;		break;
	case 13: totalBet = 0;		break;
	case 21: totalBet = 21;		break;
}



for 루프 밖에서 인덱스 번호 i가 필요할 때는 다음과 같이 하면 된다.

let i = 0;

for(; i < bigArrayOfNumbers.length; i++) {
	if (isPrime(bigArrayofNumbers[i])) break;
}

if (i === bigArrayOfNumbers.length) console.log("No prime Numbers!");
else console.log(`First prime number found at position ${i}`)



배열을 수정할 땐 감소하는 인덱스를 사용하자.

const arr = [1,2,3,4,5,6,7,8,9,10];

const deleteEven = arr => {
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] % 4 !== 0) arr.splice(i, 1);
    }
    console.log(arr);
}
deleteEven(arr);	// 기댓값 : [4, 8]  /  결과 : [2,4,6,8,10]
const foo = arr => {
    for(let i = arr.length; i >= 0; i--) {
        if(arr[i] % 4 !== 0) arr.splice(i, 1);
    }
    console.log(arr);
}
foo(arr); 			// 기댓값 : [4, 8]  /  결과 : [4, 8]



문자를 숫자로 간단하게 바꾸는 방법

const s = "5";
const y = 3 + +s;		// 문자에 단항 플러스(+) 를 넣어 숫자로 변환
y === 8 				// true



typeof null 의 반환값

object



심볼

심볼은 항상 유일하다.

다른 어떤 심볼과도 일치하지 않는다.

이런 면에서 객체와 유사하다. 객체는 모두 유일하기 때문.

심볼을 생성하는 방법은 다음과 같다.

const RED = Symbol("The color of a sunset!");
const ORANGE = Symbol("The color of a sunset!");
RED === ORANGE 	// false



객체

원시 타입과 달리 여러 값을 나타낼 수 있으며, 변할 수도 있다.

객체의 본질은 컨테이너이다.

컨테이너의 내용물은 시간이 지나면서 바뀔 수 있지만, 컨테이너가 바뀌는 건 아니다.

const obj = {};
  • 객체의 콘텐츠는 프로퍼티 또는 멤버라고 부른다.

  • 프로퍼티는 와과 으로 구성된다. 프로퍼티 이름은 반드시 문자열 또는 심볼이어야 한다. 값은 상관 X

  • 프로퍼티 이름이 유효한 식별자가 아니라면 계산된 멤버 접근자 [] 를 써야 한다.

obj["not an identifier"] = 3;
obj["not an identifier"];		// 3	
  • 객체에서 프로퍼티를 제거할 때는 delete 연산자를 사용한다.
delete obj.color;



정규표현식

regex 또는 regexp로도 쓴다.

문자열에서 필요한 복잡한 검색과 교체 작업을 비교적 단순하게 만든다. (지금은 복잡해 보인다..)

const email = /\b[a-z]0-9._-]+@[a-z_-]+(?:\.[a-z]+)+\b/;



do-while 문

while 문과 달리 조건이 false 이더라도 최소 한 번은 실행 되는 반복문이다.

let dobi = "slave";
do{
	console.log("dobi is free!");
}while(dobi !== slave);
    
// dobi is free!

while 문 내의 조건이 거짓임에도 불구하고 반복문이 한 번 실행되었다.



Truthy && Falsy

자바스크립트에서는 모든 데이터 타입을 참 같은 값거짓 같은 값으로 나눌 수 있다.

  • 거짓 같은 값(Falsy)
    • undefined
    • null
    • false
    • 0
    • NaN
    • '' (빈 문자열)
  • 이외에는 모두 참 같은 값(Truthy) 이나, 몇 가지는 염두에 두자.
    • 모든 객체, valueOf() 메서드를 호출했을 때 false를 반환하는 객체도 참 같은 값에 속한다.
    • 배열, 빈 배열도 참 같은 값에 속한다.
    • 공백만 있는 문자열 (" " 등)
    • 문자열 "false"



단축 평가

x가 거짓 같은 값이면 x && yy의 값을 평가할 필요도 없이 false 이다.

이런 동작을 단축 평가 (short-circuit evaluation) 라고 한다.

  • 두 번째 피연산자에 부수 효과(side effect) 가 있다 하더라도, 단축 평가를 거치면 이를 무시할 수 있다.
const x = true;
let y = 0;
const result = x || y++;

console.log(y);		// 0



피연산자가 불리언이 아닐 때 논리 연산자가 동작하는 방법

  • 불리언이 아닌 피연산자에 대한 AND(&&)의 진위표
xyx && y
거짓 같은 값거짓 같은 값x (거짓 같은 값)
거짓 같은 값참 같은 값x (거짓 같은 값)
참 같은 값거짓 같은 값y (거짓 같은 값)
참 같은 값참 같은 값y (참 같은 값)
  • 불리언이 아닌 피연산자에 대한 OR(||)의 진위표
xyx || y
거짓 같은 값거짓 같은 값y (거짓 같은 값)
거짓 같은 값참 같은 값y (참 같은 값)
참 같은 값거짓 같은 값x (참 같은 값)
참 같은 값참 같은 값x (참 같은 값)
  • 예시
const options = suppliedOptions || {name : "Default"};

// suppliedOptions 가 객체(참 같은 값)이면    options = suppliedOptions
// 		""		   가 null 혹은 undefined면 options = {name : "Default"}



조건(3항) 연산자

조건 연산자는 if...else 문과 동등한 표현식이다.

const doIt = false;
const result = doIt ? "Did it!" : "Didn't do it.";
if(isPrime(n)) {
	label = 'prime';
} else {
	label = 'non-prime';
}

->

const label = isPrime(n) ? 'prime' : 'non-prime';

if-else 문이 매우 짧아진다.



해체 할당

ES6 에 도입된 기능으로, 객체나 배열내 원소들을 변수로 해체할 수 있다.

  • 객체 해체 예시
// 객체 선언
const obj = {b : 2, c : 3, d : 4};

// 해체 할당 ver.1
const {a, b, c} = obj;
a;	// undefined
b; 	// 2
c;	// 3
d;	// ReferenceError

// 해체 할당 ver.2
let a,b,c;
({a,b,c} = obj);

객체를 해체할 때는 반드시 변수 이름과 객체의 프로퍼티 이름이 일치해야 한다.

  • 배열 해체 예시
// 배열 선언
const arr= [1,2,3];
const arr2 = [1,2,3,4,5];

// 해체 할당 ver.1
let [x,y] = arr;
x;	// 1
y;	// 2
z;	// ReferenceError

// 해체 할당 ver.2
let [x,y, ...rest] = arr2;
x;		// 1
y;		// 2
rest;	// [3, 4, 5]



쉼표 연산자

쉼표 연산자는 표현식을 결합하여 두 표현식을 평가한 후,

두 번째 표현식의 결과를 반환한다.

let x = 0, y = 10, z;
z = (x++, y++);		// 10

쉼표 연산자는 우선순위가 가장 낮아 괄호를 사용했다.



void 연산자

피연산자를 평가한 후 undefined 를 반환한다.

<a href="javascript:void 0">Do nothing.<a>

브라우저에서 다른 페이지로 이동하는 일을 막을 수 있다.



함수의 매개변수 해체

  • 객체를 함수 내 변수로 해체
function getSentence({ subject, verb, object}) {
	return `${subject} ${verb} ${object}`;
}

const o = {
	subject = "I",
	verb = "love",
	object = "JavaScript",
};

getSentence(o);	// I love JavaScript
  • 배열을 함수 내 변수로 해체
function getSentence([subject, verb, object]) {
	return `${subject} ${verb} ${object}`;
}

const o = ["I", "love", "JavaScript"];

getSentence(o);		// I love JavaScript	



확산 연산자(...)를 써서 남는 매개변수 이용하기

function addPrefix(prefix, ...words) {
    const prefixedWords = [];
    for(let i = 0; i < words.length; i++) {
        prefixedWords[i] = prefix + words[i];
    }
    return prefixedWords;
}

addPrefix("con", "verse", "vex");	// ["converse", "convex" ]



매개변수에 기본값 주기

function f(a, b = "default", c = 3) {
	return `${a} - ${b} - ${c}`;
}

f(5, 6, 7);		// 5-6-7
f(5, 6);		// 5-6-3
f(5);			// 5 - `default` - 3
f();			// undefined - `default - 3



this

함수 바디 안에는 특별한 읽기 전용 값인 this 가 있다.

메서드를 호출하면 this 는 호출한 메서드를 소유하는 객체가 된다.

this는 함수를 어떻게 선언했느냐가 아니라 어떻게 호출했느냐에 따라 달라진다.

const o = {
	name: "Wallace";
	speack() {	return `My name is ${this.name!}`},
}

o.speak();	// 'My name is Wallace!'

thiso 에 묶인 이유는 speako의 프로퍼티여서가 아니라,

o 에서 speak 를 호출했기 때문이다.

클래스의 인스턴스 객체의 this 를 생각해보면 쉽다.



중첩된 함수 안에서 this 사용하기

함수 안에서 this가 들어있는 함수를 호출하는 경우, 내부 함수에서의 this 는 엉뚱한 객체를 가리키는 경우가 많다.

const o = {
    name : "Julie",
    greetBackwards: function() {
        function getReverseName() {
            let nameBackwards = '';
            for(let i = this.name.length-1; i >=0; i--) {
                nameBackwards += this.name[i];
            }
          return nameBackwards;
        }
        return `${getReverseName()} si eman ym ,olleH`;
    }
};
o.greetBackwards();

// Cannot read of property 'length' of undefined

getReverseName() 은 객체 o 안에 있음에도 this 가 undefined로 할당된다.

위 코드는 함수 안의 함수로 들어가기 전에, this 를 변수에 저장해주면 해결할 수 있다.

const o = {
    name : "Julie",
    greetBackwards: function() {
        const self = this;	// this 를 self 라는 변수에 할당
        function getReverseName() {
          let nameBackwards = '';
          for(let i = self.name.length-1; i >=0; i--) {
              nameBackwards += self.name[i];
          }
          return nameBackwards;
        }
        return `${getReverseName()} si eman ym ,olleH`;
    }
};
o.greetBackwards();	

// `eiluj si eman ym ,olleH`



화살표 표기법

화살표 표기법은 function 이라는 단어와 중괄호 숫자를 줄이기 위해 고안된 단축 문법이다.

  • function 을 생략해도 괜찮다.
  • 함수에 매개변수가 하나 뿐이라면 괄호도 생략할 수 있다.
  • 함수 바디가 표현식 하나라면 중괄호와 return 도 생략할 수 있다.
  • 생성자 함수로는 사용할 수 없다.
const f1 = function() {return "hello!";}
const f1 = () => "hello!";

const f2 = function(name) {return `bye! ${name}`;}
const f2 = (name) => `bye! ${name}`;

const f3 = function(a, b) {return a + b};
const f3 = (a,b) => a + b;

화살표 함수는 위 예제와 달리 익명 함수를 만들어 다른 곳에 전달할 때 매우 유용하다.

  • 화살표 함수에서 this 는 정적으로(lexically) 묶인다.

    • 즉, 내부 함수 안에서 this 를 사용할 수 있다.
    const o = {
        name : "Julie",
        greetBackwards: function() {
            const getReverseName = () => {		// 내부 함수가 화살표 함수를 쓰면
                								// this 사용 가능
              let nameBackwards = '';
              for(let i = this.name.length-1; i >=0; i--) {
                  nameBackwards += this.name[i];
              }
              return nameBackwards;
            }
            return `${getReverseName()} si eman ym ,olleH`;
        }
    };
    o.greetBackwards();



apply로 배열 내 최대, 최소값 구하기

const arr = [2, 3, -5, 15, 7];
Math.min.apply(null, arr);	// -5
Math.max.apply(null, arr);	// 15

Math.min 과 Math.max 는 this 와 관계없이 동작한다.



정적 스코프

정적 스코프는 어떤 변수가 함수 스코프 안에 있는지 함수를 정의할 때 알 수 있다는 뜻이다.

const x = 3;

function f() {
	console.log(x);	
	console.log(y);	
}

{
	const y = 5;
	f();
}
// 3
// undefined



IIFE

Immediately Invoked Function Expression 의 준말이며,

선언 즉시 실행되는 함수이다.

count message = (function() {
	const secret = "I'm a Secret.";
	return `The secret is ${secret.length} characters long.`;
})();
console.log(message);

// `The secret is 6 characters long.`

변수 secret 은 스코프 안에서 보호되며, 외부에서 접근할 수 없다.



클로저

함수가 특정 스코프에 접근할 수 있도록 의도적으로 그 스코프에서 정의하는 것.

스코프를 함수 주변으로 좁히는(closing) 하는 것이라고 생각하면 편하다.

let globalFunc;		// 정의되지 않은 전역 함수
	{
		let blockVar = 'a';		// 블록 스코프에 있는 변수
		globalFunc = function() {
			console.log(blockVar);
		}
	}
globalFunc();				// "a"
  • 클로저를 통해 외부 스코프에 접근하는 방법
let f;
{
	let o = { note: "Safe"};
	f = function() {
		return o;
	}
}
let oRef = f();
oRef.note = "Not so safe after all!";



사각지대 (temporal dead zone)

let 으로 선언하는 변수는 선언하기 전까지 존재하지 않는다.

스코프 안에서 변수의 사각지대는 변수가 선언되기 전의 코드이다.



Strict 모드

암시적 전역 변수를 허용하지 않는 모드.



객체마다 다른 id 값 주기

class Person{
	constructor(name) {
		this.name = name;
		this.id = Person.nextId++;
	}
}
Person.nextId = 0;

const jamie = new Person("Jamie"),	// id = 0
    juliet = new Person("Juliet"),	// id = 1
    peter = new Person("Peter"),	// id = 2
    jay = new Person("Jay");		// id = 3



map과 filter 체인

const arr = [1,2,3,4,5];

const evenOfEven = arr.filter(x => x % 2 === 0)
                        .map(x => x * 2);

console.log(evenOfEven); //[4, 8]



각 단어를 첫글자에 따라 묶기

const words = ["Beachball", "Rodeo", "Angel", "Aardvark", "Xylophone", "November", "Chocolate", "Papaya", "Uniform", "Joker", "Clover", "Bali"];

const alphabetical = words.reduce((acc, x) => {
	if(!acc[x[0]]) {
		acc[x[0]] = [];
	}
	acc[x[0]].push(x);
	return acc;
}, {});



콜백을 메서드처럼 활용하는 방법

콜백을 받는 메서드들은 옵션으로 콜백을 호출할 때 this로 사용할 값을 받을 수 있다. 이 매개변수를 활용하면 콜백 함수를 메서드처럼 사용할 수 있다.

0개의 댓글