가장 쉬운 배열 내장함수
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)