자바스크립트 기초 다지기

정승옥(seungok)·2021년 1월 9일
1
post-thumbnail

1. JavaScript란?

  • 웹페이지를 동적, 프로그래밍적으로 제어하기 위해 고안된 언어
  • 브라우저에서 웹서버까지 확장(Node.js)
  • ECMAScript라는 자바스크립트 표준안을 따름

2. 자료형(Data Type)

  • 자바스크립트는 동적 언어로 변수의 타입을 미리 선언할 필요가 없음
let a = 42;    // a 는 이제 Number 임
let b = "bar"; // b 는 이제 String 임
let c = true;  // c 는 이제 Boolean 임
  • 기본 자료형 / 원시 타입
    1) Boolean
    2) Null
    3) Undefined
    4) Number
    5) String
    6) Symbol
    👉 ES6에서 새로 추가됨, 변경이 불가능한 원시 타입
    👉 주로 충돌 위험이 없는 유일한 객체의 속성 키를 만들기 위해 사용
  • 객체 타입
    1) Object

3. 연산자

  • 할당연산자: 오른쪽 피연산자의 값을 왼쪽 피연산자에 할당
    종류: =
  • 비교연산자: 피연산자들을 비교하고 비교에 따라 논리값을 반환
    종류: ==, !==, ===, >, >=, <, <=
  • 산술연산자: 피연산자로 숫자로 갖고 하나의 숫자 값을 반환
    종류: +, -, *, /, %, --, ++
  • 논리연산자: bool값과 사용될때 bool값 반환, (&&,||)는 실제 명시된 피연산자들 중 하나를 반환
    종류: &&, ||, !
  • 비트연산자: 숫자 1과 0로만 구성된 값인 이진수로 연산 가능
    1) 비트 논리 연산자
    👉 AND(곱) a&b
    👉 NOT(반대값) ~a
    👉 OR(하나라도 1이면 1반환) a|b
    👉 XOR(배타적으로 1인경우 1반환) a^b
    2) 비트 이동 연산자:
    👉 a << b
    👉 a >> b
    👉 a >>> b
    비트연산자 개념정리

4. for/while 반복문

  • for

for(i=0;i<10;i++){ // 초기화;조건;실행코드
console.log(i);} // 반복 실행코드
  • for in

    👉 객체에서 문자열로 키가 지정된 모든 속성에 대해 반복
for(const item in store){ // item: 속성(property), store: 객체(Object)
console.log(store[item]);}
  • while

while(i<10){ // 조건
console.log(i);  // 반복 실행코드
--i;
}

5. 함수🍊

  • 함수 표현식과 함수 선언문

    1) 함수 표현식: 함수를 정의하면서 동시에 변수에 함수 리터럴 할당
    2) 함수 선언문: 함수 이름으로 선언
// 함수 표현식
const printName = function(name){ // name은 매개변수(parameter)
  console.log(name);
};
// 함수 선언문
function Print(name){
  console.log(name);
};
// 함수 호출
printName('Max'); // Max는 인자(argument)
Print('Max');
  • 예외처리

    1) 에러 발생을 대비하기 위한 예외 처리
    2) throw문과 try-catch-finally문
    👉 throw문 : 사용자가 고의로 예외를 정의
    👉 try문 : 실행될 선언들
    👉 catch문 : try문에서 예외가 발생했을때 실행될 선언들
    👉 finally문: try문 선언이 완료된 이후 실행될 선언들
function checkNumber(val){
  if(typeof val !== 'number')
    throw '유효하지 않은 값'; // 고의로 에러를 발생시켜 예외상황을 알림
  console.log('숫자형 값으로 확인');
}

try{
  checkNumber(100);
  checkNumber('Wrong Type');
} catch (e){
  console.log(e); // 변수 e에 에러정보 전달
} finally {
  console.log('완료');
}
  • arguments 객체

    👉 함수에 전달되는 인자로 배열 형태의 객체
    👉 length 속성 외에 배열의 어떤 속성, 메소드를 가지고 있지 않음
function sum(){
    // call 메소드로 slice 메소드에 arguments객체 바인딩
    const newArr = Array.prototype.slice.call(arguments);
    console.log(arguments, newArr); // {'0':1,'1':2,'2':3} [1,2,3]
}
sum(1,2,3);
  • 나머지 매개변수

// arguments 객체와 달리 나머지 매개변수는 배열
function sum(...args){
    console.log(args); // [1,2,3]
}
sum(1,2,3);
  • 스코프 이해하기

    1) 스코프(scope): 유효 범위로써 변수와 매개변수가 어띠가지 유효한지 나타냄
    2) 자바스크립트는 기본적으로 전역과 함수 단위로 스코프를 생성
    3) 자바스크립트는 렉시컬 스코프이므로 코드를 작성한 시점에서 상위 스코프 결정
let a = 1;
function printA(){
    console.log(a); // 1
}
function printB(){
    let a = 2;
    printA(a); // 1
}

printA();
printB();
  • 함수 호이스팅 이해하기

    1) 호이스팅: 함수를 선언하기 전에 호출이 가능한 동작
    2) 자바스크립트는 초기화가 아닌 선언만 끌어올림
hello(); // '안녕'
function hello(){
  console.log('안녕');
};

bye(); // TypeError: undefined
let bye = function(){
  console.log('bye');
};

6. 배열

  • 대괄호와 괄호 사이의 요소(들)로 구성
  • 여러개의 데이터를 하나의 변수에 저장
  • 연관된 데이터를 모아서 관리하기 위해 사용되는 데이터 타입
    1) 추가: push(), unshift(), concat() <= 복수의 원소 추가
    2) 제거: pop(), shift()
    3) 정렬: sort(), reverse()
    4) splice(): splice(인덱스, 제거할 개수, 인덱스~인덱스+제거할개수 사이에 추가할 원소)
  • 인덱스: 배열 안에 위치한 요소의 좌표

7. 객체🍓

  • 값들을 그룹으로 묶은 데이터 모음
  • 표현식으로 {} 사용;
  • 키(key)와 값(value)를 한쌍으로 정의하며 이를 속성이라 부름
  • this 키워드를 통해 속성 접근
const myObj = {
    group: {
        minsoo:26,
        gildong:20
    },
    show1: () => {
        console.log(this.group); // undefined
        for(person in myObj.group){
            console.log(person+':'+myObj.group[person]);
        }
    },
    show2: function() {
        console.log(this.group); // myObj.group
        for(person in myObj.group){
            console.log(person+':'+myObj.group[person]);
        }
    }
};
  • 화살표 함수에서 this 주의사항
    1) 화살표 함수는 자신의 this가 없다
    2) 렉시컬 범위의 this가 사용되고 없을 경우 바깥 범위에서 this를 찾는 것으로 검색을 끝낸다
  • 속성 접근/추가/삭제
const family = {
    members:{}
};
// .(콤마) 키이름, [] 안에 키값 문자열을 통해 속성 접근
const members = family.members;
members['nephew'] = {age:5,name:'lyn'}; // 추가
members.niece = {age:3,name:'hyun'}; // 추가
delete members['nephew']; // 삭제
delete members.niece; // 삭제
  • 단축 속성명: 변수명으로 속성의 키와 값을 한번에 정의

const city = 'Seoul',
member = {},
addFamily = function(role,age,name){
this.member[role] = {age, name};
}
const family = {city, member, addFamily};
family.addFamily('father',30,'Max');
  • 비구조화 할당

// 객체: {}안에 속성 이름을 넣어 객체의 여러 속성을 한 번에 가져옴
// 배열: []안에 변수에 배열 요소가 순서대로 할당
const obj = {
    a:1,
    b:2
}
const {a, b} = obj; // a = 1, b =2
const arr = [1,2,3];
const [e,f,g] = arr; // e = 1, f = 2, g = 3

8. var / let / const 변수 선언🍅

  • var : 함수 단위의 유효범위를 가짐
  • let : 블록 단위의 유효범위를 가짐
  • const : 블록 단위의 유효범위를 가지고 선언시 값을 할당해야 하고 이후에 재할당을 할 수 없음
if(true){
  var v = 'function-scope';
  let l = 'block-scope';
}
console.log(v); // function-scope
console.log(l); // ReferenceError
  • let 은 블록 시작부터 선언이 이루어진 라인까지 일시적으로 접근을 막음
  • const객체를 할당하면 불변 객체가 되지 않고 속성에 다른 값을 할당할 수 있음
let l = '바깥';
if(true){
  console.log(l); // ReferenceError
  let l = "안";
}

const user = {
  name: 'Jeong',
  age: 26
};
console.log(user.name, user.age); // Jeong 26
user.name = 'Jay';
user.age = 20;
console.log(user.name, user.age); // Jay 20

9. 스코프 체인🍌

  • 스코프체인 : 유효범위(스코프)가 연결되어 있음을 나타냄
  • 실행 컨텍스트
    1) 코드가 실행되기 위해 필요한 정보를 가짐
    2) 실행 가능한 코드가 실행될 때 생성
    3) 렉시컬 환경을 가짐
    4) 전역컨텍스트 👉 전역코드 평가 👉 실행컨텍스트 👉 코드 실행/종료 후 제거
  • 렉시컬 환경 : 환경 레코드외부 렉시컬 환경으로 구성
  • 환경 레코드: 식별자와 가르키는 값이 키(key)와 값(value)로 기록
  • 외부 렉시컬 환경: 자신의 실행 환경을 감싸는 외부 실행 환경에 대한 참조
실행 컨텍스트 = {
  	렉시컬 환경: {
  		환경 레코드: {},
  		외부 렉시컬 환경: 참조
	}
}

let student = 'Jeong';
// 전역 실행컨텍스트 👉 printName 실행컨텍스트 👉 printBoth 실행컨텍스트
// printBoth는 printName 참조 
// printName은 전역 실행컨텍스트를 참조
function printName(){
  let teacher = 'Kim';
  
  function printBoth(){
    console.log(student);
    console.log(teacher);
  }
  
  printBoth();
  console.log('print finished');
}
printName();
console.log('finished');

10. 클로저🍉

  • 클로저 : 함수가 정의될 때렉시컬 환경을 기억하는 함수
function Count(){
  let count = 0;
  return {
    increase: function(){
      ++count;
    },
    get: function(){
      return count;
    }
  };
};
const counter1 = Count();
const counter2 = Count();

counter1.increase();
counter1.increase();
counter2.increase();
console.log(counter1.get()); // 2
console.log(counter2.get()); // 1
  • counter1과 counter2는 다른 렉시컬 환경에서 환경 레코드에서 count에 접근
  • increase와 get 함수는 실행 컨텍스트가 각각 생성되고 각각의 실행 컨텍스트 렉시컬 환경을 기억하는 클로저

11. 화살표 함수🍇

  • 매개변수가 하나일 경우 인자를 정의할 때 괄호 생략 가능
  • 매개변수가 없거나 둘 이상일 경우 괄호 작성
  • 코드 블록을 지정하지 않고 한 문장으로 작성 시 return 문을 사용하지 않아도 결과값 반환
  • 코드 블록을 지정했을 경우 return 문을 작성해야 결과값을 반환하고 없을 시 undefined 반환
const sum1 = a => a + a;
const sum2 = (a,b) => a + b;
const sum3 = (a,b) => {
  return a + b;
} 
console.log(sum1(2)); // 4
console.log(sum2(1,2)); // 3
console.log(sum3(1,2)); // 3

12. 객체지향 프로그래밍🍋

  • 객체지향 프로그래밍 : 프로그램을 객체들로 구성하고 객체들 간에 서로 상호작용하도록 작성하는 방법
  • 객체지향에서 "객체" : 식별 가능한 구체적인 사물 또는 추상적인 개념
  • 객체는 특징적인 행동(메소드)변경 가능한 상태를 가짐
  • 함수 값으로 가지는 속성을 메소드, 그 외는 변경 가능한 상태
const teacher = {
  name: 'Jeong',
  age: 30,
  teach: function(student){
    student.gainKnowledge();
  }
}
const student = {
  name: 'Kim',
  age: 10,
  knowledge: 0,
  gainKnowledge: function(){
    ++this.knowledge;
  }
}
teacher.teach(student);
console.log(student.knowledge); // 1
  • 메소드 teach를 통해 객체 teacher, student 간에 메시지 전달
const gainKnowledgeProto = {
  gainKnowledge: function(){
    ++this.knowledge;
  }
}
const student = {
  name: 'Jeong',
  knowledge: 10,
  __proto__: gainKnowledgeProto
}
student.gainKnowledge();
console.log(student.knowledge); // 11
  • 자바스크립트는 프로토타입 기반으로 객체지향 프로그래밍을 지원
  • 기존 객체를 복사하여 새로운 새로운 객체를 생성
  • 프로토타입으로 객체에 공통 사항을 적용할 수 있음
  • __proto__ 속성으로 원형 객체를 정의
  • __proto__ 속성에 객체를 할당하지 않으면 기본적으로 Object.prototype 객체가 연결

13. 생성자 함수🍆

  • 객체를 생성하기 위한 방법으로 함수 사용
  • new 키워드를 사용하여 함수를 호출하면 return 문이 없어도 새로운 객체 반환
  • 생성자 함수 : 객체를 생성하는 역할을 하는 함수
  • 함수명을 대문자로 시작하는 관례를 가짐
function Teacher(name,age,subject){
  this.name = name;
  this.age = age;
  this.subject = subject;
  this.teach = function(student){
    console.log(`${student}에게 ${this.subject}를 가르쳤습니다.`);
  }
}

const Jeong = new Teacher('Jeong',30,'JavaScript');
Jeong.teach('Kim'); // Kim에게 JavaScript를 가르쳤습니다.
  • 객체에 타입이 적용되면 해당 객체는 그 타입의 인스턴스라 부름
  • 위 코드에서 Jeong 객체는 Teacher 생성자 함수의 인스턴스

14. 프로토타입 기반 상속🥭

  • 모든 함수는 prototype 속성으로 프로토타입 객체를 가짐
  • 모든 인스턴스는 해당 생성자 함수의 프로토타입 객체의 속성과 메소드를 상속
  • 모든 객체는 __proto__ 속성을 가지고 __proto__ 속성은 해당 객체를 생성한 생성자 함수의 프로토타입 객체를 가르킴
function Storage(){
  this.dataStore = {};
}
Storage.prototype.put = function(key, data){
  this.dataStore[key] = data;
}
Storage.prototype.get = function(key){
  return this.dataStore[key];
}
const productStorage = new Storage();
productStorage.put('Iphone',{price:'$900', color:'black'});
console.log(productStorage);
// Storage { dataStore: { Iphone: { price: '$900', color: 'black' } } }

function RemovableStorage(){
  Storage.call(this);
}
RemovableStorage.prototype = Object.create(Storage.prototype);
RemovableStorage.prototype.removeAll = function(){
  this.dataStore = {};
}
const productStorage2 = new RemovableStorage();
productStorage2.put('Iphone',{price:'$900', color:'white'});
console.log(productStorage2);
// Storage { dataStore: { Iphone: { price: '$900', color: 'white' } } }
productStorage2.removeAll();
console.log(productStorage2);
// Storage { dataStore: {} }
  • Storage 생성자 함수에 내부 속성 dataStore, 메소드 put, get을 추가
  • Storage 타입의 인스턴스 productStorage는 Storage 생성자 함수에 정의된 메소드, 속성을 상속
  • Storage.call(this) : Storage 생성자 함수에서 정의된 속성(dataStore)을 추가
  • Object.create(Storage.prototype) : Storage 생성자 함수의 프로토타입 객체가 RemovableStorage 함수의 프로토타입 객체의 __proto__에 할당
  • Storage와 RemovableStorage의 프로토타입이 상속관계를 가짐
  • RemovableStorage 생성자 함수에 의해 만들어진 인스턴스는 내부에 없는 메소드를 RemovableStorage 생성자 함수의 프로토타입에서 먼저 찾고 없으면
    Storage 생성자 함수의 프로토타입에서 찾음
  • 프로토타입 객체가 서로 연결되어 있음을 프로토타입 체인이라 함

15. 클래스🍐

클래스

  • 별도 타입의 객체를 생성하는 설계 도면
  • 클래스를 통해 객체가 가져야 할 상태와 행위들을 속성와 메소드로 정의
  • 해당 클래스에서 만들어진 객체들은 클래스에 정의된 특성에 따라 행위를 함
  • 클래스에 의해 만들어진 객체들을 해당 클래스의 인스턴스라고 함
class Cart {
  constructor() {
    this.store = {};
  }
  addProduct(product<) {
    this.store[product.id] = product;
  }
  getProduct(id) {
    return this.store[id];
  }
}

const cart1 = new Cart();
cart1.addProduct({id:0,name:'노트북'});
console.log(cart1); // Cart { store: { '0': { id: 0, name: '노트북' } } }
const noteBook = cart1.getProduct(0);
console.log(noteBook); // { id: 0, name: '노트북' }
  • constructor로 생성자 함수 정의
  • new 키워드를 사용하여 객체를 생성

클래스 상속

class Parent {
  constructor(mom,dad){
    this.mom = mom;
    this.dad = dad;
  }
  showFamily(){
    console.log('We are Family');
  }
}

class Children extends Parent{
  constructor(mom,dad,son){
    super(mom,dad);
    this.son = son;
  }
  showAll(){
    this.showFamily();
    console.log(`${this.mom} ${this.dad} ${this.son}`);
  }
}

const myFamily = new Children('Amy','John','Tom');
myFamily.showAll(); 
// We are Family
// Amy John Tom
  • extends 키워드를 사용해 클래스 상속
  • super 키워드를 사용해 생성자 함수에 상속한 부모 클래스의 생성자 함수 호출
  • 상속을 통해 부모 클래스에 정의된 메소드를 사용할 수 있음

클래스 정적 메소드와 속성

class Product {
  static build(name,price){
    const id = Math.floor(Math.random() * 1000);
    return new Product(id, name, price);
  }
  static getTaxPrice(product){
    return (product.price * 0.1) + product.price;
  }
  constructor(id, name, price){
    this.id = id;
    this.name = name;
    this.price = price;
  }
}

class DeposableProduct extends Product {
  depose(){
    this.depose = true;
  }
}

const gum = Product.build('껌',1000);
console.log(gum); // { id: 64, name: '껌', price: 1000 }

const cloth = new DeposableProduct(1,'옷',5000);
const clothTax = DeposableProduct.getTaxPrice(cloth);
console.log(clothTax); // 5500
  • 정적 메소드클래스를 통해 직접 호출하는 메소드
  • 클래스로 상속하게 되면 정적 메소드 또한 상속
class ProductCode{
  static get Default_Code(){
    return "SeungOk's ";
  }
  constructor(id){
    this.id = id;
    this.code = ProductCode.Default_Code + id;
  }
}
ProductCode.getNumber = '1234';
const firstProduct = new ProductCode('001');
console.log(ProductCode.Default_Code); // SeungOk's 
console.log(firstProduct.code); // SeungOk's 001
console.log(ProductCode.getNumber); // 1234
console.log(firstProduct.number); // 1234
  • 정적 속성 또한 static 키워드get 키워드를 통해 정의
  • 클래스 몸통 블록 밖에서도 정의할 수 있음
  • 가독성을 위해 몸통 블록 안에서 정의하는 것이 좋음

16. this🌰

this.valueA = 'a'
console.log(valueA); // a
valueB = 'b';
console.log(this.valueB); // b

function checkThis(){
  console.log(this); // Window
}
function checkThis2(){
  'use strict'
  console.log(this); // undefined
}
  • 브라우저 환경에서 this를 전역으로 사용하면 전역 객체인 Window 객체를 가르킴
  • 엄격한 모드에서 실행하면 this는 undefined가 됨
function Product(name,price){
  this.name = name;
  this.price = price;
}
const product1 = Product('패딩',10000);
console.log(window.name, window.price); // 패딩 10000
  • 생성자 함수를 new 키워드 없이 호출하면 this는 window 객체를 가르킴
  • new 키워드와 함께 호출해야 this는 해당 객체를 가르킴
const product2 = {
  name: '바지',
  price: 5000,
  getVAT: function(){
    return this.price / 10;
  }
};
const calVAT1 = product2.getVAT();
console.log(calVAT1); // 500
const calVAT2 = product2.getVAT;
const VAT2 = calVAT2();
console.log(VAT2); // 1000
const calVAT3 = calVAT2.bind(product2);
const VAT3 = calVAT3();
console.log(VAT3) // 500
  • 메소드를 다른 변수에 저장하고 그 변수를 통해 호출하면 일반적인 함수가 호출되어 this는 전역객체를 가르침
  • 그러므로 이전 코드의 window.price를 기준으로 계산됨
  • 호출되는 시점에 점(.)연산자와 객체가 함께 주어져야 this가 해당 객체가 됨
  • bind 메소드를 통해 전달한 인자값으로 this를 변경할 수 있음
const counter1 = {
  count: 0,
  findThis: function(){
    const me = this;
    console<.log(me); // counter1
    function innerBlock(){
      me.count += 1;
      console.log(this.count); // undefined
    }
    innerBlock();
  }
}
// undefined
counter1.findThis();
const counter2 = {
  count: 0,
  findThis: function(){
    const me = this;
    const innerBlock = () => {
      me.count += 1;
      console.log(this.count); // 1
    }
    innerBlock();
  }
}
counter2.findThis();
  • 메소드 안에서 중첩함수로 작정되면 this는 전역객체를 가르킴
  • 화살표 함수에서 this는 부모 환경의 this를 가리킴
  • 화살표 함수는 작성하는 시점의 부모 환경에서의 this로 정의되고 변경이 불가능

17. 모듈🥦

모듈 이해하기

  • 파일이나 코드의 묶음 단위
  • 애플리케이션의 구성요소
  • 모듈 단위로 코드를 재사용
  • 작은 기능 단위로 분리하여 관리
// hello.js
export function hello(name){
  console.log(`${name}! Hello!`);
}
// app.js
import {hello} from './hello.js';
hello('SeungOk'); // SeungOk! Hello
  • export 키워드를 통해 모듈 내 특정 코드를 외부에서 사용
  • import 키워드를 통해 export한 코드들을 가져옴
  • export와 import를 통해 모듈은 의존 관계를 형성
  • 여러 모듈들이 의존 관계를 맺어 의존 그래프를 형성
  • 위코드를 실행하면 SyntaxError: Cannot use import statement outside a module 에러 발생
  • package.json에서 "type" : "module"로 설정하면 에러 해결
  • 모듈로 정의된 파일들을 실행하는 방법
    1) 런타임 로딩
    👉 의존 관계가 형성된 모듈들을 애플리케이션 구동 시점에 HTTP 요청으로 불러오고 실행
    👉 system.jsrequire.js같은 모듈 로더 필요
    2) 번들링
    👉 의존 관계가 형성된 모듈들을 하나의 파일로 묶음
    👉 애플리케이션이 구동할 때 묶여진 파일을 로드
    👉 개발시점에서 이루어지고 브라우저 환경이 아닌 node.js 환경에서 이루어짐
    👉 대표적인 모듈 번들러로 웹팩이 있음

모듈 기본값

// hello.js
export default class Hello{
  constructor(greeting){
    this.greeting = greeting;
  }
  hi(name){
    console.log(`${name} ${this.greeting}`);
  }
}
// app.js
import Hello from './hello.js'

const greet = new Hello('Nice to Meet You!');
greet.hi('SeungOk!'); // SeungOk! Nice to Meet You!
  • 기본으로 내보내는 값을 정의
  • 기본형 값과 객체, 함수, 클래스 모두 올 수 있음
  • 단, 하나의 모듈에서 한번만 사용 가능
  • 즉, 하나의 값만 defualt로 정의 가능
  • var, let, const와 같은 변수선언 키워드는 올 수 없음

모듈 여러이름 내보내고 가져오기

// multiModule.js
export const version = 'v1.0';
export const sum = (a,b) => a+b;
// app.js
import {version, sum} from './multiModule.js';
console.log(version, sum(1,2)); // v1.0 3
  • 기본값과 달리 중복되지 않는 한 여러이름을 내보낼 수 있음

모듈 다양한 방식으로 사용하기

// version.js
export default function sum(a,b){
  return a+b;
}
export const version = 'v1.0';
export let value = 1;
setTimeout(()=>{
  value++;
},1000);
// app.js
import {version as moduleVersion} from './version.js';
import * as Version from './version.js';
import {value} from './version.js';
console.log(moduleVersion); // v1.0
console.log(Version.default(1,2), Version.version) // 3 v1.0
setTimeout(()=>{
  console.log(value); // 2
},2000); //
  • as 키워드로 가져온 값을 다른 이름으로 사용
  • *을 이용하여 전체를 가져오고 as 키워드로 이름 부여
  • Version은 모듈 객체로 version, default 속성을 가짐
  • 내보낸 모듈에서 값을 변경하게 되면 가져온 모듈에서도 영향을 받음
profile
Front-End Developer 😁

0개의 댓글