https://github.com/jihazard/TIL/blob/master/MD/ReplaceNEstedConditonalwithGuardClauses/ReplaceNestedConditionalwithGuardClauses.md

##여러겹의 조건문을 감시절로 변환

* 메서드에 조건문이 있어서 정상적인 실행 경로를 파악하기 힘들 땐 모든 특수한 경우에 감시 절을 사용하자.

조건절 두가지 형태

  1. 어느 경로가 정상적인 동작의 일부인지 검사하는 형태

  2. 조건판별의 한 결과만 정상적인 동작을 나태내고 나머지는 비정상적인 동작을 나타내는 형태

    조건문에는 다양한 의도가 있는데 그 의도가 코드에 반영되어 들어나야 한다.
    조건문이 특이한 조건이라면 그 조건을 검사해서 조건이 true일 경우 반환하자
    이런식의 검사를 감시절이라고 한다 (guard clause)

    * 조건문이 복잡해서 실행경로를 알수없는 코드 예제

~~~
double getPayAmount() {
double result;
if(_isDead) result = deadAmount();
else {
if(_isRetired) result = sepratedAmount();
else {
result = normalPayAmount();
}

    }  
    return result;  
}  

  \* 감시절을 이용하여 변경한 예제  
\~~~  
    double getPayAmount() {  
        if(\_isDead) result deadAmount();  
        if(~isSeparated) return sepratedAmount();  
        if(\_isRetired) return retiredAmount();  
        return normalPayAmount();  

    }  

* 조건문을 역순으로 만들기 위한 예제

    public double getAdjustedCapital() {  
        double result = 0.0;  
        if(\_capital > 0.0) {  
            if(\_intRate > 0.0 && \_duration > 0.0) {  
                result = (\_income / \_duration) \* ADJ\_fACTOR;  
            }  
        }  
        return result;  
    }  

* 역순 조건문을 감시절을 이용해 변경하기

    public double getAdjustedCapital() {  
        if(\_capital > 0.0) return 0.0;  
        if(\_intRate > 0.0 || \_duration > 0.0) return 0.0;  
        return (\_income / \_duration) \* ADJ\_fACTOR;  
    }  

https://github.com/jihazard/TIL/blob/master/MD/removeControlFlag/RemoveControlFlag.md

 

 

## Remove Control Flag  조건문 간결화

* 논리연산식의 제어플래그 역할을 하는 변수가 있을 경우 그변수를 break 나 return 문으로 변경하자.

제어 플레그 예제 

~~~
    void checkSecurity(String [] people) {
        boolean found = false   // 제어플래그
        
        for(int i = 0; i < people.length ; i++){
            if(!found) {
            if(people[i].equals("don"){
                sendAlert():
                found = true;
                }
            if(people[i].equals("john"){
                sendAlert():
                found = true;
             }
                           
            }
        }
    }

~~~~
* 제어플래그 선언부 found를 삭제하고 분기문의 제어플래그 부분을 break 로 변경하자


~~~~
    void checkSecurity(String [] people) {
        for(int i = 0; i < people.length ; i++){
            if(!found) {
            if(people[i].equals("don"){
                sendAlert():
                break;
                }
            if(people[i].equals("john"){
                sendAlert():
                break;
             }
                           
            }
        }
    }

~~~~

* 제어 플래그를 return 문으로 교체 

~~~~
    void checkSecurity(String [] people) {
        boolean found = "";   // 제어플래그
        
        for(int i = 0; i < people.length ; i++){
            if(found.equals("")) {
            if(people[i].equals("don"){
                sendAlert():
                found = "don";
                }
            if(people[i].equals("john"){
                sendAlert():
                found = "john";
             }  
            }
        }
    someLaterCode(found);  
    }

~~~~

- 이번예제의 경우 플래그 기능과 리턴결과를 나타내는 역할을 한다 이럴 때 found변수를 알아내는 코드를 
  메서드로 빼내자.
  
  
  ~~~~
      void checkSecurity(String [] people) {
         String found = foundMiscreant(people);
         someLaterCode(found);
         }
         
         String foundMiscreant(String[] people){
         for(int i = 0; i < people.length ; i++){
                     if(found.equals("")) {
                     if(people[i].equals("don"){
                         sendAlert():
                         return "don";
                         }
                     if(people[i].equals("john"){
                         sendAlert():
                         return "john";
                      }  
                     }
                 }
             return "";
           }
         }
  ~~~~

컴포넌트 스캔의 주요 기능

               ●스캔 위치 설정

               ●필터: 어떤 어노테이션을 스캔할지 또는 하지 않을지 설정

 

스프링 부트 기준으로 @SpringBootApplication 어노테이션 안에 @ComponentScan을 가지고 있기 때문에

@SpringBootApplication를 등록한 메인 클래스가 포함한 패키지부터 이하의 모든 패키지를 스캔해줌

 

@ComponentScan 이 모든 객체를 빈으로 등록해주는 것은 아님

excludeFilter를 통해 걸러낼 수 있음

@ComponentScan에는 어디부터 어떻게 스캔할 것인지와 어느 것을 걸러낼 것인지 필터 해주는 속성이 존재하고

아래 어노테이션이 모두  빈으로 등록됨

 

@ComponentScan 대상들

    @Repository

    @Service

    @Controller

    @Configuration

 

동작원리

@ComponentScan은 실제 스캐닝은 ConfigrationClassPostProcess라는 BeanFactoryPostProcessor에 의해 처리됨

 

 

기본 프로젝트 구조

 

bookService 는 bookRepository를 주입하고 외부에서 의존성을 주입받을 수 있도록 setter를 만든다

 

빈설정 방법 1 : bean 을 xml에 직접 등록

bean 을 설정해주는 application.xml을 생성 후 빈을 등록한다.

resouces폴더에 springconfig 파일형태로 application.xml파일을 생성 후 빈을 등록한다. 매우 고전적인 방법

BookService 와 BookRepository를 빈으로 등록 service에서는 repository를 property로 넣어 의존성을 추가할 수 있도록 등록해줌

이제 빈이 등록 됐는지 꺼내서 확인 해보자.

실행결과

결과값 정상

이렇게 할 경우 매번 빈을 등록해줘야 하기 때문에 매우매우매우 번거롭고 귀찮다.

그래서 스프링 2.5부터 나온 방식은 컴포넌트 스캔을 이용한 방식

 

빈설정 방법 2 : 컴포넌트 스캔component-scan 을 이용한 방식

application.xml 설정파일에 component-scan 을 정의해보자 정의 방식

base-package= "여기서 부터 하위를 모두 스캐닝해서 빈으로 등록하겠다는 뜻"

스캐닝할 때는 기본적으로 @Service ,@Repository를 빈으로 등록하고 저 두가지 어노테이션은 @Component를 확장하고 의존성 주입을 할때는 @Autowired를 이용하여 주입이 가능함

 

1번 방식과는 다르게component-scan을 사용하면 어노테이션을 추가해야함!

결과실행 시 잘 됨

여기서 한단계 더 나아가 xml이 아닌 자바 파일에 빈 설정파일을 만들기

 

빈설정 방법 3 : ApplicationConfig.java 자바파일로 빈설정하기

ApplicationConfig.java를 생성 후  @Configuration어노테이션으로 설정파일로 설정 후 @Bean어노테이션을 이용해 빈으로 직접 등록

 

               위의 경우 @Autowired 어노테이션이 필요하지 않다. 의존성 주입까지 모두 처리했기 때문에

그래서 모든 어노테이션 없이 결과를 실행해도 결과값이 true가 나온다.

          

결과값 확인

추가로 bookservice 에서 의존성을 주입하지 않고 바로 객체를 반환할 경우에는

 

    BookService에서 @Autowired 어노테이션을 추가하면 정상적으로 사용이 가능하다.

 

@Autowired가 없을 경우 객체를 주입받지 못해 테스트 할 경우 false를 출력한다.

 

그런데 말입니다

빈을 일일이 등록하는게 귀찮다. 그래서 사용하는게 @ComponentScan

 

빈설정 방법 4 : ApplicationConfig.java 자바파일안에서 @ComponentScan 으로 빈 자동등록하기

 

@ComponentScan(basePackageClasses = DemoApplication.class) //DemoApplication.class 가 위치한곳부터

컴포넌트 스캐닝을 하라는 의미
@ComponentScan(basePackages = "test.ok.spring.demo" ) //해당 패키지를 스캐닝 하라는 의미

 

스캐닝을 하기위해서는 기본적으로 @Service @Repository어노테이션이 있어야함

 

 

그러나 ApplicationContext를 만들고 지지고 볶고하는 것은 테스트를 위함이고 스프링 부트 기준으로 main함수가 있는 Application.java파일에 @SpringBootApplication이 있다면 위의 모든 일을 처리해줌

 

인프런 백기선님 강좌보면서 정리함

 

 

 

 

 

 

IOC( Inversion of Control)

                                                 제어권의 역전

IOC란?

  • 제어권이 역전된 것을 Ioc라고 함

일반적으로 본인이 사용할 의존성은 아래와 같이 본인이 생성함  

class OwnerController {
  private final OwnerRepository owners; = new OwnerRepository ();


그러나 여기서 본인인 OwnerController 가 직접관리하는게 아니라 아래와 같이

생성자를 통해 외부에서 객체를 만들어 주입하는것

의존성을 만드는 것은 더이상 OwnerController 가 아니라 외부에서 가능하게 하는것을

제어권이 역전이라고 함


class OwnerController {
  private final OwnerRepository owners;


  //IOC
  public OwnerController(OwnerRepository clinicService) {  //의존성 주입(DI)
      this.owners = clinicService;
  }




IOC 컨테이너란?

ApplicatioContext(BeanFactory) 둘중 하나를 사용 하는데 ApplicationContext는       BeanFactory 를 상속하기 때문에 더 다양한 일을 할 수 있음

  • 빈(bean)을 만들고 의존성을 엮어주고 제공해주는게 IOC컨테이너

모든 객체가 빈으로 등록되는 것은 아님

등록 조건

  1. 특정 어노테이션을 쓰거나 인터페이스를 상속

@Controller @Service 등등

   2. 직접 @Bean어노테이션을 이용하여 등록

@Bean
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
return cm -> {
cm.createCache("vets", cacheConfiguration());
};

위방법으로 등록된 빈들은 서로간의 의존성 주입을 ioc컨테이너가 해줌

  //IOC
  public OwnerController(OwnerRepository clinicService) {  //의존성 주입(DI)
      this.owners = clinicService;
  }

의존성 주입은 ioc컨테이너 안에 있는 빈들끼리만 서로 해주는것을 원칙으로 함


  • ApplicationContext를 이용하여 저장된 bean 확인

@Autowired
ApplicationContext applicationContext;

@Test
public void getBean(){
  OwnerController bean = applicationContext.getBean(OwnerController.class);
  assertThat(bean).isNotNull();

}


  • 실제 의존성 주입받은 객체 owners와 ApplicationContext를 이용해 호출한 객체가 동일한 객체인지 확인


@Controller
class OwnerController {

  private final OwnerRepository owners;
  private final ApplicationContext applicationContext;


  public OwnerController(OwnerRepository clinicService

                       , ApplicationContext applicationContext) {
      this.owners = clinicService;
      this.applicationContext=applicationContext;
  }

  @GetMapping("/bean")
  @ResponseBody
  public String bean(){
      return "bean :" + applicationContext.getBean(OwnerRepository.class) + "\n"
           + "owner 객체 : " + this.owners;
  }


결과

org.springframework.data.jpa.repository.support.SimpleJpaRepository@3e6a72 org.springframework.data.jpa.repository.support.SimpleJpaRepository@3e6a72



백기선님의 강좌를 보고 정리했슴돠 백기선님 짱



리팩토링

메서드정리

  • 리팩토링의 주된 작업은 코드를 포장하는 메서드를 적절히 정리하는 것.

장황한 메서드에 많은 정보가 들어가는데 마구 얽힌 복잡한 로직들에 정보가 묻힌다.핵심적인 리펙토링 기법은 메서드 추출과 메서드 삽입이 있다.

메서드 추출에서 가장 어려운 작업은 지역변수를 처리하는 것인데 그것은 주로 임시 변수 때문이다.

임시변수를 메서드 호출로 전환을 실시해서 없어도 되는 임시변수는 전부 제거

메서드 추출 (extract Method)

  • 어떤코드를 그룹으로 묶어도 되겠다고 판단될 땐 그 코드를 빼내어 목적을 잘 나타내는 직관적 이름의 메서드로 만들자.

void printOwing(double mount){
  printBanana();

  System.out.println("name " + _name);
  System.out.println("mount " + mount);
}

리팩토링

void printOwing(double mount){
  printBanana();
  printDetail(mount);
}

private void printDetail(double mount) {
  System.out.println("name " + _name);
  System.out.println("mount " + mount);
}


  • 동기

    • 메서드 코드가 너무길거나 코드에 주석을 달아야 의도를 이해할 수 있을 때 사용함

    • 직관적 이름의 간결한 메서드가 좋은 이유   
      1.메서드가 잘게 쪼개져 있을 경우 다른메서드에서 사용하기 쉽다.
      2.상위 계층의 메서드에서 주석같은 더 많은 정보를 읽을수 있다
      3.재정의 하기 훨씬 수월하다.


  • 방법

    • 목적에 부합하는 이름의 새 메서드를 생성하자. 이때 메서드명은 원리가 아니라
      기능을 나타내는 이름으로 해야좋다.

    • 기존의 메서드에서 빼낸 코드를 새로 생성한 메서드로 복사하자.

    • 빼낸 코드에서 기존 메서드의 모든 지역변수 참조를 찾자 그것들을 새로 생성한 메서드의 지역변수나 매개변수로 사용

    • 빼낸 코드에서 읽어들인 지역변수를 대상 메서드에 매개변수로 전달한다.

    • 모든 지역변수 처리를 완료했으면 컴파일을 실시하자.

  


  • 예제 : 지역변수 사용안함

void printOwing(){
  Enumeration e = _orders.elements();
  double outstanding = 0.0;

  System.out.println("----------------------");
  System.out.println("---------고객외상-------");
  System.out.println("----------------------");
 
  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  }

  System.out.println("고객명 : " + _name);
  System.out.println("외상액 : " + outstanding);
 
}


    • 위의 코드중 배너 관련 코드를  아래와 같이 리팩토링 할 수 있다


void printOwing(){
  Enumeration e = _orders.elements();
  double outstanding = 0.0;

  printBaner();

  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  }

  System.out.println("고객명 : " + _name);
  System.out.println("외상액 : " + outstanding);

}

private void printBaner() {
  System.out.println("----------------------");
  System.out.println("---------고객외상-------");
  System.out.println("----------------------");
}

  • 예제 : 지역변수 사용

void printOwing(){
  Enumeration e = _orders.elements();
  double outstanding = 0.0;

  printBaner();

  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  }

  System.out.println("고객명 : " + _name);
  System.out.println("외상액 : " + outstanding);

}


    • 위 코드 중 세부내역 출력코드를 하나의 매개변수를 받는 메서드로 리팩토링 가능.


void printOwing(){
  Enumeration e = _orders.elements();
  double outstanding = 0.0;

  printBaner();

  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  }

  printDetails(outstanding);

}

private void printDetails(double outstanding) {
  System.out.println("고객명 : " + _name);
  System.out.println("외상액 : " + outstanding);
}


  • 예제: 지역변수를 다시 대입하기

void printOwing(){
  Enumeration e = _orders.elements();
  double outstanding = 0.0;
  printBaner();
  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  }
  printDetails(outstanding);
}

    • 계산부분을 아래와 같이 리팩토링 할 수 있음.

void printOwing(){
  printBaner();
  double outstanding = getOutstanding();
  printDetails(outstanding);
}
private double getOutstanding() {
  Enumeration e = _orders.elements();
  double outstanding = 0.0;
  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      outstanding += each.getAmout();
  } return outstanding;
}

    • 열거형 e 변수는 빼낸 코드에서만 사용되므로 새메서드로 아예 옮겨도 된다.
      메서드를 컴파일하고 테스트 했으면 언제나 처럼 반환값의 이름을 변경하자..


void printOwing(){
  printBaner();
  double result = getOutstanding();
  printDetails(outstanding);
}
private double getOutstanding() {
  Enumeration e = _orders.elements();
  double outstanding = 0.0;
  while(e.hasMoreElements()){
      Order each = (Order) e.nextElement();
      result += each.getAmout();
  } return result;
}

    • 변수를 두개 이상 반환해야 할때는 변수를 반환하는 각각의 메서드를 2개 만드는게
      최선의 방법이다.


메서드 내용 직접 삽입 (inline Method)

  • 메서드 기능이 너무 단순해서 메서드명만 봐도 너무 뻔할 땐 그 메서드의 기능을 호출하는 메서드에 넣고 그 메서드는 삭제하자

int getRating(){
  return (moreThanFiveLateDeliveries()) ?2:1;
}

private boolean moreThanFiveLateDeliveries() {
return _numberOfLateDeliveries > 5;
}

위의 코드를 아래와 같이 리팩토링 가능하다

int getRating(){
  return (_numberOfLateDeliveries > 5) ?2:1;
}


  • 동기

    • 메서드 기능이 지나치게 단순할 때는 메서드를 없애야 한다. 불필요한 인다이렉션은 장애물일 뿐이다.


  • 방법

    • 메서드가 재정의되어 있지 않은지 확인하자.

    • 메서드를 호출하는 부분을 모두 찾자.

    • 호출부분을 메서드 내용으로 교체하자.

    • 테스트를 하자.

    • 메서드 정의를 삭제하자.


임시변수 내용 직접 삽입 (inline Temp)

  • 간단한 수식을 대입받는 임시변수로 인해 다른 리팩토링 기법 적용이 힘들땐 그 임시변수를 참조하는 부분을 전부 수식으로 치환하자.

double bestPrice = anOrder.bestPrice();
return (bestPrice > 1000);

위의 코드를 아래와 같이 리팩토링 가능하다

return (anOrder.bestPrice() > 1000);


  • 동기

    • 임시변수가 메서드 추출등 다른 리팩토링에 방해가 된다면 임시변수 내용 직접삽입을
      적용해야함


  • 방법

    • 대입문의 우변에 문제가 없는지 확인

    • 문제가 없다면 임시변수를 final로 선언하고 컴파일하자.

    • 수정을 마칠때마다 컴파일과 테스트 하자.


임시변수 메서드 호출로 전환 (repalce Temp with Query)

  • 수식의 결과를 저장하는 임시변수가 있을 땐 그 수식을 빼내어 메서드로 만든 후 임시변수 참조부분을 전부 수식으로 교체  (다른메소드에서 호출가능)

double basePrice = _quantitiy * _itemPrice;
if (basePrice > 1000)
  return basePrice * 0.95;
else
  return basePrice * 0.98;

위의 코드를 아래와 같이 리팩토링 가능하다

public double test() {
 if (basePrice() > 1000)
      return basePrice() * 0.95;
   else
      return basePrice() * 0.98;
}
private double basePrice() {
  return _quantitiy * _itemPrice;
}


  • 동기

    • 임시변수는 일시적이고 적용이 국소적 범위로 제한된다는 단점이 있음 임시변수는 자신이 속한 메서드 안에서만 인식되므로 외부에서 접근하려면 코드가 길어짐 그래서 메서드호출로 전환하면 코드가 훨씬 깔끔해짐


  • 방법

    • 값이 한번만 대입되는 임시변수를 찾자.

    • 그 임시 변수를 final로 선언하자

    • 컴파일을 실시하자.

    • 대입문 우변을 빼내어 메서드로 만들자.

    • 컴파일과 테스트를 실시하자.

  • 예제

public double getPrice() {
   int basePrice =_quantitiy * _itemPrice;
   double discountFactor;
   if(basePrice > 1000) discountFactor = 0.95;
   else discountFactor = 0.98;
   return basePrice * discountFactor;
}

    • 아래와 같이 리팩토링 가능하다 임시변수를 메서드로 추출함으로써 직관적이고 깔끔한 코드가 완성됐다.


public double getPrice() {
  return basePrice() * discountFactor();
}

private int basePrice() {
  return _quantitiy * _itemPrice;
}

private double discountFactor() {
  if(basePrice() > 1000) return 0.95;
  return 0.98;
}



직관적 임시변수 사용 (introduce Explaining Variable)

  • 사용된 수식이 복잡할 땐 수식의 결과나 수시의 일부분을 용도에 부합하는 직관적 이름의 임시변수에 대입하자.

if((platform.toUpperCase().indexOf("MAC") > -1)&&
      (browser.toUpperCase().indexOf("IE") > -1)){
  //기능코드
}

위의 코드를 아래와 같이 리팩토링 가능하다

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIeBrowser = browser.toUpperCase().indexOf("IE") > -1;


if(isMacOs && isIeBrowser){
  //기능코드
}


  • 동기

    • 수식이 너무 복잡해져서 이애하기 힘들 경우 임시변수를 사용하면 수식을 더 처리하기 쉽게 쪼갤수 있다.

  • 방법

    • 수식에서 한부분의 결과를 임시변수의 값으로 교체하자

    • 그 임시 변수를 final로 선언하자

    • 컴파일과 테스트를 실시하자.








개떡같다. 
호이스팅 

호이스트  사전적의미  :  끌어 올리다.
자바스크립트에서 변수 선언과 함수 선언을 끌어 올린다. 

호이스팅이 없다면 아래의 코드는 에러가 발생하겠지만 
console.log(a())
console.log(b())
console.log(c())


function a() {
return 'a'
}
var b = function bb() {
return 'b'
}

var c = function() {
return 'c'
}

앞서 설명했듯이 호이스팅이 끌어 올리는 역할을 하기 때문에 실제 자바스크립트가 실행 될 때는 아래와 같이 변환된다고 생각하면 됨

function a() {
return 'a'
}

var b;
var c;
console.log(a())
console.log(b())
console.log(c())


b = function bb() {
return 'b'
}

c = function() {
return 'c'
}

함수 선언은 통째로 올라가버린 반면에 함수 표현식은 선언만 올라 갔다. 이유는 할당은 해당사항이 아니기 때문이다.
함수 선언은 그 자체가 하나의 선언이지만 표현식은 var b = 함수는 분리가 가능하기 때문에 b와 c는 선언만 올라갔다.

그렇다면 함수 표현식과 함수 선언식이란?? 차이점은??

함수선언식
function a() {
return a;
}

기명함수표현식
var b = function bb() {
return 'bb'
}

(익명) 함수표현식  : 이름 생략이 가능함 
var c = function(){
return 'c'
}

이전에는 기명함수 표현식이 이점이 있었음 왜냐 에러 발생 시 함수의 이름을 노출해줬기 때문 그러나 요즘에는
함수명이 비어져 있을 경우 자동으로 변수명을 네임프로퍼티에 할당하기 때문에 이제는 익명 함수표현식이 선호되고 있음

익명 함수표현식이 선언되는 과정

var c = function(){
return 'c'
}

  1. 변수 c 선언
  2. 익명 함수 선언 
  3. 함수를 변수c에 할당

할당이 키포인트다. 
할당을 하면 함수 표현식이고 
할당을 하지 않으면 함수 선언식이다.

할당을 하지 않으면 함수 전체가 호이스팅 되고
할당을 하면 변수만 호이스팅 됨

그럼 호이스팅이 왜 중요할까 설명은 개떡처럼 못하면 서 왜 계속 설명할까..
 
협업 시 소스가 길어질 때 2명의 개발자가 같은 함수를 만들었을 때를 가정해 보자. 
그럼  두개의 함수가 모두 호이스팅 되어 끌어올려질 것이고 나중에 선언된 함수가 기존의 함수를 덮어 버릴 것이다 그럼 결과가 
개떡처럼 나오겠지. 또한 가독성면에서 좋지 않기 때문에 욕먹기 딱 좋다. 

function sum(a,b){
return a+b;
}

sum(1,2)

/* 중략 ..1만라인.. */



function sum(a,b){
return 'a'+'+'+'b'+'='+(a+b)
}

sum(1,2)

그래서 함수 선언식보다는 무조건 함수 표현식을 쓰길 권장함
안전하고 예측가능한 소스가 되기 때문에 

var sum = function sum(a,b){
return a+b;
}

sum(1,2)

/* 중략 ..1만라인.. */

var sum = function sum(a,b){
return 'a'+'+'+'b'+'='+(a+b)
}

sum(1,2)


함수스코프와 실행컨텍스트

스코프 (SCOPE )  : 유효범위 (변수)
실행컨텍스트 (EXCUTION CONTEXT)  : 실행되는 코드 덩어리( 추상적 개념)

둘의 가장큰 차이는 발생 시점에 있음

스코프는 함수가 정의 될 때 결정된다.
실행 컨텍스트는 함수가 실행 될 때 생성된다.

실행 컨텍스트에는 
호이스팅, this 바인딩 등의 정보가 담김
즉 함수실행에 필요한 정보를 불러 담은 정보 집합체 라고 생각하면될 것 같다.


var a = 1;

function outer(){
console.log(a);

function inner(){
console.log(a)
var a = 3;
}

inner();

console.log(a);
}

outer();
console.log(a);


실행순서를 생각해 보자 



실행 값을 예측해보자.


왜 2번에서 undefined 가 출력됐을까? 실행 순서를 보고 알아보자.

기본형과 참조형의 종류 및 차이점

Primitive Type   - Number, String,Boolean,null,undefined  
기본값 : 값을 그대로 할당.

Reference Type - Object - Array,Function RegExp , Map,Set WeakMap , WeakSet
참조값 : 값이 저장된 주소값을 할당(참조)

우선 기본값에 대해 알아보자 
var a ; 를 타이핑하면 우선 a라는 변수를 저장할 데이터 영역을 확보한다. 314번 영역을 확보하고 해당 주소를 변수명과 맵핑시킨다.



이제 a에 값을 입력해보자.  
a=10; 변수명에 맵핑된 주소를 찾아가 해당 주소의 데이터 영역에 10을 저장한다.

이번에는 변수 b에 "abc"를 할당해 보자.
위와 마찬가지의 과정을 거쳐 아래와 같이 저장된다.
var b = 'abc' 

b에 다른 값을 할당하고 b=c 할 경우 

기본값은 직접적인 비교가 가능하다.
a===b   : false
a===c   :  true

이제 참조형에 대해서 알아보자.

var obj ={
    a:1,
    b:'b'
}
라는 객체가 선언 됐을 때 아래와 같이 저장된다.

즉 참조형은 기본형의 집합으로 생각할 수 있다.

그렇다면 var obj2 = obj를 선언했을 때 어떻게 될까?

저장된 객체의 주소만을 복사해온다. 참조

만약  obj2.a =10으로 할당할 경우. obj.a 역시 10으로 변환한다. 
즉 obj === obj2 는  true 동일한 객체를 바라본다.

그렇다면 참조에 참조가 걸리는 경우는 어떻게 될까?

var obj3 = {
    a: [1,2]
}


그렇다면 a에 'new'라는 문자를 대입할 경우 어떻게 될까?


var obj3 = {
    a: [1,2]
}

obj3.a='new'



a자리에 new 가 대입되면서 1012와 1013은 연결이 끊기게 되고 GC가 실행될 때 같이 사라지게됩니다.

+ Recent posts