https://youtube.com/playlist?list=PLZKTXPmaJk8JZ2NAC538UzhY_UNqMdZB4
var
는 한번 선언된 변수를 다시 선언 가능
동일한 상황에서 let
은 에러나옴
var
는 선언 전에 사용 가능. 호이스팅 덕임. 선언은 호이스팅되나 할당은 호이스팅 안되기 때문에 undefined
찍힘
var name;
console.log(name); // undefined
name = 'JiMoon';
호이스팅
은 스코프 내부 어디서든 변수 선언은 최상위에 선언된 것 처럼 행동한다는 개념
let
과 const
도 호이스팅
이 되지만 TDZ(Temporal Dead Zone
이라는 개념을 도입해 다른 언어들과 같은 논리적 순서에 맞게 동작하도록 설정했기 때문임. 이는 불확실성을 떨어뜨려줌.
위 사진을 보면. 4번줄이 생기면서 3번줄은 TDZ
에 들어갔기 때문에 오류 발생.
변수는 크게 3단계 생성과정을 거침
undefined
를 할당 해주는 단계var
는 아래와 같이 2단계로 작동 함
let
은 3단계 생성과정 거침
호이스팅
되며 이루어짐const
는 1단계 생성과정 거침. 그래서 나중에 할당만으로 값을 바꾸는게 불가능
스코프
var
는 함수 스코프(function-scoped)
함수 스코프는 함수 내에서 선언된 변수만 지역변수.
위 사진처럼 if문
안에서 var
로 선언된 변수는 같은 함수 내라면 if문
밖에서도 사용가능
위 사진처럼 var
도 함수 스코프 밖에선 사용 불가
let
, const
는 블록 스코프(block-scoped)
블록 스코프는 모든 코드블록에서 선언된 변수는 코드블록 내에서만 유효하고, 외부에선 접근할 수 없다는 의미. 즉 코드블록 내부에서 선언한 변수는 지역변수임. 여기서 말하는 코드블록은 함수
, if 문
, for 문
, while 문
, try/catch 문
등을 의미
위 사진처럼 코드블럭 밖에서 사용하자 에러
var
는 이제 사용하지 않고, 예측 가능한 결과를 내고 버그를 줄일 수 있는 let
과 const
사용 권장
비슷한 객체를 여러개 만들어야 하는 경우에 사용
생성자 함수의 첫글자는 대문자로 이름짓고, new 연산자를 사용해서 함수를 호출
어떻게 동작하나 순서를 살펴보면
this
에 할당함this
에 프로퍼티들을 추가함this
를 반환함function User(name, age) {
// this = {}
this.name = name;
this.age = age;
this.sayName = function () {
console.log(`내 이름은 ${name}이야`)
// return this;
}
실제로 // 문장들은 저 코드에 없지만 new를 붙여 실행하는 순간 저 방식으로 알고리즘이 돌아감.아래 첫번째 사진에서 5번줄 age
대신, 두번째 사진[a]
처럼 대괄호로 묶어주면 a라는 문자열이 아니라 변수 a에 할당된 값이 들어감. 이를 computed property(계산된 프로퍼티)
라고 함
식 자체를 넣는것도 가능
위의 정보들을 응용하여 객체를 만드는 함수를 만들면
key
의 위치에 [key]
이렇게 써줘야 스트링 매개변수를 받아 우리가 알고있는 key
의 문법 Object.abc
또는 Object['abc']
의 형태가 되어서, key 값으로 인식할 수 있다Object Methods
const user = {
name : 'JiMoon'
age : 29,
}
const cloneUser = user; // 이러면 객체가 복사되는 것이 아니라 주소만 복사됨
// 하나의 객체를 두 변수가 접근하게됨
또 다른 객체로써 동일하게 복제하려면 Object.assign() 메소드를 써야함const newUser = Object.assign({}, user);
// 위와같이 하면 첫번째 매개변수는 초기값 빈객체를 만들어주는것이며
// 두번째 매개변에서 받은 객체의 프로퍼티들을 빈객체에 넣어주는 메소드임
{} + { name : 'JiMoon', age : 29 }
= { name : 'JiMoon', age : 29 }
// 위와 같이 서로 다른 주소값에 담긴 동일한 정보를 담고있는 객체로 복제됨
Object.assign({ gender:'male' }, user);
// 위와 같이 초기 객체에 프로퍼티를 담아주게되면 그 이후에 들어감
// 키가 같다면 덮어씌움
이런 assign의 알고리즘을 응용해서 객체를 합치는데도 이용가능const user = {
name : 'JiMoon',
}
const info1 = {
age : 29,
}
const info2 = {
gender = 'male',
}
Object.assign(user, info1, info2);
const a = Symbol(); // new를 붙이지 않음
const b = Symbol();
console.log(a) // Symbol()
console.log(b) // Symbol()
console.log(a === b) // false
console.log(a == b) // false
for in
도 건너뜀for ... in ...
에서 이미 객체의 키값을 받기때문에 key
자체로 받으면 되고, value
값은 key
자체가 스트링 값이므로 객체의 문법중 하나인 Object['']
을 사용해서 value
값에 접근하는것.하나의 심볼만 보장받을 수 있음. 없으면 만들고, 있으면 가져오기 때문
Symbol
함수는 매번 다른 Symbol
값을 생성하지만, Symbol.for
메소드는 하나를 생성한 뒤 키를 통해 같은 Symbol
을 공유
const id1 = Symbol.for('id');
const id2 = Symbol.for('id');
id1 === id2; /// true
// 이름을 얻고싶다면 Symbol.keyFor 이용
Symbol.keyFor(id1) // 'id'
// 전역심볼이 아닌 심볼은 description 사용
const id = Symbol('id 입니다');
id.description; // 'id 입니다'
숨겨진 Symbol key 보는 법
toString() : 기본적으로 스트링으로 전환할때 사용하는 메소드인데 괄호안에 넣어준 숫자의 진법으로 변경해주는 기능도 있다
let num = 10;
num.toString(); // '10'
num.toString(2); // '1010'
let num2 = 255;
num2.toString(16); // 'ff'
Math : 자바스크립트에는 수학과 관련된 프로퍼티와 메소드들을 가지고있는 Math
라는 내장 객체가 있다
let userRate = 30.1234;
// 요구사항 : 소수점 둘째자리 까지 표현 (셋째 자리에서 반올림)
Math.round(userRate * 100)/100 // 30.12
👉 해당 메소드들은 항상 소수점 첫째자리를 기준으로 계산하므로 내가 10의 n제곱을 곱하거나 나눠서 나리를 맞춰주면 됨toFixed()
를 사용하면 됨. ()안에 내가 나타내고자하는 소수점 자리수를 넣어주면 알아서 반올림 해서 나타내줌. 주의할점은 결과는 문자열로 반환해 줌. 그래서 반환 후 Number()
를 이용해 숫자로 변환 후 작업하는 경우가 많음.NaN
인지 아닌지 판단해줌. 오직 inNaN() 만이 판단 가능. NaN
은 자기 자신마저도 같지 않다고 나오기 때문let x = Number('x'); // NaN
x == NaN // false
x === NaN // false
NaN == NaN // false
isNaN(x) // true
isNaN(3) // false
Number()
와 다른점은 문자가 혼용되어 있어도 동작함.parseInt
도 읽을 수 있는 부분 까지만 읽고 문자를 만나면 숫자를 반환하므로, 시작이 문자면 바로 반환됨.let margin = '10px';
parseInt(margin); // 10
Number(margin); // NaN
let redColor = 'f3';
parseInt(redColor); // NaN
그러나 parseInt
는 두번째 인수를 받아 전달받는 숫자의 진수를 지정할 수 있다let redColor = 'f3';
parseInt(redColor); // NaN
let rdeColor = 'f3';
parseInt(redColor, 16); // 243
parseInt('11', 2) // 3
parseInt
와 동일하게 동작하나 parseInt
는 정수만 반환하지만 parseFloat
는 부동 소수점을 반환함let padding = '18.5%';
parseInt(padding); // 18
parseFloat(padding); // 18.5
Math.floor(Math.random()*100)+1
Math.max(1,4,-1,5,10,9,5.54); // 10
Math.min(1,4,-1,5,10,9,5.51); // -1
''
, ""
: 작은 따옴표과 큰 따옴표는 큰 차이가 없다 상황에 맞게 쓰면됨
""
로 된 내용들이 있으므로 ''
가 편하다''
가 들어가므로 ""
가 편하다`` : 백틱은 $
와 {}
를 이용해 변수를 표현하거나 표현식을 쓸 수 있다
let desc = `오늘은 맑고 화창한
날씨가 계속 되겠습니다.
내일은 비소식이 있습니다.`;
let desc = '오늘은 맑고 화창한\n날씨가 계속 되겠습니다.'; // 따옴표로 줄바꿈을 표현하려면 /를 써야함
let desc = '오늘은 맑고 화창한 // error! 따옴표로 작성시에는 꼭 한줄로 써야지 줄바꿈시 에러남
날씨가 계속 되겠습니다.
내일은 비소식이 있습니다.'
배열처럼 문자열도 length
로 문자열 길이를 구할 수 있다
배열과 동일하게 문자열도 대괄호와 숫자로 특정 위치에 접근 가능. 하지만 배열과 달리 한글자만 바꾸는건 허용 x
toUpperCase()
/ toLowerCase()
: 영어의 경우 대문자, 소문자로 변환
indexOf(text)
: 문자를 인수로 받아 몇번 째에 위치하는지 알려줌. 만약 찾는 문자가 없으면 -1
을 반환
if
문 사용시 조건에 주의하며 써야함if(desc.indexOf('Hi')) {
console.log('Hi가 포함된 문장입니다.'); // Hi가 첫번째에 있어서 0이 나와 false가 됨
}
if(desc.indexOf('Hi') > -1) {
console.log('Hi가 포함된 문장입니다.'); // 이래야 true가 되서 if문이 발동됨
}
str.slice(n, m)
: 시작점 n
부터 m
이 없으면 문자열 끝까지, 양수면 그 숫자까지(포함x), 음수면 끝에서부터
str.substring(n, m)
: n
과 m
사이 문자열 반환. n
과 m
을 바꿔도 동작. 음수는 0으로 인식
str.substr(n, m)
: n
부터 시작해서 m
개를 가져옴
str.trim()
: 앞 뒤 공백 제거
str.repeat(n)
: 문자열을 n번 반복
문자열도 비교가 가능함
1
보다 3
이 크듯이, 'a'
보다 'c'
가 큼codePointAt(0);
을 이용해 얻을 수 있다. 예를들어 소문자 'a'
의 번호가 궁금하다면 'a'.codePointAt(0); // 97
이렇게 나온다.String.fromCodePoint(97); // 'a'
실전 예제
숫자를 제외한 문자로만 구성된 새로운 배열 얻기
금칙어가 들어가있다면 알림
indexOf
활용
위 사진 처럼 하면 원하는 결과가 제대로 안나옴
조건문에 조건을 이렇게 해줘야 정상적으로 출력
includes
활용
arr.splice(n, m)
: n
에서 시작해서 m
개 지움.
arr.splice(n, 2, x, y)
이런식으로 써주면 됨.m
을 0
으로 하면 됨arr.splice()
는 삭제된 요소를 반환함arr.slice(n, m)
: n
부터 m
까지 반환. m
은 포함 X
arr.concat(arr2, arr3 ..)
:합쳐서 새배열 반환
arr.forEach(fn)
: 배열 반복. 함수를 인수로 받음
let users = ['Mike', 'Tom', 'Jane'];
users.forEach((item, index, arr) => {});
// item 은 Mike, Tom, Jane
// index 는 0, 1, 2
// arr 는 users
arr.indexOf
/ arr.lastIndexOf
: 발견하면 해당요소의 인덱스 반환. 없으면 -1
을 반환
arr.lastIndexOf
사용arr.includes()
: 포함 하는지 확인. 불리언으로 반환
arr.find(fn)
/ arr.findIndex(fn)
: indexOf
처럼 찾는다는 의미는 동일하지만, 보다 복잡한 연산이 가능하도록 함수를 전달 가능
arr.find(fn)
는 첫번째 true
값만 반환하고 끝. 만약 없으면 undefined
를 반환arr.findIndex(fn)
은 해당 index
를 반환. 없으면 -1
을 반환arr.filter(fn)
: 조건을 만족하는 모든 요소를 찾고싶을 때
arr.reverse()
: 역순으로 재정렬
arr.map(fn)
: 함수를 받아 특정 기능을 시행하고, 새로운 배열을 반환
arr.join()
: 배열을 합쳐서 문장을 만들 때 사용
arr.split()
: 문자열을 나눠서 배열로 만들어줌
arr.isArray()
: 배열인지 아닌지 확인
arr.sort(fn)
: 배열 재정렬. 배열 자체가 변경되니 주의.
arr.reduce
for
, for of
, forEach
를 사용함reduce
임reduce
는 함수를 갖는데 현재까지 누적된 계산값과 현재값을 가짐. 초기값은 옵션이고 안쓰면 첫번째 요소부터 시작.arr.reduceRight()
는 reduce
와 기능은 동일하나 배열 오른쪽부터 실행하는 차이점만 있다지금까지 배운 메소드를 상황에 맞게 잘 사용하는 것도 실력임
연습을 많이 해보자!
let [x, y] = [1, 2];
console.log(x); // 1
console.log(y); // 2
split
을 응용 할 수 있음undefined
들어감let [a, b, c] = [1, 2]; // c = undefined
let [a=3, b=4, c=5] = [1, 2];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 5
let [user1, , user2] = ['Mike', 'Tom', 'Jane', 'Tony'];
console.log(user1); // 'Mike'
console.log(user2); // 'Jane'
undefined
undefined
가 찍힐 뿐임length
와 index
가 있어 배열이라고 착각하기 쉽지만 Array 형태의 객체임length
와 index
등의 속성은 갖고있지만, 배열의 내장 메소드는 가지고 있지 않음!(forEach
나 map
등 사용 불가)...
를 찍고 뒤에 배열 이름을 나타내줌(위에선 names
)names
배열 안에 전달된 인수들이 들어감undefined
가 아니라 빈배열이 나타남arguments
랑 다르게 배열이므로 메소드도 사용 가능let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let result = [...arr1, ...arr2];
console.log(result); // [1, 2, 3, 4, 5, 6]
let result2 = [0, ...arr1, ...arr2 7, 8, 9];
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.push()
), 중간에 빼고( arr.splice()
), 병합( arr.concat()
) 하는 작업들은 굉장히 번거로움. 그러나 전개 구문을 사용하면 쉬워짐let user = {name: 'Mike'};
let mike = {...user, age:30};
console.log(mike) // {name: 'Mike', age: 30}
assign
을 쓰지 않아도 복사가 잘됨let arr = [1, 2, 3];
let arr2 = [...arr]; // [1, 2, 3]
let user = {name;'Mike', age:30};
let user2 = {...user};
user2.name = 'Tom';
console.log(user.name); // 'Mike'
console.log(user2.name); // 'Tom'
forEach
사용[6, 5, 4, 1, 2, 3]
이 나옴assign
, forEach
사용num
의 은닉화에 성공한 것. 갑자기 99로 바꾼다거나 100씩 증가하거나 하는건 불가능함function fn() {
console.log(3);
}
setTimeout(fn, 3000);
// 아래와 동일
setTimeout(function () {
console.log(3)
}, 3000);
setTimeout
은 두개의 매개변수를 가짐. 첫번째는 일정시간이 지난뒤 실행되는 함수이고, 두번째는 시간임. 시간은 ms 단위이다. 인수가 필요하다면 시간 뒤에 적어주면 된다.function showName(name) {
console.log(name);
}
setTimeout(showName, 3000, 'Mike');
clearTimeout(tId)
는 예정된 작업을 없앰. setTimeout
은 타임id를 반환하는데 이것을 이용해 취소할 수 있다.const tId = function showName(name) {
console.log(name);
}
setTimeout(showName, 3000, 'Mike');
clearTimeout(tId);
setTimeout
와 사용법 동일clearInterval(tId);
실행setTimeout(function(){
console.log(2)
}, 0);
console.log(1);
let num = 0;
function showTime() {
console.log(`안녕하세요. 접속하신지 ${num++}초가 지났습니다.`);
}
setInterval(showTime, 1000);
만약 계속 보여주기 싫고 5초까지만 보여주고싶다면?
let num = 0;
function showTime() {
console.log(`안녕하세요. 접속하신지 ${num++}초가 지났습니다.`);
if (num > 5) {
clearInterval(tId);
}
}
const tId = setInterval(showTime, 1000);
apply
는 함수 매개변수를 처리하는 방법을 제외하면 call
과 완전히 같음. call
은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply
는 매개변수를 배열로 받음.apply
는 배열 요소를 함수 매개변수로 사용할 때 유용apply
는 두번째 매개변수로 배열을 전달하면 그 요소들을 차례대로 인수로 사용함call
과 apply
가 헷갈린다면 apply
는 array
로 받는다고 기억Math
안에는 숫자만 넣어야하는데 배열을 넣게 되면 NaN
이 나옴 제일 빠른 방법은 전개구문을 사용하는 것이고, call
도 사용 가능Math
는 this
가 필요하지 않아 아무 값이나 넣은것call
을 쓴다면 차례대로 매개변수가 들어가야하니 스프레드 연산자를 쓰면 됨예제 1
실전 사용 예제
hasOwnProperty
라는 메소드가 있음. 그런데 이 hasOwnProperty
는 만든적이 없는데 도대체 어디있는 걸까?__proto__
라고 표현되어있기도 함. 일단 객체가 프로퍼티를 읽는데 없다면 이곳에서 찾음hasOwnProperty
라는 프로퍼티가 있다면 어떻게 될까?hasOwnProperty
를 사용하면 됨hasOwnProperty
는 객체가 직접 가지고있는 프로퍼티만 트루를 반환해줌__proto__
를 일일히 작업해줄 필요가 없어짐instance
라고 불려짐. 자바스크립트에서는 이를 편리하게 확인할 수 있는 instanceof
연산자가 있다instanceof
를 이용해서 객체와 생성자를 비교할 수 있고, 이는 해당 객체가 그 생성자로부터 생성된것 인지를 판단해서 true
혹은 false
를 반환함instance
객체는 constructor
라는 프로퍼티가 존재함. constructor
는 생성자를 가르킴
위 12~20번째 줄을 더욱 깔끔하게 해보면
그런데 이렇게하면 constructor
이 사라짐
이러한 이유로 22~31 처럼 프로토타입을 덮어 씌우지 말고, 원래 12~20번 줄처럼 하나씩 프로토타입을 추가하는게 좋은 것
아니면
이런식으로 constructor
를 수동으로 명시해주면 좋다
위와 같이 자바스크립트는 언제나 정확한 constructor를 제시해 주지 않으므로 언제든지 수정될 수 있다는 점을 염두 해 두자
위와같이 자동차의 색상을 맘대로 변경할 수 있게되면 문제가 생길 수 있다. 방지하려면 클로저를 이용하면 됨
이렇게 하면 초기에 셋팅했던 칼라값을 얻을수만 있고 바꿀 수는 없다
getColor 함수는 생성될 당시의 칼라값을 기억하는 것
showName
처럼 class
내에 정의한 메소드는 User2
의 프로토타입에 저장됨super
라는 키워드를 사용하면 된다super.메소드명
으로 부모클래스의 메소드를 사용 가능. 이런 방식을 오버라이딩
이라고 함
constructor 에서 this 를 사용하기전에 super constructor 즉, 부모 생성자를 먼저 호출해야 한다고 나옴
위에서 공부한 것처럼 클래스의 constructor 은 빈 객체를 만들어 주고, this 로 그 객체를 가르키게 됨
반면 extends 를 이용해서 만든 자식 클래스는 빈 객체를 만들어 주고 this 에 할당해 주는 작업을 건너 뜀. 그래서 항상 super() 키워드로 부모 클래스의 constructor 을 실행시켜줘야함.
그러나 navigation 은 잘 들어갔는데, color 값이 제대로 안들어감.
이를 위해선 자식클래스의 컨스트럭터에 동일한 인수를 받는 작업을 해줘야함
15번줄에서 color 를 받고 16번줄에서 부모에게 넘겨줌
const pr = new Promise((resolve, reject) => {
// code
});
callback
함수라 함판매자의 코드 : 주문을 받으면 3초동안 뭔가를 한후 성공인지 실패인지 알려줌
소비자의 코드
then
을 이용해서 리젝트와 리졸브를 처리할 수 있다
then
이외에 사용할 수 있는것이 catch
와 finally
이다
catch
는 에러가 발생한 경우. 즉 리젝트인 경우에만 실행finally
는 이행이든 거부든 처리가 완료되면 항상 실행
위처럼 뎁스가 깊어지며 계속 콜백을 호출하는 것을 콜백헬, 콜백지옥이라함
콜백함수를 사용하지 않고 프로미스로도 가능
위와같이 프로미스가 계속 연결되는것을 프로미스 체이닝(Promises chaining)
2번을 실패로 돌리니 3번은 실행조차 안됨
시간을 측정해보니 6초정도 걸림. 만약 세 사람이 각 상점으로 가서 동시에 주문하면 제일 오래걸리는 3초면 모든 제품을 받을 수 있을 것임. 이때 쓰이는게 Promise.all
위 처럼 Promise.all
은 한꺼번에 실행하고 모두 이행되면 값을 사용할 수 있다. 시간도 절약 가능
1번을 리젝트로 바꿔주니 어떠한 데이터도 얻지 못하고 에러가 남. 이런건 하나의 정보라도 누락되면 페이지를 보여주면 안되는 경우에 활용 가능. 다 보여주거나 아예 안보여주거나 할때