함수는 프로그램 안에서 각각의 작은 단위의 기능들을 수행함
function name(param1, param2) { body... return; }
// function 입력, 함수 이름 지정(파라미터 나열) {함수 안의 기본적인 비즈니스 로직 작성 ... 리턴;}
하나의 함수는 한 가지의 일만 해야함
함수는 동작하는 것이기 때문에 함수의 이름은 커맨드 형태 혹은 동사 형태로 정해야 함
→ e.g. createCardAndPoint -> createCard, createPoint
JS에서 함수는 오브젝트로 간주
→ 함수를 변수에 할당 할 수 있음, 파라미터로 전달이 됨, 함수 리턴 가능
function log(message) {
console.log(message);
}
log('Hello');
log(1234)
primitive 타입 같은 경우 메모리에 값이 그대로 저장되어 있기 때문에 값이 전달 되고, 오브젝트는 메모리에 레퍼런스가 저장되어 있기 때문에 레퍼런스가 전달되어 짐
function changeName(obj) {
obj.name = 'coder';
}
const ellie = { name: 'ellie' };
changeName(ellie);
console.log(ellie);
// {name: "coder"}
파라미터 옆에 원하는 디폴트 값을 지정해 놓으면 사용자가 파라미터를 전달하지 않을 때 값이 대체 되어 사용됨
function showMessage(message, from = 'unknown') {
console.log(`${message} by ${from}`);
}
showMessage('Hi!')
...
을 작성하게 되면 배열 형태로 전달됨
function printAll(...args) {
for (let i = 0; i < args.length; i++) {
console.log(args[1]);
}
}
printAll('dream', 'coding', 'ellie');
// dream
// coding
// ellie
간략한 코드
for (const arg of args) {
console.log(arg);
}
args.forEach((arg) => console.log(arg));
함수에서는 파라미터로 값을 전달받아서 계산된 값을 리턴할 수 있음
function sum(a, b) {
return a + b;
}
const result = sum(1, 2); // 3
console.log(`sum: ${sum(1, 2)}`);
JS에서는 function도 다른 데이터 타입처럼 변수에 할당이 가능하고 그렇기 때문에 함수의 파라미터 인자로도 전달이 되고 함수에 리턴 타입으로도 return이 된다.
const print = function () { // anonymous function
console.log('print');
};
print(); // print
const printAgian = print;
printAgian(); // print
const sumAgian = sum;
console.log(sumAgian(1,3)); // 4
function randomQuiz(answer, printYes, printNo) {
if (answer === 'love ypu') {
printYes();
} else {
printNo();
}
}
// anonymous function
const printYes = function () {
console.log('yes');
};
// named function
// better debugging in debugger's stack traces
// recursions
const printNo = function print() {
console.log('no');
};
randomQuiz('wrong', printYes, printNo); // no
randomQuiz('love you', printYes, printNo); // yes
함수를 간결하게 만들어줌 (anonymous function)
const simplePrint = function () {
console.log('simplePrint');
};
const simplePrint = () => console.log('simplePrint');
함수를 선언함과 동시에 호출
(function hello() {
console.log('IIFE');
})();
// IIFE
Function Expression은 함수가 할당 된 다음부터 호출이 가능
Function declaration은 hoisted가 되기 때문에 함수가 선언되기 전에 호출이 가능함
연관있는 변수와 함수를 묶어 놓는 컨테이너
ES6에서 도입되었으며 클래스가 도입 되기 전에는 클래스를 정의하지 않고 바로 오브젝트를 만들 수 있었다.
class name {
field1;
field2;
method(); // method가 없는 클래스는 data class라고 부름
}
클래스 내부에서도 내부적으로 보여주는 변수와 외부적으로 보여지는 변수를 나누어서 캡슐화 라고 함
클래스를 이용해서 상속과 다형성이 이루어짐
→ 객체지향 언어(object-oriented programming)의 특징
class Person {
// constructor, 오브젝트를 만들 때 필요한 데이터를 전달함
constructor(name, age) {
// fields
this.name = name;
this.age = age; // 데이터 할당
}
// methods
speak() {
console.log(`${this.name}: hello!`);
}
}
// 오브젝트 생성
const ellie = new Person('ellie', 20);
console.log(ellie.name); // ellie
console.log(ellie.age); // 20
ellie.speak(); //ellie: hello!
class User {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
get age() {
return this._age; // call stack 무한반복을 막기 위해 get과 set의 변수 값을 변경해야 함
}
// getter를 정의한 순간, this.age는 메모리에 올라간 데이터를 읽어오는 것이 아닌 getter를 호출하게 됨
set age(value) {
this._ago = value < 0 ? - : value;
}
// setter를 정의한 순간, = age는 바로 메모리의 값을 할당하는 것이 아니라 setter를 호출하게 됨
}
const user1 = new User('steve', 'job', -1);
console.log(user1.age);
user1.age이 -1인 것은 말이 안되기 때문에 get을 이용해서 값을 리턴하고 set을 이용해서 값을 설정할 수 있다.
→ 사용자가 get age를 호출하게 되면 this.age를 리턴해야 되고 새로운 value를 받으면 this.age를 value로 설정하게 된다.
public
생성자를 쓰지 않고 필드를 정의하면 외부에서 접근 가능함 ()
private
#를 붙이면 클래스 내부에서만 접근이 가능해서 값을 볼 수 있고 변경도 되지만 외부에서는 불가능함
class Experiment {
publivField = 2;
#privateField = 0;
}
const Experiment = new Experiment();
console.log(experiment.publivField); // 2
console.log(experiment.privateField); // undefined
오브젝트와 데이터에 상관없이 클래스가 가지고 있는 고유한 값과 이런 데이터에 상관없이 동일하게 반복적으로 사용 되는 메소드가 있을 수 있음
→ Static을 사용하면 오브젝트에 상관없이 클래스 자체에 연결됨
class Article {
static publisher = 'Dream Coding';
constructor(articleNumber) {
this.articleNumber = articleNumber;
}
static printPublisher() {
console.log(Article.publisher);
}
}
const article1 = new Article(1);
const article2 = new Article(2);
console.log(Article.publisher) // Dream Coding
// publisher는 Article이라는 클래스 자체에 붙어있음
Article.printPublisher(); // Dream Coding
오브젝트에 상관없이 공통적으로 클래스에서 쓸 수 있다면 Static과 Static method를 이용해서 작성하는 것이 메모리의 사용을 조금 줄여줌
공통적으로 쓰이는 속성 값을 계속 재사용하면 유지보수하기 쉬워짐
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
console.log(`drawing ${this.color} color!`);
}
getArea() {
return width * this.height;
}
}
// 새로운 클래스를 만들고 싶을 때 extands를 사용해서 Shape를 연장함(상속)
class Rectangle extends Shape {}
class Triangle extends Shape {
// 부모 오브젝트의 함수를 호출하고 재정의한 함수도 호출하려면 super 사용
draw() {
super.draw();
console.log('🔺');
}
// 필요한 함수만 재정의(오버라이딩)
getArea() {
return (this.width * this.height) / 2;
}
}
const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw();
console.log(rectangle.getArea());
const triangle = new Triangle(20, 20, 'red');
triangle.draw();
console.log(triangle.getArea());
오브젝트는 클래스를 이용해서 만들어진 새로운 인스턴스이다.
→ instanceof를 사용하면 오브젝트가 해당 클래스를 이용해서 만들어진 인스턴스인지 확인하는 방법
console.log(rectangle instanceof Rectangle); // true
console.log(triangle instanceof Rectangle); // false
console.log(triangle instanceof Triangle); // true
console.log(triangle instanceof Shape); // true
console.log(triangle instanceof Object); // true
object = { key: value };
오브젝트는 접근할 수 있는 프로퍼티와 그 프로퍼티가 가지고 있는 값으로 이루어짐
primitive type은 변수 하나당 하나의 값만 담을 수 있음
const name = 'ellie';
const age = 4;
print(name, age);
// name과 age를 각각 파라미터로 전달해줘야함
const obj1 = {}; // object literal
const obj2 = new Object(); // object constructor
// 오브젝트 화
function print(person) {
console.log(person.name);
console.log(person.age);
}
const ellie = { name: 'ellie', age: 4 };
print(ellie);
// can add properties later
ellie.hasJob = true;
console.log(ellie.hasJob);
// can delete properties later
delete ellie.hasJob;
console.log(ellie.hasJob);
오브젝트의 안에 있는 데이터에 접근하려면 .
을 이용함
오브젝트는 프로퍼티를 .
을 이용해서 접근이 가능하고 또는 computed property []
에서 접근이 가능함
console.log(ellie.name);
console.log(ellie['name']);
ellie['hasJob'] = true;
console.log(ellie.hasJob)
.
코딩할 때 그 키에 해당하는 값을 받아 오고 싶을 때 사용[]
실시간으로 원하는 키의 값을 받아 오고 싶을 때 사용키와 밸류의 이름이 동일하다면 생략할 수 있음
const person1 = { name: 'bob', age: 2 };
const person2 = { name: 'steve', age: 3 };
const person3 = { name: 'dave', age: 4 };
function makePerson(name, age) {
return {
name,
age,
};
}
const perdon4 = makePerson('ellie', 30 );
JS 엔진이 알아서 오브젝트를 생성함
function Person(name, age) {
// this = {};
this.name = name;
this.age = age;
// return this;
}
const perdon4 = new Person('ellie', 30 );
해당 키를 가진 프로퍼티가 객체 내에 있는지 확인할 때 사용
console.log('name' in ellie);
console.log('age' in ellie);
console.log('random' in ellie); // 정의하지 않은 키를 사용 -> false 출력
console.log(ellie.random); //정의하지 않은 키에 접근 -> undefined 출력
모든 키를 받아와서 처리하고 싶을 때 사용
for (key in ellie) {
// 'ellie'가 가지고 있는 키들이 블럭을 돌 때 마다 'key'라는 지역변수에 할당이 됨
console.log(key);
}
// name
// age
// hasjob
오브젝트를 쓰는 것이 아닌 배열리스트를 사용
const array = [1, 2, 4, 5];
for (value of array) {
console.log(value);
}
// array의 모든 값이 value에 할당 되면서 블럭 안에서 순차적으로 출력하거나 값을 개선할 수 있음
// 1
// 2
// 4
// 5
오브젝트를 복제하는 방법
const user = { name: 'ellie', age: '20' };
const user2 = user;
user2.name = 'coder';
console.log(user);
// user라는 변수의 레퍼런스에는 'ellie'이라는 값과 '20'을 가지고 있음
// user2의 변수는 user가 할당되어 있기 때문에 동일한 레퍼런스와 값을 가지고 있음
// user2가 가리키고 있는 레퍼런스는 'ellie'를 'coder'로 변경함
// 따라서 user가 가리키고 있는 오브젝트가 'coder'로 변경됨
object.assign
// old way
const user3 = {};
for (key in user) { // name, age
user3[key] = user[key];
// user3 프로퍼티의 값은 기존에 있는 user의 값을 가져옴
}
console.log(user3); // {name: 'coder', age: '20'};
const user4 = Object.assign({}, user);
console.log(user4);
객체지향 언어의 특성: 상속, 캡슐화, 다형성 +추상화
역시나 정보처리기사 공부할때 나왔던 개념이다. 근데 이걸 코드로 보니까
함수를 물어봐도 와까라나이
클래스를 물어봐도 와까라나이
그저 울고 있는 아기 코린이가 되었다...
강의 들으면서 모르겠는 부분은 계속 돌려 보고 있는데 쉽지 않다..