Node
JavaScript 문법

JavaScript

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

대부분의 문법이 dart와 같다. 그래서 다른 부분이나 처음 알게 된 내용을 정리해보고자 한다.

변수 선언

let str2 = "Hello"; // 변수
const str3 = "Hello"; // 상수

var 키워드는 사용하지 않는다.

Hoisting

Hositing이란 ?
모든 변수 선언문이 코드의 최상단으로 이동되는 것처럼 느껴지는 현상

console.log(str1); // undefined
 
var str1 = "Hello";
 
console.log(str2); // Error, Cannot access 'str2' before initialization
 
let str2 = "Hello";
 
console.log(str3); // Error, Cannot access 'str3' before initialization
 
const str3 = "Hello";
 
// 실제로 없는 변수는 not defined로 에러가 발생한다
console.log(str4) // str4 is not defined

에러가 발생하는 이유는 str2와 str3는 undefined로 선언이 되지만
let 키워드와 const 키워드는 초기화하기 이전에 접근이 불가능하기 때문에 에러가 발생한다.
var 키워드는 hoisting으로 인한 버그가 발생할 가능성이 있어서 사용하지 않는다.

Array

muttable

기존 배열의 메모리에서 값을 변경하는 함수들

push

배열의 끝에 값을 추가하고 추가한 배열의 길이를 return

let ive = ['안유진', '가을', '레이', '장원영', '리즈', '이서'];
 
console.log(ive.push('제니')); // 7
console.log(ive); // ['안유진', '가을', '레이', '장원영', '리즈', '이서', '제니']

pop

배열의 끝에 값을 제거하고 제거한 값을 return

let ive = ['안유진', '가을', '레이', '장원영', '리즈', '이서'];
 
console.log(ive.pop()); // '이서'

unshift

push와 반대로 배열의 맨 왼쪽 끝에 데이터를 넣음

  • 시간 복잡도 : O(n)
let ive = ['안유진', '가을', '레이', '장원영', '리즈', '이서'];
 
console.log(ive.unshift('제니')); // 7
console.log(ive); // [ '제니', '안유진', '가을', '레이', '장원영', '리즈', '이서' ]

shift

pop과 반대로 맨 왼쪽(스택의 최하단)에 있는 데이터를 뽑아낸다.

  • 시간 복잡도 : O(n)
let ive = ['안유진', '가을', '레이', '장원영', '리즈', '이서'];
 
console.log(ive.shift()) // ['안유진']
console.log(ive); // [ '가을', '레이', '장원영', '리즈', '이서' ]

splice

splice(n,m)은 index기준 n \<= index \< m 만큼의 데이터를 삭제한다.

let ive = ['안유진', '가을', '레이', '장원영', '리즈', '이서'];
console.log(ive.splice(0, 2)) // [ '안유진', '가을' ]
console.log(ive) // [ '레이', '장원영', '리즈', '이서' ]

reverse

let ive = [1,2,3,4,5];
console.log(ive.reverse()); // [ 5, 4, 3, 2, 1 ]

Object

Object는 기본적으로 key : value 형식을 갖고 사용할 때는 map을 사용하듯이 사용하거나 decimal을 이용해서 값을 불러올 수 있다.

let yuJin = {
  name : "안유진",
  group : "Ive", 
  // 함수 사용 가능 
  dance : function() {
    return "안유진이 춤을 춥니다."
  }
};
const nameKey = "name";
// 아래 세 개는 전부 같은 표현 
console.log(yuJin.name);
console.log(yuJin["name"]);
console.log(yuJin[nameKey]);
 
console.log(yuJin.dance());

Object 내의 변수 사용

let yuJin = {
  name : "안유진",
  group : "Ive",
  dance : function() {
    return `${this.name} 춤을 춥니다.`
  }
};
 
console.log(yuJin.dance());

변수로 Object 생성

const nameKey = "name";
const nameValue = "안유진";
let yuJin2 = {
  [nameKey] : nameValue,
}
 
console.log(yuJin2.name);

모든 키/값 가져오기

const yuJin = {
  name : "안유진",
  group : "Ive",
  dance : function() {
    return `${this.name} 춤을 춥니다.`
  }
};
 
// 모든 키 가져오기 
console.log(Object.keys(yuJin));
// 모든 값 가져오기 
console.log(Object.values(yuJin));

객체의 특징

  1. 객체 안의 프로퍼티나 메서드는 변경할 수 있다.
  2. const로 선언할 경우 객체 자체를 변경할 수 없다.
const yuJin = {
  name : "안유진",
  group : "Ive",
  dance : function() {
    return `${this.name} 춤을 춥니다.`
  }
};
yuJin.group = "black pink";
yuJin = {} // error
 
console.log(yuJin.group); // black pink

Copy by Value/Reference

  • Copy by value : 값에 의한 전달
  • Copy by reference : 참조에 의한 전달

기본적으로 모든 primitive 값은 Copy by value로 동작한다.

  • premitive : 기본 타입
Copy By Reference
const name = "안유진";
const yuJin = {
  name,
  group : "IZ*ONE",
};
 
const yuJin2 = yuJin;
 
yuJin2.group = "Ive"
 
console.log(yuJin.group);
console.log(yuJin.group);
console.log(yuJin === yuJin2); // true

try...catch

function runner() {
  console.log("Hello");
  throw new Error("큰 문제가 생겼습니다.");
  console.log("World");
}
 
try {
  runner();
} catch(e) {
  console.log(e);
  console.log("에러가 발생시 이런 행동을 합니다.");
} finally {
  console.log('그래서 이렇게 끝이 납니다.')
}

class

클래스를 typeof로 확인해보면 함수라는 것을 알 수 있다. 그러나 객체를 typeof로 확인해보면 object라는 것을 알 수 있다.

class IdolModel {
  name = "안유진";
  year = 2003;
}
 
  sayName() {
    console.log(`내 이름은 ${this.name}이야.`);
  }
 
const yuJin = new IdolModel;
yuJin.sayName();
console.log(yuJin); // 안유진
console.log(typeof IdolModel); // function
console.log(typeof yuJin); // object

Constructor

Javascript에는 construntor라는 키워드가 있다. 재밌는 점은 Construntor에 값을 넣지 않아도 에러가 발생하지 않는다는 것이다.

class IdolModel {
  name;
  year;
  // private 값
  #group;
  constructor(name, year, group) {
    this.name = name;
    this.year = year;
    this.#group = group;
  }
}
 
const yuJin = new IdolModel('안유진', 2003);
const wonYoung = new IdolModel();
console.log(`${yuJin.name}\t${yuJin.year}`+ "\n" + `${wonYoung.name}\t${wonYoung.year}`); // 안유진, undefined

Getter와 Setter

Javascript에서는 get이라는 키워드와 set이라는 키워드가 존재한다.

class IdolModel {
  name;
  year;
  #group;
  constructor(name, year, group) {
    this.name = name;
    this.year = year;
    this.#group = group;
  }
 
  get nameAndYear() {
    return `${this.name} ${this.year}`;
  }
 
  set setName(value) {
    this.name = value;
  }
 
  get group() {
    return this.#group;
  }
 
  set group(value) {
    this.#group = value;
  }
}
 
const yuJin = new IdolModel('안유진', 2003);
yuJin.setName = "유진";
yuJin.group = "ive";
console.log(yuJin.group);
console.log(yuJin.nameAndYear);

Static and Factory

class IdolModel {
  name; 
  year;
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
 
  static fromObject(obj) {
    return new IdolModel(obj.name, obj.year);
  }
  static fromList(list) {
    return new IdolModel(list[0], list[1]);
  }
}
 
const yuJin = new IdolModel('YuJin', 2003);
const yuJin2 = IdolModel.fromList(['YuJin', 2003]);
const yuJin3 = IdolModel.fromObject({ yuJin2: yuJin });
console.log(yuJin2);
console.log(yuJin3);
console.log(yuJin3 === yuJin); // false

상속

javascript에는 interface나 abstract class가 없다.

class IdolModel {
  name; 
  year;
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
 
  introduce() {
    return `My name is ${this.name}, I'm ${this.year} years old`;
  }
}
 
class FemaleIdolModel extends IdolModel {
  part;
  constructor(name, year, part) {
    super(name, year);
    this.part = part;
  }
  // override 키워드 없이 override 가능
  introduce() {
    // 부모 위젯의 함수를 호출 가능하다 (변수는 불가능)
    return super.introduce() + ` I'm in ${this.part} part`;
  }
}
 
const yuJin = new FemaleIdolModel('YuJin', 2003, 'Dance');
console.log(yuJin.introduce());

생성자 함수

class를 다음과 같은 방식으로 선언하기도 한다.

function IdolModel(name, year) {
  this.name = name;
  this.year = year;
}

Property Attribute

  • Property : Object를 선언했을 때 그 안에 들어가는 변수, 메서드 등을 전부 프로퍼티(Property)라고 한다.
  1. 데이터 프로퍼티 : 키와 값으로 형성된 실질적으로 값을 가지고 있는 프로퍼티
  2. 액세서 프로퍼티 : 자체적으로 값을 갖고 있지 않지만 다른 값을 가져오거나 설정할 때 소출되는 함수로 구성된 프로퍼티(ex. getter, setter)
const yuJin = new IdolModel('YuJin', 2003, 'Dance');
console.log(Object.getOwnPropertyDescriptors(yuJin)); // 모든 프로퍼티에 대해서 알려줌
console.log(Object.getOwnPropertyDescriptor(yuJin, 'name')); // 특정 프로퍼티에 대해서 알려줌
/**
 * {
  value: 'YuJin', -> 실제 프로퍼티의 값
  writable: true, -> 값을 수정할 수 있는지 여부, false일 경우 수정 불가능
  enumerable: true, -> 열거가 가능한지 여부
  configurable: true -> 프로퍼티 어트리뷰트의 재정의가 가능한지를 판단
                        false일 경우 해당 프로퍼티의 삭제, 어트리뷰트 값의 변경이 불가능
                        단, writable이 true일 경우 값의 변경은 가능
}
 */
  • Emunerable, Writable, Configurable 예시
Object.defineProperty(yuJin2, 'name',{
  enumerable: false, 
});
 
 
console.log(Object.getOwnPropertyDescriptors(yuJin2));
 
console.log(Object.keys(yuJin2)); // name이 나오지 않음
console.log(yuJin2.name); // 값은 존재하지만 열거가 불가능 하다는 것을 알 수 있음