기본
1. 상수 표기법
상수는 const로 선언된 변수이며, 대문자와 _ 로만 나타낸다.
2. null과 undefined의 차이
- null은 값이 할당되지 않았거나 알 수 없는 상태
- undefined은 값이 할당되지 않은 상태
- 값이 할당되지 않았을 때는 명시적으로 null 사용한다.
3. 자료형
- 원시 자료형: 한 가지만 표현 가능한 것 (int, string)
- 객체: 데이터들의 집합
- 심볼: 객체의 고유 식별자
4. 형변환
- 문자형으로 형변환: String
- 숫자형으로 형변환: Number
5. 동등연산자와 일치연산자
- 동등연산자(==): 값만 일치하면 된다. (0 == false ==> true)
- 일치연산자(===): 값과 자료형이 일치해야 한다. (0 === false ==> false)
6. 논리연산자의 사용법
- 논리연산자는 첫 번째 참 값을 찾기 때문에 변수들을 나열한 후 첫 번째 참 값을 찾을 때 사용하면 된다.
ex) const name = firstName || nickName ; 하면 firstName이 참인 경우에는 name == firstName이고 거짓인 경우에는 name==nickName이 된다.
7. ?? - null 병합 연산자
- a ?? b 는 (a !== null) && (b !== undefined) ? a : b와 같다
- ||은 첫 번째 참 값을, ?? 은 첫 번째 정의된 값을 찾을 때 사용하는 것으로 null과 0을 구분할 때 사용한다.
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
8. 함수 선언문과 함수 표현식
- 함수 선언문은 정의되기 전에도 사용 가능하다.
//함수 선언문
let hap = sum(1,2); //실행 가능
function sum(a, b) {
return a+b;
}
- 함수 표현식은 정의되고 난 후에 사용 가능하다.
//함수 표현식
let hap = sum(1,2); //error
let sum = function(a,b) {
return a+b;
};
객체: 기본
1. 객체 생성법
let user = new Object();
let user = {};
user.age = 21;
user.name = "kimtaeju";
2. 객체 프로퍼티 삭제
delete user.age;
3. 객체 프로퍼티 키 조회
- 존재하지 않는 키를 조회할 경우, undefined를 반환한다.
for key in user {
...
}
4. 객체 복사
- 객체는 참조에 의한 복사가 일어난다. 즉, 값을 복사하는 것이 아니라 주소를 복사한다.
let user = {
name:"kimtaeju",
age: 21,
};
let admin = user;
admin.age = 22; //user.age도 22가 된다.
- 값에 의한 복하를 하려면 Object.assign을 사용하면 된다.
let user = {
name:"kimtaeju",
age: 21,
};
let admin = {}
Object.assign(admin, user);
admin.age = 22; //user.age==21
5. 메서드와 this
- 메서드: 객체의 프로퍼티에 할당된 함수
- this: 함수를 실행시킨 객체
let user = {
name: "kimtaeju",
age: 21
}
user.sayHi = function() {
alert(`hello, i am ${this.name}`);
user.sayHi();//hello, i am kimtaeju
- this는 객체에 따라 달라진다.
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;
// 'this'는 '점(.) 앞의' 객체를 참조하기 때문에
// this 값이 달라짐
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
6. 생성자 함수와 new
- 유사한 객체를 여러 개 만들 때 생성자를 이용해 객체 생성
function User(name) {
this.name = name;
}
let user = new User("kimtaeju");
//user = {name: "kimtaeju"}가 생성된다.
- 함수 앞에 new 키워드가 있을 경우, 함수 실행가 동시에 빈 객체를 생성해 this에 대입하고, 함수가 종료되면 this를 반환한다.
- 생성자 함수를 작성할 때 메서드도 포함시킬 수 있다.
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "My name is: " + this.name );
};
}
let john = new User("John");
john.sayHi(); // My name is: John
7.옵셔널 체이닝: ?.
- 앞의 대상 값이 존재하지 않으면 에러 대신 undefined를 반환한다.
let user = {};
alert(user.address.street); //error가 발생.
alert(user?.address?.street); //undefined 발생
- 존재하지 않아도 되는 대상에만 사용할 것.
- ?.는 쓰기에는 사용이 불가능하다.
user?.name = "kimtaeju"; //error가 발생한다.
8. 심볼
- 유일한 식별자를 생성.
let id1 = Symbol("id");
let id2 = Symbol("id");
alert(id1 == id2); // false 반환
1) 숨김 프로퍼티
- 외부 코드에서 접근이 불가능하고 값도 덮어 쓸 수 없는 것.
let user = { // 서드파티 코드에서 가져온 객체
name: "John"
};
let id = Symbol("id");
user[id] = 1;
alert( user[id] ); // 심볼을 키로 사용해 데이터에 접근할 수 있습니다.
- 위의 코드와 같이 작성하면, id 값이 같아 사용자가 충돌할 일을 방지할 수 있다.
- 심볼은 for keys in object를 실행할 때 제외된다.
2) 전역 심볼
- 심볼이 존재하지 않으면 새로 생성, 존재하면 기존의 것을 사용
// 전역 레지스트리에서 심볼을 읽습니다.
let id = Symbol.for("id"); // 심볼이 존재하지 않으면 새로운 심볼을 만듭니다.
// 동일한 이름을 이용해 심볼을 다시 읽습니다(좀 더 멀리 떨어진 코드에서도 가능합니다).
let idAgain = Symbol.for("id");
// 두 심볼은 같습니다.
alert( id === idAgain ); // true
자료형
1. 배열
- 큐처럼 사용: push, shift
- 스택처럼 사용: push, pop
- push, pop 이 shift, unshift보다 속도가 빠르다. (배열을 이동시킬 필요가 없으므로)
1) 반복문
let arr = ["사과", "오렌지", "배"];
// 1.index 이용
for (let i = 0; i < arr.length; i++) {
alert( arr[i] );
}
// 2. index 이용x
for (let fruit of fruits) {
alert( fruit );
}
2) method
- splice(index, count): index번 째부터 count개 만큼 삭제
- slice(start, end): start 부터 end-1까지 배열 반환
let a = [1,2,3]
a.slice(0,2) //[1,2]
- concat(arr1, arr2) : arr1과 arr2를 합쳐서 반환
let a = [1,2,3];
a.concat([4,5]); //a = [1,2,3,4,5];
- forEach(function): 배열의 각 요소에 대해 function 실행
let a = [1,2,3]
a.forEach( item => {
console.log(item)}); //1,2,3 출력
- 배열 탐색하기
1) indexOf(item, from): from부터 탐색하기 시작해 item이 있는 index를 반환. 발견하지 못하면 -1 반환
2) arr.lastIndexOf(item, from): 뒤에서 부터 탐색
3) arr.includes(item, from): from부터 탐색하기 시작해서 item이 있으면 true, 없으면 false 반환
4) find(condition): 특정 조건이 만족하는 요소 하나만 반환
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
let user = users.find(item => item.id == 1);
alert(user.name); // John
5) filter(condition): 특정 조건이 만족하는 모든 요소 반환
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
// 앞쪽 사용자 두 명을 반환합니다.
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
6) map(function): 모든 요소에 대해 function 실행 후 배열 반환
7) reduce: 배열에 대해 하나의 값을 도출할 때 사용
let a = [1,2,3];
let sum = a.reduce((total, item) => total += item, 0);
alert(sum); //6
8) Array.isArray(a): a가 배열인지 아닌지 판단
alert(Array.isArray({})); // false
alert(Array.isArray([])); // true
9) thisArg: func의 this, 가장 마지막 매개변수 위치에 있다.
arr.find(func, thisArg);
arr.filter(func, thisArg);
arr.map(func, thisArg);
// ...
// thisArg는 선택적으로 사용할 수 있는 마지막 인수입니다.
사용법
let army = {
minAge: 18,
maxAge: 27,
canJoin(user) {
return user.age >= this.minAge && user.age < this.maxAge;
}
};
let users = [
{age: 16},
{age: 20},
{age: 23},
{age: 30}
];
// army.canJoin 호출 시 참을 반환해주는 user를 찾음
//만약 army가 없다면 this를 찾지 못해 error 발생
let soldiers = users.filter(army.canJoin, army);
alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23
2. map
- key value 쌍으로 구성된 것으로 key에는 숫자도 올 수 있다.
map의 메소드는 다음과 같다.
new Map() – 맵을 만듭니다.
map.set(key, value) – key를 이용해 value를 저장합니다.
map.get(key) – key에 해당하는 값을 반환합니다. key가 존재하지 않으면 undefined를 반환합니다.
map.has(key) – key가 존재하면 true, 존재하지 않으면 false를 반환합니다.
map.delete(key) – key에 해당하는 값을 삭제합니다.
map.clear() – 맵 안의 모든 요소를 제거합니다.
map.size – 요소의 개수를 반환합니다.
- map의 요소에는 다음과 같이 반복작업을 할 수 있다.
map.keys(): key들을 반환
map.values(): values를 반환
map.entries(): key value 쌍 반환
- Objects.entries: 객체를 map으로 변경
3. keys, values, entries
map, set, array에서 사용가능하고 기능은 다음과 같다.
- Object.keys(obj) – 객체의 키만 담은 배열을 반환합니다.
- Object.values(obj) – 객체의 값만 담은 배열을 반환합니다.
- Object.entries(obj) – [키, 값] 쌍을 담은 배열을 반환합니다.
let user = {
name: "John",
age: 30
};
//Object.keys(user) => name, age
//Object.values(user) => John, 30
//Object.entries(user) => name: John, age: 30
4. 구조 분해 할당
- 배열을 분해할 때는 [], 객체를 분해할 때는 {} 사용한다.
let arr = ["Bora", "Lee"]
let [firstName, surname] = arr;
alert(firstName); // Bora
alert(surname); // Lee
let options = {
title: "Menu",
width: 100,
height: 200
};
let {title, width, height} = options;
alert(title); // Menu
alert(width); // 100
alert(height); // 200
5. JSON
- JSON.stringify : 객체를 JSON 형태로 변경
- JSON.parse: JSON을 객체로 변경
- 서버와 클라이언트 간의 데이터 통신을 할 때 사용.
함수
1. 나머지 매개변수와 전개 문법
function sumAll(...args) { // args는 배열의 이름입니다.
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6
- arguments: 함수의 매개변수를 저장해놓은 배열.
- spread: 배열을 매개변수로 변경하는 것으로, ...를 사용한다.
let arr = [3, 5, 1];
alert( Math.max(arr) ); // NaN
alert( Math.max(...arr)); //5
2. 변수의 유효 범위와 클로저
- 변수의 유효 범위는 {} 기준이다.
- 중첩 함수: 함수 안에 함수가 존재하는 것
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
왜 0이 3개가 안 나오고, 1씩 증가해 나오는가?
좀 더 깊게 공부해보자
- 렉시컬 환경
크게 2가지로 구성되어있다.
1) 환경 레코드 - 모든 지역 변수를 프로퍼티로 저장
2) 외부 렉시컬 환경 - 외부 코드와 연관됨
’변수’는 특수 내부 객체인 환경 레코드의 프로퍼티일 뿐입니다. '변수를 가져오거나 변경’하는 것은 '환경 레코드의 프로퍼티를 가져오거나 변경’함을 의미합니다.
1) 전역 변수를 저장했을 경우 렉시컬에서 일어나는 일
// 1단계
let a; // 2단계
a = "hello"; // 3단계
1단계: 스크립트가 시작되면 스크립트 내에서 선언한 변수 전체가 렉시컬 환경에 올라갑니다. a는 uninitialized 상태이다. 또한, a를 사용할 수 없다. (아직 초기화 되기 전)
2단계: 아직 a는 undefined이지만 이 시점부터 사용 가능
3단계: a에 hello를 할당한다.
즉, 자바스크립트에서 변수를 지정한다는 것은 환경 레코드의 프로퍼티 값을 변경한다는 것이다.
2) 함수 선언문을 저장했을 경우
함수는 변수와 마찬가지로 값임.
다만 함수 선언문으로 선언한 함수는 일반 변수와는 달리 바로 초기화된다는 점에서 차이가 있습니다. 함수 선언문으로 선언한 함수는 렉시컬 환경이 만들어지는 즉시 사용할 수 있습니다.
3) 함수를 실행할 경우
let phase = "hello";
function say(name){
alert(`${phase} ${name}`);
}
say("kimtaeju");
함수를 호출해 실행할 경우 새로운 렉시컬이 만들어짐.
이 렉시컬에는 지역 변수와 전역 변수를 저장하기 위해 내부 렉시컬 환경과 외부 렉시컬 환경이 만들어짐.
내부 렉시컬 환경에는 name이, 외부 렉시컬 환경에는 phase, say를 가진다.
코드에서 변수에 접근할 땐, 먼저 내부 렉시컬 환경을 검색 범위로 잡습니다. 내부 렉시컬 환경에서 원하는 변수를 찾지 못하면 검색 범위를 내부 렉시컬 환경이 참조하는 외부 렉시컬 환경으로 확장합니다. 이 과정은 검색 범위가 전역 렉시컬 환경으로 확장될 때까지 반복됩니다.
지역 변수부터 찾고 없으면 전역 변수를 찾는다.
4) 반환 함수
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
makeCounter()을 실행하면 새로운 렉시컬 환경이 만들어짐.
이 때, counter는 makeCounter의 중첩 함수이다. 모든 함수는 함수가 생성된 렉시컬의 환경을 [[Environment]]에 저장한다. 따라서 counter.[[Environment]]에 {count: 0}이라는 렉시컬의 외부 참조가 저장된다.
counter()을 호출하면 먼저 자체 렉시컬 환경에서 변수 count를 찾는다. 하지만 지역 변수에 존재하지 않으므로 외부 렉시컬 환경 (makeCounter)에서 찾는다. 변숫값 갱신은 그 변수가 있는 환경에서 일어나므로, makeCounter에서 변수 갱신이 일어나고 count 값이 1씩 증가하게 된다.
4. 전역 객체
- 전역 객체를 사용하면 어디서나 사용할 수 있는 변수를 만들 수 있다. (window)
window.name = "kimtaeju";//어디서든 name을 사용할 수 있다.
5. 객체로서의 함수와 기명 함수 표현식
- name 프로퍼티: 함수의 이름을 반환
function sayHi() {
alert("Hi");
}
alert(sayHi.name); // sayHi
let sayHi = function() {
alert("Hi");
};
alert(sayHi.name); // sayHi
- length 프로퍼티: 함수의 매개변수 개수를 반환
function f1(a) {}
function f2(a, b) {}
function many(a, b, ...more) {}
alert(f1.length); // 1
alert(f2.length); // 2
alert(many.length); // 2
- 커스텀 프로퍼티: 함수 자체에 프로퍼티 추가
function sayHi() {
alert("Hi");
// 함수를 몇 번 호출했는지 세봅시다.
sayHi.counter++;
}
sayHi.counter = 0; // 초깃값
sayHi(); // Hi
sayHi(); // Hi
alert( `호출 횟수: ${sayHi.counter}회` ); // 호출 횟수: 2회
클로저로 정의할 경우에는 외부에서 접근이 불가능하지만, 커스텀 프로퍼티로 저장할 경우에는 sayHi.counter처럼 외부에서도 접근이 가능하다.
- 기명 함수 표현식: 이름이 있는 함수를 표현하는 식
let sayHi = function func(who) { //func이 기명 함수 표현식이다
if (who) {
alert(`Hello, ${who}`);
} else {
func("Guest");
}
};
- 함수 내부에서 호출이 가능 (func("Guest"))
- 외부에서는 호출이 불가능하다.
6. new Function 문법
let sum = new Function('a', 'b', 'return a + b');
alert( sum(1, 2) ); // 3
- 문자열을 코드로 바꿔 실행할 수 있다.
function getFunc() {
let value = "test";
let func = new Function('alert(value)');
return func;
}
getFunc()(); // ReferenceError: value is not defined
- new Function은 렉시컬을 참조할 때 전역 렉시컬을 참조하기 때문에 error 발생
//일반적인 방법
function getFunc() {
let value = "test";
let func = function() { alert(value); };
return func;
}
getFunc()(); // getFunc의 렉시컬 환경에 있는 값 "test"가 출력됩니다.
7. 함수 바인딩
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(user.sayHi, 1000); // Hello, undefined!
user.sayHi 라는 독립적인 함수를 전달했기 때문에 this가 없어 에러 발생
해결 방법
1) wrapper
setTimeout(function() {
user.sayHi(); // Hello, John!
}, 1000);
실행되는 이유는 외부 렉시컬 환경에서 user를 가져왔기 때문.
2) bind
func.bind(context)는 함수처럼 호출 가능한 '특수 객체(exotic object)'를 반환합니다. 이 객체를 호출하면 this가 context로 고정된 함수 func가 반환됩니다.
let user = {
firstName: "John"
};
function func(phrase) {
alert(phrase + ', ' + this.firstName);
}
// this를 user로 바인딩합니다.
let funcUser = func.bind(user);
funcUser("Hello"); // Hello, John (인수 "Hello"가 넘겨지고 this는 user로 고정됩니다.)
여기서는 this가 user가 되는 것입니다.
8. 화살표 함수
- this가 없다. 화살표 함수에서 this로 접근하면 외부 것을 가져온다.
let group = {
title: "1모둠",
students: ["보라", "호진", "지민"],
showList() {
this.students.forEach(
student => alert(this.title + ': ' + student) //this == group
);
}
};
group.showList();
let group = {
title: "1모둠",
students: ["보라", "호진", "지민"],
showList() {
this.students.forEach(function(student) {
// TypeError: Cannot read property 'title' of undefined, this == showList() 라서 에러 발생
alert(this.title + ': ' + student)
});
}
};
group.showList();
'Javascript' 카테고리의 다른 글
visibilitychange 이벤트 사용하기 (0) | 2021.03.24 |
---|---|
javascript reduce 배열 메서드 (0) | 2021.03.24 |
javascript 101 (0) | 2021.03.24 |
javascript 변수와 상수 (var vs const) (0) | 2021.03.24 |
Data Structure(자료구조) 란? (0) | 2021.03.23 |
개의 댓글