javascript 중급

김민지·2022년 9월 6일

프론트

목록 보기
8/13

var, const, let

  • var : 변수재선언o / const,let : 변수재선언x
  • let : 변수재할당o / const: 변수재할당x

객체리터럴

let user = {
            name: 'mike',
            age: 30,
        }

-> 여러개의 객체를 만들어내기위해 생성자 함수가 필요하다

생성자함수

 User(name, age){
   			//빈 객체 생성 this = {}
            this.age = age;
            this.name = name;
   			//객체 반환 코드가 생략되어있음 return this;
        }
let user1= new User('mike',30);
let user2= new User('sally',20);
  • 생성자 함수가 있다면 일일이 객체리터럴을 만들지 않고도 손쉽게 객체를 만들어낼 수 있다

computed property

let a = 'age';
const user = {
     name: 'mike',
     [a] : 30
}
  • 변수 a가 아니라 a에 할당된 값이 들어가게 된다

다양한 method

Object.assign() : 객체 복제

  • const cloneUser = user; 를한다고 복사되지 않는다. user에는 user객체의 참조값이 저장되어있다
    즉, 하나의 주솟값을 두개의 객체가 참조하게 된다
    -> Object.assign을 사용하면 새로 객체를 만들어서 내용을 붙여넣어준다
  • Object.assign(user1, info1, info2)를 실행하게 되면 info1과 info2를 user1 data에 합쳐준다


Symbol

지금까지 property의 key는 문자였다 그런데 문자말고 symbol도 가능하다

const a = Symbol();
const b = Symbol();
//a!=b
  • 원시자료형 중 하나이다
  • symbol은 유일한 식별자를 만들 때 사용한다(변경불가)
  • console.log로 a와 b를 찍어보면 둘다 symbol()이라고 나오지만 a==b나 a===b의 연산결과는 false 가 나온다
  • symbol을 만들때 설명을 넣어줄 수 있다
  • symbol은 이름이 같더라도 다르다. 그런데 이름이 같으면 같은객체를 반환해야할때가 있다. 그때 사용하는것이 Symbol.for() 전역심볼이다
  • symbol()은 매번 다른 symbol값을 생성하지만 Symbol.for() 은 하나를 생성한 뒤에 키를 통해 같은 symbol을 공유한다
const a = Symbol.for('id');
const b = Symbol.for('id');
//a===b
sybmol.keyFor(a);//return id
  • 전역심볼이 아니면 keyfor 를 사용할 수 없다. 대신 a.description;을 통해 생성할때 만든 이름을 알 수 있다

  • 심볼을 완전히 숨길 수 있는 방법은 없다 Object.getOwnPropertySymbols(user);을 하게 되면 심볼들만 볼수있다

  • Reflect.ownKeys(user);는 symbol을 포함한 모든 property를 보여준다

    symbol의 사용이유

    symbol사용이유를 잘 모르겠습니다 예를들어 무수히 많은 변수가 있을때 name이라는 변수가 있는지 모르고 덮어씌우게 된다면 에러가 발생합니다
    하지만 symbol을 사용하면 name이라는 변수가 두개더라도 두개는 다른것으로 인식이 되기 때문에 오류가 나지 않습니다
    근데 이렇게 되면 나중에 더 곤란해지는게 아닐까요?
    같은이름의 변수가 두개라는것.. 둘의 구분을 어떻게 하려고 그걸 냅두는건지 모르겠어요 ㅠ

  • 예를들어 isArray에 대한 함수를 내가 구현했다고 하자. 근데 나중에 isArray가 추가되면서 내가 작성했던 함수는 덮어쓰여지게 되면서 코드가 꼬이게 된다
    이런현상을 막아줄수있다

  • 내가 짠 코드 때문에 남이 짜놓은 코드가 돌아가지 않으면 안된다. 이러한 것을 방지하기 위해서 symbol을 사용할 수 있다

isNaN()

  • NaN == NaN //false이기때문에 오직 isNaN만이 NaN을 판별할 수 있다

특정 위치에 접근

let str = '안녕'

  • str[2]에는 접근이 가능하지만 변경하진 못한다

map

let userList =[
            {name: 'mike', age:30},
            {name: 'mike', age:30},
            {name: 'mike', age:30},
        ];

let newUserList = userList.map((user, idx)=>{
      return Object.assign({}, user, {
          id: idx+1,
          isAdult: user.age >19,
     })
})
  • map의 두번째 인자는 매번 자동증가된다

reduce

  • 현재까지누적된 계산값 = prev
  • 초깃값은 0
const result = arr.reduce((prev, cur) => {
            return prev+cur;
        }, 0)
let userList = [
            {name: 'mike', age:30},
            {name: 'jan', age:20},
            {name: 'jaen', age:10},
             {name: 'mikeee', age:20},
            {name: 'jawswn', age:900},
            {name: 'jaa2n', age:10},
        ];
        let result = userList.reduce((prev, cur)=>{
            if(cur.age > 19) prev.push(cur.name)
            return prev;
        }, []);
let result = userList.reduce((prev,cur)=>{
            return prev += cur.age;
        }, 0);

undefined, NaN, null의 차이

  • undifiend : 선언은 되었으나 값이 할당 되지 않은 상태 (초기화 안하면 무조건 undefined 상태)
  • number 타입이며, '숫자가 아님'을 의미하는 숫자
  • null : 값자체가 없다는 의미가 아니라, 값이긴 한데 어떠한 유효한 값도 아니라는 것을 의미함

구조 분해 할당

배열이나 객체의 속성을 분해해서 그 값을 변수에 담을 수 있게 하는 표현식

let users = ['1','2', '3'];
let [user1, user2, user3] = user;
console.log(user1);//'1'
console.log(user2);//'2'
console.log(user3);//'3'
  • 만약에 여기서 user3의 세번째 요소가 비어있다면 console.log(user3) 은 undefined가 떴을 것이다

기본값

let [a=2, b=1, c=12] = [1,2];

일부 반환값 무시

let [user1, , user2] = ['1', '2', '3'];
        console.log(user1);//'1'
        console.log(user2);//'3'

바꿔치기

[a,b] = [b,c] -> 필요없는 변수를 추가로 선언하지 않아도됨


객체 구조 분해

배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.

let user = {name: 'mike', age:20};
let {name, age} = user;
console.log(name);//'mike'
console.log(age);//20
  • 순서 상관없다
  • 배열 구조 분해와 같이 기본값을 할당할 수 있다

나머지 매개변수, arguments

  • js는 인자가 하나인 메서드를 실행할때 아무것도 넘겨주지 않거나 그 이상을 넘겨주어도 에러가 나지 않는다
  • 함수의 인수를 얻는 방법은 두가지가 있다 1) 나머지 매개변수, 2) arguments

arguments

  • 함수로 넘어온 모든 인수에 접근 가능
  • 함수내에서만 이용가능한 지역 변수
function showName(name){
            console.log(arguments.length);
            console.log(arguments[0]);
            console.log(arguments[1]);
        }
        showName('mike', 'tom');
        //2
        //mike 
        //tom

나머지 매개변수

정해지지 않은 수의 매개변수를 배열로 나타낼 수 있게 한다

function showName(... names){
            console.log(names);
}
showName();//[] , undefined가 아님
showName('mike');//['mike']
showName('mike', 'tom');//['mike', 'tom']
  • 주의) 나머지 매개 변수는 항상 매개변수들 중 가장 마지막에 있어야한다

전개구문

let arr1 = [1,2,3];
let arr2 = [4,5,6];
let result = [...arr1, ...arr2];
console.log(result);
  • 배열 중간에 data넣는거 매우 번거로운데 전개구문을 사용하면 간단하게 할 수 있음
  • 전개구문에서 객체복사는 다른 주솟값을 참조한다

나머지 매개변수와 전개구문의 차이

나머지 매개변수는 함수의 인수 전달 시에 마지막으로 사용되며, 전달된 인수들의 목록을 배열로 압축할때 사용되어진다.
전개 구문은 뭉쳐있는 여러 개의 값들을 개별적인 값들의 목록으로 만들때 사용되어진다. 즉, 나머지 매개변수는 배열로 합쳐주고, 전개 구문은 배열 또는 객체를 펼쳐주는 역할을 한다.

lexical 환경

코드를 실행하기 전 생성되는 특별한 객체로, 실행할 스코프 범위 안에 있는 변수와 함수를 프로퍼티로 저장하는 객체

property

기본적으로 property는 어떤 값을 나타냅니다. 그런데 이 값이 다른 값과 연관되어 있을 때 property라고 부릅니다.

클로저

함수 + lexical 환경

  • 자신이 선언될 당시의 환경을 기억하는 함수
  • js는 어휘적 환경을 가진다
  • 코드가 실행되면 스크립트내에 선언한 변수들이 Lexical환경에 들어간다. 이때 변수는 초기화가 안되어있어서 사용이 불가능하고 함수는 사용이 가능하다
  • let one;이 지나면 one이 undefined로 초기화 된다
  • addOne(5)를 실행하면 새로운 Lexical환경이 하나 더 생긴다
  • 선언이 아니라 실행될떄 lexical환경이 생긴다
		let one;
        one = 1;
        function addOne(num){
            cosloe.log(one+num);
        }
        addOne(5);
  • 위 코드에서는 전역lexical환경내부 lextical환경 두가지가 있다
  • function의 선언에서 num과 one을 일단 내부 lextical에서 찾고 없으면 전역에서 찾는다

서로 다른 lexical environment

  • ex1과 ex2은 서로 다른 lextical 환경을 가지고 있다
function makeAddr(x){
            return function(y){
                return x+y;
            }
        }
        const ex1 = makeAddr(3);

        const ex2 = makeAddr(10);
        console.log(ex1(2));
        console.log(ex2(10));//둘은 다른 lexical 환경을 가지고 있음
}

같은 lexical envirionment

function makeAddr(){
        let num = 0;//선언 후 변경 불가, 은닉화
        return function(){
            return num++;
        };
    }
    let counter = makeAddr();
    console.log(counter());
    console.log(counter());
    console.log(counter());

setTimeout : 일정시간이 지난 후 함수 실행

setInterval : 일정시간 간격으로 함수 반복

  • setTimeout시간을 0으로 해놔도 script가 끝난 이후부터 세기때문에 다음 코드는 1부터 출력된다
setTimeout(function(){
            console.log(2)
        }, 0);
        console.log(1);

call, apply, bind

함수호출방식과 상관엇이 this를 지정할 수 있음

  1. call
const tom = {
            name:"tom"
        };
        function showName(){
            console.log(this.name);
        }
        showName;
        console.log("----------")
        showName.call(tom);
  • call의 두번째 인자부터는 함수가 사용할 매개변수 전달에 쓰인다
  1. apply
  • 매개변수를 배열로 받는다
update.apply(mike, [1099, "single"]];
const min = Math.min([3,10,20,200]);
console.log(min);//NaN

-> 왜 NaN이 나오는걸까? 다음과 같이 코드를 짜야한다

 const nums = [3,10,20,200];
       const min = Math.min(...nums);
       console.log(min);
  • fn([1,2,3,4]) vs fn(1,2,3,4) 가 달라서 위의 예제가 NaN이 나온것이다

call과 apply의 차이

const min = Math.min.apply(null, nums);
const max = Math.max.call(null, ...nums);
  • 동작방식은 같다
  1. bind : 영원히 바꿀 수 있다
    -> 불변이라는 의미인가?

상속, prototype

prototype: class랑 비슷함
상속 : .__proto__ 이용

.__proto__로 상속 구현

const car = {
        wheel: 4,
        drive(){
            console.log("drive..");
        }
    }
const bmw = {
    color: "red"
}
bmw.__proto__ = car;
console.log(bmw.wheel);

생성자 함수로 상속 구현

const car = function (color){
        this.color = color;
        this.drive = function(){
            console.log("drive..");
        };
    };
const x1 = new car("red");
console.log(x1.color);

상속 구현

const Bmw = function (color){
        this.color = color;
};
Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function(){
    console.log("druve,,,");
};
    
const x1 = new Bmw("red");
console.log(x1);

var parent = {pVal:'super'}   
var child = {cVal:'sub'}
child.__proto__ = parent;
child.pVal = 'ss'
console.log(child);
console.log(parent);
  • child.pVal = 'ss'에서 parent의 pVal까지 바뀐게 아니다. child의 pVal을 새로 생성해서 대입한것이다
  • parent값까지 변경하기 위해선 child.__proto__.pVal = 'ss'를 사용해야한다.

instance of

a instance of b : a가 b로부터 생겨난것인지를 t/f로 return 해준다

class

지금까지 비슷한 형태의 객체를 생성하기 위해서는 생성자 함수를 사용했었는데 class로도 만들 수 있다

  • 생성자 함수 사용
const User = function(name, age){
        this.name = name;
        this.age = age;
        this.showName = function(){
          console.log(this.name);
        };
      };
      const mike = new User('mike', 30);
  • 생성자 함수로 showName을 만들면 proto에 저장되는게 아니다
  • 아래 class랑 동일하게 동작하게 하려면 아래의 코드를 this.showName = ~ 코드를 지우고 아래 코드를 넣어주면 된다
  • 마지막 줄의 new User()를 User()로 바꾸게 되면 undefined가 뜬다. 왜냐하면 함수가 반환하는 값이 없기 때문이다
  • 근데 class는 new가 없으면 type error가 아니라 error가 뜨게 된다
  • 여기서 for in 문으로 mike의 요소들을 모두 출력하게 되면 name, age, showName이 모두 출력되지만, 아래 코드의 tom과 같은 경우 name, age만 출력된다
User.prototype.showName = function(){
        console.log(this.name);
      }
  • class 사용
class User2{
        constructor(name, age){//객체 만들어주는 생성자 메서드
          this.name = name;
          this.age = age;
        }
        showName(){
          console.log(this.name);
        }
      }
}
const tom = new User2("tom", 19);
for(const p in tom)
{
	console.log(p);
}
  • class를 사용하여 showName을 만들면 proto하위에 만들어진다

class를 사용하면서 class의 method를 만드는 방법은?

class Dog {
  constructor(name, fn) {
    this.name = name;
    this.fn = fn;
  }
}
const dog = new Dog('hi', () => console.log('hi'));
  • 인스턴스마다 다른 동작이 필요해서 저렇게 동적으로 함수 넣는게 필요한 걸 제외하면 그냥 내부에서 선언하는게 좋을 것 같아요 어차피 프로토타입 체이닝으로 다 접근할 수 있기 때문에..

class의 상속 - extends

 class Car{
        constructor(color){
          this.color = color;
          this.wheels = 4;
        }
        drive(){
          console.log("drive");
        }
        stop(){
          consoloe.log("stop!!!");
        }
      }
      class Bmw extends Car{
        park(){
          console.log("part!");
        }
      }
      const z = new Bmw("red");

class의 오버라이딩

class Bmw extends Car{
        constructor(color){//overriding
          super(color);
          this.navigation = 1;
        }
        park(){
          super.stop();//overriding
          console.log("part!");
        }
      }

promise

비동기 처리에 사용되는 객체입니다

  • 비동기 처리 : 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성
    const pr = new Promise((resolve, reject) => {});

  • resolve : 성공했을때 실행되는 함수

  • reject : 실패했을 때 실행되는 함수

  • callback 함수 : 어떤일이 완료됐을 때 호출되는 함수

  • new promise생성자가 반환하는 promise 객체는 state, result를 property로 갖는다

  • state는 pending(대기) 상태였다가 성공하면 fulfilled가, 실패하면 rejected가 채워넣어진다


https://hyeooona825.tistory.com/24
https://ryublock.tistory.com/43
https://blog.naver.com/magnking/220966405605
https://velog.io/@ye-ji/%EB%82%98%EB%A8%B8%EC%A7%80-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EC%A0%84%EA%B0%9C-%EA%B5%AC%EB%AC%B8Rest-parameters-Spread-syntax

https://ko.javascript.info/prototype-inheritance

profile
안녕하세요!

0개의 댓글