가장 쉬운 배열 내장함수
forEach함수의 파라미터로는, 각 원소에 대하여 처리하고 싶은 코드를 함수로 넣어줌
이렇게 함수형태의 파라미터를 전달하는 것을콜백함수라고 함
const superheroes = ['아이언맨', '캡틴 아메리카', '토르', '닥터 스트레인지']
superheroes.forEach(hero => {
console.log(hero); // 아이언맨 캡틴 아메리카 토르 닥터 스트레인지
})
map은 배열 안의 각 원소를 변환할 때 사용 되며
이 과정에서 새로운 배열이 만들어짐
map함수의 파라미터로는 변화를 주는 함수를 전달해줌(변화함수)
파라미터로 변화함수를 주어 해당 함수조건에 맞는 새로운 배열을 생성해줌
const squared = array.map(n => n * n);
console.log(squared);
배열 안의 모든 숫자를 제곱해서 새로운 배열을 만들어 보자
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const squared = [];
for (let i = 0; i < array.length; i++) {
squared.push(array[i] * array[i]);
}
console.log(squared);
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const squared = [];
array.forEach(n => {
squared.push(n * n);
});
console.log(squared);
const array = [1, 2, 3, 4, 5, 6, 7, 8];
const square = n => n * n;
const squared = array.map(square);
console.log(squared);
indexOf는 원하는 항목이 몇번째 원소인지 찾아주는 함수
파라미터로 원하는 값을 넣어줌
const superheroes = ['아이언맨', '캡틴 아메리카', '토르', '닥터 스트레인지'];
const index = superheroes.indexOf('토르');
console.log(index); // 2
만약 배열 안에 있는 값이 객체이거나 배열이라면
indexOf로 찾을 수 없고
findIndex함수로 찾아야 함
만약 객체 내의 값을 찾으려면 해당함수에 검사하고자 하는 조건을 반환하는 함수를 넣어서 찾아야함
const todos = [
{
id: 1,
text: '자바스크립트 입문',
done: true
},
{
id: 2,
text: '함수 배우기',
done: true
},
{
id: 3,
text: '객체와 배열 배우기',
done: true
},
{
id: 4,
text: '배열 내장함수 배우기',
done: false
}
];
const index = todos.findIndex(todo => todo.id === 3);
console.log(index); // 2
find함수는findIndex와 비슷하지만 인덱스값이 아닌 찾은 값 자체를 반환함
const todos = [
{
id: 1,
text: '자바스크립트 입문',
done: true
},
{
id: 2,
text: '함수 배우기',
done: true
},
{
id: 3,
text: '객체와 배열 배우기',
done: true
},
{
id: 4,
text: '배열 내장함수 배우기',
done: false
}
];
const todo = todos.find(todo => todo.id === 3);
console.log(todo); // {id: 3, text: '객체와 배열 배우기', done: true}
filter함수는 배열에서 특정 조건을 만족하는 값들만 따로 추출하여 새로운 배열을 만듬
filter함수의 파라미터로는 조건을 검사하는 함수를 넣어주며
이 함수의 파라미터로 각 원소의 값을 받아오게 됨
const taskNotDone = todos.filter(todo => !todo.done);
예를 들어 이전에 만든 todos 배열에서 done값이 false인 항목들만 따로 추출해서
새로운 배열을 만들 수 있음
const todos = [
{
id: 1,
text: '자바스크립트 입문',
done: true
},
{
id: 2,
text: '함수 배우기',
done: true
},
{
id: 3,
text: '객체와 배열 배우기',
done: true
},
{
id: 4,
text: '배열 내장함수 배우기',
done: false
}
];
const tasksNotDone = todos.filter(todo => todo.done === false);
console.log(tasksNotDone); // [{ id:4, text: '배열 내장함수 배우기', done: false}]
splice는 배열에서 특정 항목을 제거할 때 사용함
첫번째 파라미터는 어떤 인덱스부터 지울지를 의미하고 (시작점)
두번째 파라미터는 그 인덱스로부터 몇개를 지울지를 의미 (갯수)
const numbers = [10, 20, 30, 40];
const index = numbers.indexOf(30);
numbers.splice(index, 1);
console.log(numbers); // [10, 20, 40];
주로 배열을 잘라낼 때 사용하며
splice와 비슷하지만
중요한 점은 기존의 배열은 건들이지 않음
slice에는 두개의 파라미터를 넣게 되는데
첫번째 파라미터는 어디서부터 자를지 (시작점)
두번째 파라미터는 어디까지 자를지를 의미 (끝점)
const numbers = [10, 20, 30, 40];
const sliced = numbers.slice(0, 2); // 0부터 시작해서 2전까지
console.log(sliced); // [10, 20]
console.log(numbers); // [10, 20, 30, 40]
shift와pop은 비슷하지만 다름
shift는 첫번째 원소를 배열에서 추출함 (추출하며 배열에서 해당 원소는 소멸)
const numbers = [10, 20, 30, 40];
const value = numbers.shift();
console.log(value); // 10
console.log(numbers); // [20, 30, 40]
const numbers = [10, 20, 30, 40];
const value = numbers.pop();
console.log(value); // 40
console.log(numbers); // [10, 20, 30]
shift와pop이 배열에서 값을 추출했다면
unshift와push는 배열에 값을 추가하는 것
const numbers = [10, 20, 30, 40];
numbers.unshift(5);
console.log(numbers); // [5, 10, 20, 30, 40]
const numbers = [10, 20, 30, 40];
numbers.push(50);
console.log(numbers); // [10, 20, 30, 40, 50]
concat은 여러개의 배열을 하나의 배열로 합쳐줌
concat함수는 arr1과 arr2에 변화를 주지 않음
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const concated = arr1.concat(arr2);
console.log(concated); // [1, 2, 3, 4, 5, 6]
join은 배열 안의 값들을 문자열 형태로 합쳐줌
const array = [1, 2, 3, 4, 5];
console.log(array.join()); // 1,2,3,4,5
console.log(array.join(' ')); // 1 2 3 4 5
console.log(array.join(', ')); // 1, 2, 3, 4, 5
reduce함수는 잘 사용할 줄 알면 유용한 내장함수
forEach로 구현
sum을 계산하기 위해 사전에 sum을 선언하고 forEach를 통해 덧셈을 누적시킴
const numbers = [1, 2, 3, 4, 5];
let sum = 0;
numbers.forEach(n => {
sum += n;
});
console.log(sum); // 15
reduce로 구현
reduce함수에는 두개의 파라미터를 전달함
첫번째 파라미터는accumulator와current를 파라미터로 가져와서 결과를 반환하는 콜백함수
두번째 파라미터는reduce함수에서 사용할 초깃값
accumulator는 누적된 값을 의미
쉽게 생각하면 reduce함수로 반환한 값이 accumulator에게 할당되며 반복하는 콜백함수
const numbers = [1, 2, 3, 4, 5];
let sum = numbers.reduce((accumulator, current) => {
console.log({ accumulator, current });
return accumulator + current;
}, 0);
console.log(sum);
추가적으로
index와array파라미터도 받아옴
index는 현재 처리하고 있는 항목이 몇 번째인지 가르키고
array는 현재 처리하고 있는 배열 자신을 의미
const numbers = [1, 2, 3, 4, 5];
let sum = numbers.reduce((accumulator, current, index, array) => {
if (index === array.length - 1) {
return (accumulator + current) / array.length;
}
return accumulator + current;
}, 0);
console.log(sum);
숫자가 아니더라도 가능함
각 원소가 몇 개씩 있는지 세어보는 함수 제작
초기값을{}객체로 설정
const alphabets = ['a', 'a', 'a', 'b', 'c', 'c', 'd', 'e']
const count = alphabets.reduce((acc, current) => {
if (acc[current]) {
acc[current] += 1
} else {
acc[current] = 1
}
return acc
}, {})
console.log(count); // {a: 3, b: 1, c: 2, d: 1, e: 1}
객체 생성자를 네이밍 할때는 반드시 첫글자 대문자
새로운 객체를 만들때는new키워드 필요
function 이름(파라미터) {
this.변수명 = 파라미터;
this.함수명 = function() {
console.log(this.변수명)
}
}
function Animal(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
this.say = function() {
console.log(this.sound);
};
}
const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');
dog.say(); // 멍멍
cat.say(); // 야옹
같은 객체 생성자 함수를 사용하는 경우, 특정 함수 또는 값을 재사용 할 수 있는데
그것이 바로 프로토타입
function Animal(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
// 프로토타입
Animal.prototype.say = function() {
console.log(this.sound);
};
Animal.prototype.sharedValue = 1;
const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');
dog.say();
cat.say();
console.log(dog.sharedValue); // 1
console.log(cat.sharedValue); // 1
아래 코드를 보면 두개의 클래스는 거의 똑같은데 미묘한 차이로 두번이나 선언함 <- 비효율적
이럴 때 사용하는 것이 상속
function Dog(name, sound) {
this.type = '개';
this.name = name;
this.sound = sound;
}
function Cat(name, sound) {
this.type = '고양이';
this.name = name;
this.sound = sound;
}
Dog.prototype.say = function() {
console.log(this.sound);
}
Cat.prototype.say = function() {
console.log(this.sound);
}
클래스.call(this, ...)의 형태로 사용하고
상속받는 클래스.prototype = 부모 클래스.prototype을 통해 프로토타입 공유
function Animal(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
Animal.prototype.say = function() {
console.log(this.sound);
};
Animal.prototype.sharedValue = 1;
function Dog(name, sound) {
Animal.call(this, '개', name, sound);
}
function Cat(name, sound) {
Animal.call(this, '고양이', name, sound);
}
// 프로토타입 공유
Dog.prototype = Animal.prototype;
Cat.prototype = Animal.prototype;
const dog = new Dog('멍멍이', '멍멍');
const cat = new Cat('야옹이', '야옹');
dog.say();
cat.say();
ES6 이후부터는 class 문법이 JS에 추가됨
클래스 내부에 함수를 만들게 되면 자동으로 프로토타입으로 등록이 됨
확인법console.log(클래스명.prototype.함수명)
class Animal {
constructor(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
say() {
console.log(this.sound);
}
}
const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');
extends키워드를 통해 상속받음
super키워드를 통해 자신이 상속받은 클래스의constructor(생성자)를 호출해줌
class Animal {
constructor(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
say() {
console.log(this.sound);
}
}
class Dog extends Animal {
constructor(name, sound) {
super('개', name, sound);
}
}
class Cat extends Animal {
constructor(name, sound) {
super('고양이', name, sound);
}
}
const dog = new Dog('멍멍이', '멍멍');
const cat = new Cat('야옹이', '야옹');
const cat2 = new Cat('야오오옹옹이', '야오옹옹');
CSS 클래스네임을 더 효율적으로 짓기 위한 방법
BEM은 Block, Element, Modifier를 의미함
각각__와--로 구분함
.header__navigation--navi-text {
color: red;
}
위 코드에서 header는 Block, navigation은 Element, navi-text는 Modifier가 됨
BEM은 기본적으로 ID를 사용하지 않으며, calss만을 사용함
또한,어떻게 보이는가가 아닌어떤 목적인가에 다라 이름을 지음
예를 들어, 에러 메시지를 띄우는<p>에게는.red가 아닌.error라는 이름을 줘야함
이름을 연결할 때는block-name과 같이 하이픈 하나만 써서 연결
블럭이란 (독립적인 것이 핵심)
재사용 가능한 기능적으로 독립적인 페이지 컴포넌트
(A functionally independent page component that can be reused)
라고 불림
즉, 블럭 자체를 떼어다가 어딘가에서 쓸 수 있는 단위를 의미

엘리먼트란 블럭을 구성하는 단위 (의존적인 것이 핵심)
자신이 속한 블럭 내에서만 의미를 가지기 때문에 블럭 안에서 떼어다 다른 곳에 쓸 수 없음

아래의 예시를 보면
.search-form은 Block이고,
.search-form__input과.search-form__button은 Element
search-form이란 블럭은 떼어내서 어디든 붙여도 됨
하지만 내부의input과button은 검색을 위한 인풋창이고 버튼이기 때문에
search-form안에서만 존재 의미가 있는 엘리먼트
<form class='search-form'>
<input class='search-form__input'>
<button class='search-form__button'>Search</button>
</form>
엘리먼트 또한 중첩 가능
.block > .block__element1 > .block__element2도 가능하다는 말
BEM의 재밌는 점은.block__element2를.block__element1의 하위 엘리먼트로 보지 않고
둘 모두.block의 엘리먼트로 취급한다는 점
덕분에 클래스네임에 Cascading을 여러번 표시할 필요가 없음
block__element의 형태를 띄고 있지 않음
<form class="search-form">
<div class="search-form__content">
<input class="search-form__content__input">
<button class="search-form__content__button">Search</button>
</div>
</form>
<form class="search-form">
<div class="search-form__content">
<input class="search-form__input"/>
<button class="search-form__button">Search</button>
</div>
</form>
Modifier는 블럭이나 엘리먼트의 속성을 담당함
생긴게 조금 다르거나, 다르게 동작하는 블럭이나 엘리먼트를 만들 때 사용하면 됨

아래의 코드에서
--focused가 수식어에 해당함
이렇게 작성된 것을Boolean타입이라고 하는데, 해당 값이true라고 가정하고 사용함
<ul class="tab">
<li class="tab__item tab__item--focused">탭 01</li>
<li class="tab__item">탭 02</li>
<li class="tab__item">탭 03</li>
</ul>
아래의 예시에서
cool-gray와theme-normal,theme-special이 Key-Value 타입
<div class="column">
<strong class="title">일반 로그인</strong>
<form class="form-login form-login--theme-normal">
<input type="text" class="form-login__id"/>
<input type="password" class="form-login__password"/>
</form>
</div>
<div class="column">
<strong class="title title--color-gray">VIP 로그인 (준비중)</strong>
<form class="form-login form-login--theme-special form-login--disabled">
<input type="text" class="form-login__id"/>
<input type="password" class="form-login__password"/>
</form>
</div>
이미지 출처 (https://nykim.work/15)