👩🏻‍💻 TIL

JavaScript / TypeScript fundamental

ji-hyun 2022. 3. 16. 02:08

class 는 객체를 만들어준다.

 

class Person { 
} 

let kim = new Person(); 
console.log(kim);

 

실행결과

Prototype 이 객체임을 보여준다.

 

객체의 이름은 Peroson

 

 

 

 

 

Class 초기값 설정해주기

Constructor(생성자)를 이용하면 class 객체의 초기 값을 설정해 줄 수 있다.

 

 

 

new 있으면 construtor 실행 (생성자 실행)

 

 

 

 

 

 

이거는 타입스크립트 문법이 혼용됨

 

class Danbibase {
	name= "";
	contructor(name: string){
		this.name = name;
} }

const jihyun = new Danbibase("이지현");

 

 

 

 

 

class Person { 
	constructor (name,age, city) { 
        	this.name = name; 
        	this.age = age; 
            	this.city = city; 
         } 
         	//메서드생성 
         	nextYearAge() { 
                return Number(this.age) + 1; 
             } 
 } 
                 
                 
                 
let kim = new Person('kim','24','seoul'); 
console.log(kim.nextYearAge());

 

 

 

 

 

 

 

 

get set

 

class Danbibase {
	name= "";
	contructor(name: string){
		this.name = name;         // set 호출
		} 
	set name(name: string){
		this.name = name;
	}
}

 

이러면 무한 실행됨

this set 호출하기 때문

 

 

 

 

 

 

 

 

 

 

 

모듈

 

package.json 은 json 형식임

package.json 을 먼저 찾게 됨

package.json -> keyword 있으면 그 해당하는 keyword 있는지 찾게 됨

 

index 를 넣어주기

 

 

import * as module from "./module"; 

// 모두를 가져오는데 module 가져온다.

 

 

 

 

 

 

 

 

 

 

 

클로저

개념

신일님 법인카드가 필요한데 없다.

본부장님한테 물어서 빌림 -> 결제 -> 본부장님한테 다시 돌려줌 -> 근데 신일님이 법인카드를 복사본해서 가짐 -> 신일님 사용 가능

 

 

클로즈 = 닫는다.

 

스코프는 함수를 호출힐 때가 아니라 선언할 때 발생한다!

 

 

함수 안에 함수가 있다.

 

 

    function init() {
      var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
      function displayName() { // displayName() 은 내부 함수이며, 클로저다.
        alert(name); // 부모 함수에서 선언된 변수를 사용한다.
      }
      displayName();
    }
    init();

 

 

 

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.

 

여기서 "lexical"이란, 어휘적 범위 지정(lexical scoping) 과정에서 변수가 어디에서 사용 가능한지 알기 위해 그 변수가 소스코드 내 어디에서 선언되었는지 고려한다는 것을 의미한다. 단어 "lexical"은 이런 사실을 나타낸다. 중첩된 함수는 외부 범위(scope)에서 선언한 변수에도 접근할 수 있다.

 

 

init()은 지역 변수 name과 함수 displayName()을 생성한다. displayName()은 init() 안에 정의된 내부 함수이며 init() 함수 본문에서만 사용할 수 있다. 여기서 주의할 점은 displayName() 내부엔 자신만의 지역 변수가 없다는 점이다. 그런데 함수 내부에서 외부 함수의 변수에 접근할 수 있기 때문에 displayName() 역시 부모 함수 init()에서 선언된 변수 name에 접근할 수 있다. 약 displayName()가 자신만의 name변수를 가지고 있었다면, name대신 this.name을 사용했을 것이다.

 

※ 쉽게 이해하면 내부 함수는 외부 함수의 변수를 참조할 수 있다.

 

 

 

    function makeFunc() {
      var name = "Mozilla";
      function displayName() {
        alert(name);
      }
      return displayName;
    }

    var myFunc = makeFunc();
    //myFunc변수에 displayName을 리턴함
    //유효범위의 어휘적 환경을 유지
    myFunc();
    //리턴된 displayName 함수를 실행(name 변수에 접근)

 

 

이 코드는 바로 전의 예제와 완전히 동일한 결과가 실행된다. 하지만 흥미로운 차이는 displayName() 함수가 실행되기 전외부함수인 makeFunc()로부터 리턴되어 myFunc 변수에 저장된다는 것이다.

 

 

 

한 눈에 봐서는 이 코드가 여전히 작동하는 것이 직관적으로 보이지 않을 수 있다. 몇몇 프로그래밍 언어에서, 함수 안의 지역 변수들은 그 함수가 처리되는 동안에만 존재한다. makeFunc() 실행이 끝나면(displayName함수가 리턴되고 나면) name 변수에 더 이상 접근할 수 없게 될 것으로 예상하는 것이 일반적이다.

 

 

 

 

하지만 위의 예시와 자바스크립트의 경우는 다르다.

그 이유는 자바스크립트는 함수를 리턴하고, 리턴하는 함수가 클로저를 형성하기 때문이다. 클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.

 

 

 

 

 

첫 번째 예시의 경우, myFunc은 makeFunc이 실행 될 때 생성된 displayName 함수의 인스턴스에 대한 참조다. 

v   call by reference

     call by value

 

 

 

 

displayName의 인스턴스는 변수 name 이 있는 어휘적 환경에 대한 참조를 유지한다. 이런 이유로 myFunc가 호출될 때 변수 name은 사용할 수 있는 상태로 남게 되고 "Mozilla" 가 alert 에 전달된다.

 

 

 

 

 

 

 

 

    function makeAdder(x) {
      var y = 1;
      return function(z) {
        y = 100;
        return x + y + z;
      };
    }

    var add5 = makeAdder(5);
    var add10 = makeAdder(10);
    //클로저에 x와 y의 환경이 저장됨

    console.log(add5(2));  // 107 (x:5 + y:100 + z:2)
    console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
    //함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산

 

이 예제에서 단일 인자 x를 받아서 새 함수를 반환하는 함수 makeAdder(x)를 정의했다. 반환되는 함수는 단일인자 z를 받아서 x와 y와 z의 합을 반환한다.

 

 

 

본질적으로 makeAdder는 함수를 만들어내는 공장이다. 이는 makeAdder함수가 특정한 값을 인자로 가질 수 있는 함수들을 리턴한다는 것을 의미한다. 위의 예제에서 add5, add10 두 개의 새로운 함수들을 만들기 위해 makeAdder함수 공장을 사용했다. 하나는 매개변수 x에 5를 더하고 다른 하나는 매개변수 x에 10을 더한다.

 

 

 

 

add5와 add10은 둘 다 클로저이다.

 

 

이들은 같은 함수 본문 정의를 공유하지만 서로 다른 맥락(어휘)적 환경을 저장한다.

 

 

 

함수 실행 시 add5의 맥락적 환경에서 클로저 내부의 x는 5 이지만 add10의 맥락적 환경에서 x는 10이다.

 

 

 

 

또한 리턴되는 함수에서 초기값이 1로 할당된 y에 접근하여 y값을 100으로 변경한 것을 볼 수 있다. (물론 x값도 동일하게 변경 가능하다.) 이는 클로저가 리턴된 후에도 외부함수의 변수들에 접근 가능하다는 것을 보여주는 포인트이며 클로저에 단순히 값 형태로 전달되는것이 아니라는 것을 의미한다.

 

 

 

 

 

 

우리 회사는 클로저를 많이 사용한다.

클래스를 쓰지 않고 클로저 써라.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

호이스팅

자바스크립트는 컴파일러 언어이다.

 

호이스팅은 컴파일러 될 때 실행됨 ->  아래에 있는 변수나 함수들이 위로 끌어져 올라와서 실행됨

자바스크립트 호이스팅에서 발생되는 문제들이 있다.

 

 

참고: 반대로 c 는 먼저 변수나 함수가 먼저 선언되는 것을 볼 수 있었다.

 

 

 

var, function 은 호이스팅 된다. (let const 는 안됨)

 

 

 

 

console.log(myFun2)          // 안됨. 호이스팅이 안되니까

function myFun1 {            // 이건 호이스팅 됨
	return 'foo';
}



const myFun2 = function(){
	return 'foo1'
}

 

 

 

function 은 호이스팅이 되지만 const 는 안되는 것을 볼 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

this

함수를 호출한 방법에 의해 결정된다.

this 는 나 라고 생각하면 쉽다.

 

바깥에서 실행시키면 this 는 window 임

 

// 웹 브라우저에서는 window 객체가 전역 객체
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"

 

 

 

 

 

 

 

 

this 함수를 호출한 주체가 누구인지에 따라 값이 달라진다

 

 

const dyki: any = {
  leftPocket: "캔디",
  rightPocket: "립스틱",
  getRight() { return this.rightPocket },
  getLeft() { return this.leftPocket }
}

// 다영님의 오른쪽 주머니 립스틱을 얻는데 성공
console.log(dyki.getRight())



// 기다영 "오른쪽 주머니 얻기" 함수를 변수화
// 실패
const getRight = dyki.getRight;
console.log(getRight())   // undefined 를 반환한다

 

 

 

 

 

const sihyun: any = {
  leftPocket: "핸드폰",
  rightPocket: "초콜릿",
}

const getRight = dyki.getRight;

// 현신일 "오른쪽 주머니 얻기" 함수에 기다영 "오른쪽 주머니 얻기"를 주입
sihyun.getRight = getRight;

// not closes
console.log(sihyun.getRight())    // 초콜릿

// // 함수 바인딩
const getRightBinded = getRight.bind(dyki);

console.dir(getRightBinded)         // ƒ bound getRight()

// 현신일 "오른쪽 주머니 얻기" 함수에 기다영 바인드된 "오른쪽 주머니 얻기"를 주입
sihyun.getRight = getRightBinded;

// closes: bounded function
console.log(sihyun.getRight())      // 립스틱

console.dir(sihyun)


/*
{
  leftPocket: '핸드폰',
  rightPocket: '초콜릿',
  getRight: ƒ bound getRight()
}
*/

 

 

 

 

 

< bind 메서드 >

this는 자바스크립트에서 조금 골치아픈 존재이다.

그리고 경우에 따라서 this는 획획 바뀔 수 있다. 그렇기 때문에 this를 고정시키는 방법이 존재한다.

이를 this 바인딩이라고 한다.

 

 

ECMAScript 5 는 Function.prototype.bind 를 도입했다.

 

 

f.bind(someObject)를 호출하면 f와 같은 본문(코드)과 범위를 가졌지만 this는 원본 함수를 가진 새로운 함수를 생성합니다. 새 함수의 this는 호출 방식과 상관없이 영구적으로 bind()의 첫 번째 매개변수로 고정됩니다.

 

 

 

 

 

function sum(num) {
    return num + this.num1 + this.num2;
}

var myObj = {num1:20, num2: 3};

var customSum = sum.bind(myObj);

console.log(customSum(5));

 

여러분은 어떠한 함수이건(그게 메소드라 할지라도) bind라는 함수를 사용할 수 있다.

즉 function object는 모두 bind를 사용할 수 있다는 것이다.

bind함수를 사용하면 this는 내가 정한 object로 고정된다.

그전에 만약 bind가 되있다면 그 bind를 무시하고 object를 고정하게 된다.

따라서 위는 어떠한 환경이던 this는 myObj가 되므로 확정된 결과를 보여줄 수 있게 된다.

 

 

 

 

 

 

 

 

 

 

 

 

async / await

 

function hello() {
  return new Promise((resolve, reject) => {
    setTimeout(async () => {
      resolve("world")
    }, 1000)
  })
};


async function myFunc() {
  const result = await hello();
  console.log(result);     // world
}

myFunc();   // Promise { <pending> }

 

 

 

 

Promise는 다음 중 하나의 상태를 가집니다.

  • 대기(pending): 이행하지도, 거부하지도 않은 초기 상태.
  • 이행(fulfilled): 연산이 성공적으로 완료됨.
  • 거부(rejected): 연산이 실패함.

 

 

 

 

 

 

 

 

 

 

 

callback

함수를 인자로 받아 함수에서 특정 조건에서 실행시키는 함수

 

참고로 자바스크립트에서 함수는 일급 객체이다.

 

type Callback = {
  (result: number): void;
}

function lazyAdd(a: number, b: number, callback: Callback) {
  setTimeout(() => {
    callback(a + b)
  }, 1000)
}

lazyAdd(1, 2, (result) => {
  console.log(result)
})

 

 

 

 

 

 

promise

 

   
type Callback = {
  (error: Error | null, result: number): void;
}

function lazyAdd(a: number, b: number, callback: Callback) {
  setTimeout(() => {
    callback(null, a + b)
  }, 1000)
}

function lazyAddPromise(a: number, b: number): Promise<number> {
  return new Promise((resolve, reject) => {
    lazyAdd(a, b, (err, data) => {
      if (err) return reject(err);
      return resolve(data);
    })
  })
}

lazyAddPromise(1, 2).then(console.log)

 

콜백 함수

프로미스가 나오기 전에 콜백함수 많이 썼다.

-> 콜백 지옥

 

 

 

콜백 예전의 규칙

첫번째는 에러, 두번째는 데이터

 

 

프라미스 혁명

프라미스와 then catch   해결할 있다.

 

 

 

 

 

 

 

 

 

 

함수형 프로그래밍 functional programming

객체지향의 반대 라고 보면 된다.

 

  • 입출력이 순수해야함 (Pure JavaScript function)
  • 부작용(side effects)이 없어야 함: 원본 데이터는 불변 해야함.
  • 함수와 데이터를 중심으로 사고

 

 

 

 

 

1. Functional programming 의 장점

  • 부작용이 적음
  • 코드의 재사용성이 높아 짐
  • JavaScript 언의 지향점: 객체지향 => 함수형
  • 테스트의 용이 ⭐️

 

 

2. < 쓰지 말 것 >

 

  • 반복문
    • while
    • do ... while
    • for
    • for ... of
    • for ... in
  • var or let 변수선언 ( let 도 지양하자 )
  • void 함수
  • 객체 뮤테이션: ex) o.x = 5;
  • 배열 변경 메서드: 원본 배열을 변경 시키는 매서드
    • copyWithin
    • fill
    • pop
    • push
    • reverse
    • shift
    • sort
    • splice
    • unshift
  • Map mutator 매서드
    • clear
    • delete
    • set
  • Set mutator 매서드
    • add
    • clear
    • delete

 

 

 

 

 

객체 뮤테이션은 하지 말자!!!!!!!!!!!! 부모 바꿔주는건 지양 o.x = 5 같은..

 

splice 는 부모의 값을 바꿔줌. 이런거 쓰지 말기

slice 는 새로운 객체를 반환. 이걸 쓰자. 이거는 원본을 남겨두는 것!!!!

 

push 지양. 이것도 원본 배열을 바꿈

 

 

 

 

 

3. for 문 대신 재귀함수 사용.

 

function iterativeAdder(iter: number) {
 let value = 0;
 for (let i = 1; i <= iter; i++) {
   value += i;
 }
 return value;
};

console.log("== iterative add", iterativeAdder(10))


function recursiveAdder(iter: number): number {
  if (iter === 0) return 0;
  return iter + recursiveAdder(iter - 1)
}

console.log("== recursive add", recursiveAdder(10))

 

 

 

 

 

 

 

 

4. 고차함수는 몰라도

 

 

 

 

 

'👩🏻‍💻 TIL' 카테고리의 다른 글

Git 기초부터 브랜치까지  (0) 2022.03.20
Express / middleware / router  (0) 2022.03.17
프리즈마, 그래프큐엘의 yarn codegen  (0) 2022.02.21
2022_02_09_TIL  (0) 2022.02.10
기업협업에서 배운 것 정리  (0) 2022.01.17