2022 OSAM 해커톤 사전 온라인 교육에서 배운 내용입니다.
모르는 내용만 발췌하여 정리한 것이기 때문에 내용의 연결성이 부족한 점 양해 부탁드립니다.
호이스팅 : 스코프 내부 어디서든, 변수 및 함수의 선언은 스코프 최상위에 있는 것처럼 행동하는 것.
console.log(name);
var name = "yopark";
/* ----- JS 엔진 ----- */
var name; // 선언만 호이스팅된다. var는 name=undefined도 동시에 이루어짐
console.log(name); // undefined
name = "yopark"; // 할당은 호이스팅되지 않는다.
ECMAScript 2015의
let
과const
는 변수를 블록의 상단으로 끌어올리지만 초기화하지 않습니다. 변수가 선언되기 전에 블록 안에서 변수를 참조하게 되면[ReferenceError](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError)
를 발생시키게 되는데, 변수는 블록 시작부터 선언이 처리될 때까지 "temporal dead zone"에 위치하게 되기 때문입니다.
함수 스코프 | 블록 스코프 | |
---|---|---|
function | O | O |
if, for 등 | X | O |
쉽게 말해서, 함수 스코프에서는 if, for 문으로 만들어진 스코프에는 전혀 개의치 않는다!
따라서 다음의 예시도 정상 작동한다.
if (true) {
var name = "yopark";
}
console.log(name); // yopark
💡 클래스 내의 생성자(construct)와는 다른 개념입니다!
new
연산자를 붙여 실행해야 한다. function Item(title, price) {
// this = {};
this.title = title;
this.price = price;
this.showPrice = function() {
console.log(`가격은 ${price}원 입니다.`);
};
// return this;
}
const item1 = new Item("인형", 3000);
const item2 = new Item("지갑", 9000); // 유사한 객체를 여러개 만들 때 유리
item2.showPrice(); // 가격은 9000원 입니다.
function makeObj(key, val) {
return {
// key: val; 로 했더라면, {key: "male"} 이 저장되겠죠?
[key]: val
};
}
const obj = makeObj("성별", "male");
const user = {
name: "Mike"
};
const newUser = Object.assign({}, user);
// deepcopy, {name: "Mike"} Object 복사
const newUser2 = Object.assign({age: 30}, user);
// deepcopy, {age: 30, name: "Mike"} Object 병합
const newUser3 = Object.assign({name: "Tom"}, user);
// deepcopy, { name: "Mike" } 덮어쓰기
const newUser4 = Object.assign(user, {age: 30}, {gender: "Male"});
// 여러 객체를 한번에 병합할 수 있다. 이때, newUser4는 복사본이 아니라 user와 동일한 주소를 갖는다.
newUser4; // {name: "Mike", age: 30, gender: "Male"}
user; // {name: "Mike", age: 30, gender: "Male"}
Object.assign()
은 속성의 값을 복사하기 때문에, 깊은 복사를 수행하려면 다른 방법을 사용해야 합니다.
Object.assign()
이 새로운 인스턴스를 만들긴 하지만, 내부 프로퍼티 중 객체에 대한 참조 주소가 있다면 객체 자체가 복사되는 건 아니다. 따라서 완전한 deepcopy라고 할 수는 없다.
const user = {
name: "Mike"
};
const newUser = Object.assign({}, user);
const newUser2 = {...user}; // 전개 구문으로도 복제가 가능하다.
const a = Symbol();
const b = Symbol();
a === b; // false
a == b; // false
const id = Symbol("id info");
id.description; // id info
const id = Symbol("id");
const user = {
name: "Mike",
age: 30,
[id]: "myId"
};
Object.keys(user); // ["name", "age"]
for (let key in user) { } // key="name", key="age
Reflect.ownKeys(user); // ["name", "age", Symbol(id)]. Symbol까지 볼 수 있음.
Object.getOwnPropertySymbols(user); // [Symbol(id)]. Symbol만 모아보기
showName까지 순회해버리는 불상사가…
Symbol을 사용하는 이유는 뭘까 | symbol usage
const id1 = Symbol.for("id");
const id2 = Symbol.for("id");
id1 === id2; // true. key만 같다면 동일한 Symbol로 인정한다.
Symbol.keyFor(id1); // id
Symbol.keyFor(id2); // id
전역 심볼 레지스트리에 저장되며, 하나의 key에는 하나의 Symbol만 오도록 유지한다.
let userRate = 30.1234;
// Math.round에는 자릿수 기능이 없다. 무조건 정수로 반올림
Math.round(userRate * 100) / 100 // 30.12
// 자르는게 아니라 반올림이다! 완벽히 대체 가능
userRate.toFixed(2); // 30.12
let x = Number('x'); // NaN
x == NaN // false
x === NaN // false
NaN == NaN // 심지어 이것도 false
isNaN(x) // true. isNaN()만이 NaN을 판별하는 유일한 방법이다.
let n = 10;
n.toString(); // "10"
n.toString(2); // "1010"
let redColor = "f3";
parseInt(redColor, 16); // 243
let margin = "10px";
parseInt(margin); // 10 -> atoi라서 되는데까지만 파싱함.
// 물론 처음부터 not digit이라면 NaN
Number(margin); // NaN
str.slice()
vs str.substring()
vs str.substr()
"a".codePointAt(0); // 97. ord("a")와 동일
String.fromCodePoint(97); // a. chr(97)과 동일
let arr = [10, 9, 8, 7, 6];
arr.indexOf(10); // 0
arr.indexOf(0); // 없으면 -1
arr.includes(10); // true
arr.includes(0); // false
arr.find((item) => {
return item%2 === 1;
}); // 9. 요소 반환, 없으면 undefined
arr.findIndex((item) => {
return item%2 === 1;
}); // 1. index 반환, 없으면 -1
const arr = [2, 1, 3, 10];
arr.sort()
arr; // [1, 10, 2, 3] 와...
arr.sort((a, b) => {
return a-b;
});
arr; // [1, 2, 3, 10] 이제서야 이렇게 됨
// lodash 라이브러리를 이용하여
_.sortBy(arr); // 로 쓰면, python처럼 숫자든 문자든 정렬 가능!
let arr = [1, 2, 3];
const result = arr.map((val) => {
if (val%2 === 0) {
return "홀수";
}
return "짝수";
});
result; // ["홀수", "짝수", "홀수"];
arr = [1, 2, 3];
const result = arr.reduce((prev, cur) => {
return prev + cur;
}, 0); // 초기 prev 값
result; // 6 (1+2+3)
function makeCounter() {
let num = 0;
return function() {
return num++;
}; // 함수를 반환한다!
}
let counter = makeCounter();
// 반환 함수 { return num++; }가 counter에 담겨있다!
// 반환 함수가 안 사라졌기 때문에 makeCounter의 num값도 유지한다.
console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2
// num 은닉에 성공
setTimeout(function() {
console.log(2);
}, 0);
console.log(1);
이렇게 하더라도 1, 2
순서대로 출력된다.