[러버덕3]



1. 순수함수 vs 비순수함수는 외부환경, 매개변수, 인자의 영향을 받나?

순수함수와 비순수함수

  • 순수 함수는 어떤 외부 상태에도 의존하지 않으며 외부 상태를 변경하지도 않는 함수
  • 비순수함수는 외부 상태에 의존하거나 외부 상태를 변경하는 함수


인자로 값이 들어오는 경우

인자로 원시값이 들어오는 경우

var num = 0;

function fn(n) {
  return ++n;
}

let result = fn(num);
console.log(num, result); //0, 1
// 외부에 영향 미치지 않음 > 순수함수


인자로 객체가 들어오는 경우

var arr = [1, 2, 3];

function fn(arr) {
  arr[0] = 4;
  return arr;
}

let result = fn(arr);
console.log(arr, result); //[ 4, 2, 3 ] [ 4, 2, 3 ]
// 외부에 영향 미침 > 비순수함수


인자로 값이 들어오지 않는 경우

매개변수 x && 상위 스코프의 원자값 사용하는 경우

var num = 0;

function fn() {
  return ++num;
}

let result = fn();
console.log(num, result); //1, 1
// 외부에 영향 미침 > 비순수함수


매개변수 x && 상위 스코프의 객체 사용하는 경우

var arr = [1, 2, 3];

function fn() {
  arr[0] = 4;
  return arr;
}

let result = fn();
console.log(arr, result); //[ 4, 2, 3 ] [ 4, 2, 3 ]
// 외부에 영향 미침 > 비순수함수


상위 스코프에 같은 이름을 가진 변수가 없다면?

var number = 0;

function fn() {
  return ++num;
}

let result = fn();
console.log(number, result); 
//ReferenceError: num is not defined
var array = [1, 2, 3];

function fn() {
  arr[0] = 4;
  return arr;
}

let result = fn();
console.log(array, result); 
//ReferenceError: arr is not defined


매개변수 o && 인자값 없는 경우

var num = 0;

function fn(n) {
  return ++n;
}

let result = fn();
console.log(num, result); //0 NaN
var array = [1, 2, 3];

function fn(arr) {
  console.log(arr); //undefined
  arr[0] = 4;
  return arr;
}

let result = fn();
console.log(array, result);
//TypeError: Cannot set property '0' of undefined


매개변수 o && 인자값 x && 변수 이름도 다른 경우

var num = 0;

function fn(num) {
  return ++num;
}

let result = fn();
console.log(num, result); //0 NaN
var array = [1, 2, 3];

function fn(array) {
  array[0] = 4;
  return array;
}

let result = fn();
console.log(array, result);
//TypeError: Cannot set property '0' of undefined
  • 상위 스코프의 변수를 쓰는 것이 아닌 함수 스코프에서 매개변수를 선언한다.


모든게 동일한 함수가 외부 조건이 다른 경우, 순수 함수/비순수함수로 다르게 동작할 수 있을까?

var num = 0;

function fn() {
  return ++num;
}

let result = fn();
console.log(num, result); //1, 1
// 외부에 영향 미침 > 비순수함수
var number = 0;

function fn() {
  return ++num;
}

let result = fn();
console.log(number, result); 
//ReferenceError: num is not defined
  • 상위 스코프에 동일한 이름의 식별자가 있는 경우 > 비순수함수
  • 상위 스코프에 동일한 이름의 식별자가 있는 경우 > 에러
var num = 0;

function fn(n) {
  return ++n;
}

let result = fn(num);
console.log(num, result); //0, 1
var num = 0;

function fn(n) {
  return ++n;
}

let result = fn();
console.log(num, result); //0 NaN
  • 둘다 순수함수


결국 내가 헷갈렸던건?

  • 순수함수, 비순수함수의 차이(부수효과 유무) 이전에
  • 하위 스코프에서 변수 탐색시, 없으면 상위 스코프로 가서 동일한 이름의 식별자를 찾아 가져온다는 것.
  • 매개변수가 있는 경우 해당 스코프 진입시, 가장 먼저 매개변수가 호이스팅되어 선언되는 것.
    • 상위 스코프에 동일한 이름의 식별자가 있더라도 관련 x



2. js의 oop를 이해하기 위해 java를 기반으로 생각하지 말자.

  • 자바는 class 기반 oop
  • js 는 prototype 기반 oop
  • js는 모든게 public하다. 그럼 정보은닉 어떻게 해?
    • 클로져 사용 (상태를 안전하게 유지하고 변경하기 위해)
    • 일부 구현 가능하나 완전하게는 못한다.
    • 그래서 나온 시도. js를 java처럼 쓰자.
    • 하지만 이 방법은 js를 잘 활용하지 못하는 방법
  • 그럼 객체지향은 좋은거야?
    • 은탄환은 없다.
    • 프로그램 패러다임 : 명령형, 클래스, 함수형…
    • 한 패러다임에 종속되지 말자
    • 나는 좋은 코드를 위해 패러다임을 사용할 뿐이다. (패러다임에 끌려다니면 안돼!)
  • js는 멀티 패러다임 언어로, 그때 그때 트랜드가 다르지만 지금은 함수형!



3. 엄격한 js 사용하기

  • use strict 보다는 ESLint 활용하기
  • aribnb가 엄격하게 사용하니 우리도 활용하자.



4. 내가 할 수 있는 클린코드

  • 변수명 잘 짓기 (알고리즘 짤 때 함수명 solution 말고 고민하는 습관 들이기)
  • 중복 제거하기
  • 함수의 기능 쪼개기 (SRP)
    • 이름 짓기 어렵다면? 여러 기능 하고 있을 가능성 크다
    • if문이 많다면? 쪼개야한다.
  • 코드는 성의다!



5. 에러가 난다면?

  • 에러가 났다는 사실만 알고 지나치지 말자
  • 에러메세지를 통해 원인을 파악하는 습관
  • 내가 자주 마주칠 수 있는 에러
    • SyntexError
    • ReferenceError
    • TypeError



6. 함수선언문보다 함수 표현식 사용하자

  • 더 엄격하기 때문(함수 호이스팅 관점)
  • 클린코드에 더 가까운 함수 표현식은 함수의 이름을 짓지 않는 것
  • const add = function(a, b) {}



7. 생성자 함수를 즉시실행 함수에 담아서 변수에 할당하여 사용하는 이유가 무엇인지?

  • 모듈 패턴을 구현한 것
    • 왜?
    • 캡슐화 하려고. (클로져에서 더 깊이 다루자)
    • 비슷한 기능을 하는 아이들끼리 묶으려고. for 응집도 up
    • 때때로 가독성을 높이기 위해 불필요한 코드가 추가되기도 한다. > 이 경우
    • 오로지 응집도 높이려고 사용된 경우다.
    • 중간에 코드 100개있으면 헷갈리니까!



8. 객체의 프로퍼티는 또 객체다.

  • js 는 객체의 프로퍼티에 대해 또 객체를 가지고 있다. (프로퍼티 어트리뷰트)
  • js 엔진은 인터프리터에 코드를 입력만 해준다. 그 코드를 해석하고 동작시키는 건 인터프리터
    • 그 동작의 과정을 정한게 ECMAScript



9. 함수는 일급 객체다.

  • 일급 객체의 조건 기억해두기
  • 함수가 일급객체라는건 그 언어가 함수형 언어라는 것.



10. 매개변수는 var 키워드로 선언한 변수와 같이 행동한다.



11. 중첩함수 왜 쓸까?

  • 콜백함수도 중첩함수 중 하나.
  • 해당 함수를 재사용하기 위해서.
  • 함수의 일을 나누기 위해 (단일책임원칙)
  • 왜 외부에서 안하고 내부에서 해?
    • 내부에서만 사용하기 때문에. 외부에서도 사용해야한다면 외부에서 선언해야해!



12. 속성은 어트리뷰트야 프로퍼티야?

  • 둘다 번역은 맞아. 그래서 그냥 속성이란 단어를 쓰지말자.
  • html - 어트리뷰트
  • css - 프로퍼티
  • js - 객체의 프로퍼티
    • 프로퍼티는 어트리뷰트를 갖는다.
    • 근데 이 어트리뷰트는 js엔진이 사용해
    • 개발자는 알 필요가 없지. 그래서 감춰져있다.
    • 개발자가 알 필요가 있는건 간접적으로 접근할 수 있게 해준다
    • __proto__, getOwnPropertyDiscriptor



13. 접근자 프로퍼티는 함수가 아니다!

const o = {
  _name: "jo",
  get name() {
    return this._name;
  },
  set name(name) {
    this._name = name;
  },
};

// getter, setter 역할을 하는 것
// _변수명은 밖에서 public 으로 사용하지 말라는 의미야
o.name = "hyun";
console.log(o.name); //hyun

// 이렇게 직접 바꾸지 말라는 것!!
// 이걸 방지하려면 [[Readable]] : false 만들면 된다.
o._name = "rang";
console.log(o.name); //rang
  • 왜 접근자 프로퍼티 사용할까?
    • 데이터 프로퍼티는 값이 들어오면 무조건 그 값으로 할당되어야해(검사없이)
    • 접근자 프로퍼티는 값을 할당하기 전, 함수 한번 돌려서 유효성 검사 등의 체크를 할 수 있어
    • 입력된 값을 변환하고 저장해야한다면? 접근자 프로퍼티 사용하면 좋다.



14. 함수 객체 vs 함수 구분하자

const f = function(){
    const x = 1
    return {}
}

console.log(f) //[Function: f]
 // 함수를 호출하는 건 아니다. 호출은 f()
  • function()은 함수 리터럴로 평가되서 함수 객체를 만든다.
    • 함수 객체는 프로퍼티 5개(length, name, arguments, caller, prototype) 갖고있는 객체일뿐 실제 저 함수의 코드 블록 내부 문을 갖고 있는 것이 아니다.
  • const f가 선언되고 f 의 값으로 함수객체가 있는 것. 이때까지는 함수의 코드블록 내부 문들은 모른다.
  • f() 함수 호출문을 만나면 f 객체 찾고 > f.[[Call]] 내부에서 저 함수가 호출되는 것 (그제서야 내부 문들 실행)
    • 소프트웨어는 값을 미리 만들지 않는다 > lazy 하게 만든다.
    • 함수를 호출하기 전까지는 실제로 만들지 않음
      • 왜? 그 함수를 호출 안할수도 있는데 미리 만드는건 불필요
  • 함수 객체가 생성되는 시점과 함수 실행 시점은 다르다.



15. 생성자 함수가 내부적으로 동작하는 방식

function Person(name) {
  // 내부적으로
  // this={} 빈 객체 만들어서 this에 바인딩 (this = Person)
  console.log(this); //Person {}

  this.name = name;

  // this에 name 파라미터 동적 할당.
  console.log(this); //Person { name: 'Jo' }

  this.sayhello = function () {
    console.log("hello");
  };

  // return this
}

person1 = new Person("Jo");
console.log(person1);
//Person { name: 'Jo', sayhello: [Function (anonymous)] }
  • 빈 객체 만들어서 this에 바인딩
  • 빈 객체에 동적으로 프로퍼티 추가
  • return this



16. this 바인딩은 어떻게?

const f = function () {
    console.log(this)
}

// 이건 일반함수 일까, 생성자 함수일까?
// 아직 모른다 > 함수의 종류는 함수가 호출될 때 정해진다.
// js는 함수의 호출 방식을 보고 this binding을 결정한다. (동적으로)

// 1. 일반 함수
f() //global > 전역변수

// 2. 생성자 함수
let instance = new f() //f {} > 생성자함수

//3. 메소드
const o = {f}
o.f() //메소드를 호출한 o를 가리킨다.