[JavaScript] 3. Object & Property & Function & hoisting

Nam_JU·2022년 7월 9일
0

KaKao Cloud School

목록 보기
3/19
post-thumbnail


1. JavaScript 객체

객체

JS는 객체 기반의 프로그래밍 언어이다.
원시 값(Primitive type)을 제외한 나머지 값(함수, 배열, 정규 표현식 등) 모두 객체다

원시 타입의 값, 원시 값은 변경 불가능한 값 immiutable value
객체타입의 값은 mutable value이다.


프로퍼티 Property

Property는 속성이라는 뜻으로 JS에서 객체 내부의 속성을 의미한다.
JS의 객체는 0개 이상의 Property의 집합이다.
각 Property는 key와 value의 쌍으로 구성되어있다


var person = { name : "홍길동", age : 45 }

  • property key {name, age} = 문자열이거나 symbol 값이 될수 있다

    • 따옴표 생략이 가능하다 (Naming Rule에 부합하는 경우)
  • property value {”홍길동”, 45} = 자바스크립트에서 value로 인식되는 모든 것

    • value에는 함수도 나올 수 있다 (메소드)

      //property key에는 메서드가 들어갈 수 있다 
      var obj = {
          'name': '홍길동',
          'printName': function myPrint(){
              //현재 사용하는 객체를 지칭하는 것 this
              console.log(`내이름은 ${this.name}`);
          },
          myphone : '10-484848',  
          "@myphone" : '10-484848'  //naming rule에 부합되지 않는 경우 "" 사용
      
      };
      
      console.log(typeof obj);  //object

JS 객체는 함수와 밀접한 관계를 가진다. 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임을 객체지향 프로그래밍이라고 한다.


Key-value 형태가 똑같은 JSON과 JavaScirpt Object의 차이는?

json은 객체가 아니다.
JavaScript Object Notation의 약자로 서버와 데이터를 교환할 때 사용하는 데이터 표준 형태이다.(자바스크립트 객체와 헷갈리지 말기)

Json은 타입이 String인 반면 JS Object는 Object 타입으로 함수를 할당 할 수 있다.



JavaScript 객체를 생성하는 방법

  1. 객체 리터럴
  2. Object 생성자 함수를 사용 (객체만들어 내는것이 생성자 함수이다)
  3. 생성자 함수 User defined
  4. Object.create() 메소드
  5. ES6 클래스를 사용하여 만들 수 있다


2. 원시 값(Primitive value)과 객체(Object)

JS에서 데이터타입은 크게 두가지로 나뉘어졌었다.

원시타입 Primitive type

  • 원시값은 변경 불가능한 값 immutable value 이다
  • 원시 값을 변수에 할당하면 메모리 공간에는 실제 값이 저장된다
  • 여기서 말하는 변경 불가능한 값은 값 자체를 변경할 수 없다는 의미가 아니다.

    변수 : 하나의 값을 저장하기 위해 확보된 메모리 공간자체
    값 : 변수에 저장된 데이터
    변경 불가능 한 것은 변수가 아니라 값을 뜻한다
    원시 값은 변경 불가능한 값. 읽기 전용 값이다.


변수가 참조하던 메모리 공간의 주소가 변경된 이유는 변수에 할당된 원시값이 변경 불가능하기 때문이다.
새로운 메모리공간 확보 -> 재할당한 값 저장 -> 변수가 참조하던 메모리 공간 주소 변경 이러한 특성을 불변성이라고 한다.
불변성을 갖는 원시 값을 할당한 변수는 재할당 이외에 변수 값을 변경할 수 있는 방법이 없다


  • 문자열과 불변성
    //primity vlaue값은 절대 바뀌지 않는다
    //유사배열 객체 Array-life object
    let myStr = 'Hello'
    
    myStr[0] = 'h'
    console.log(myStr); //Hello

객체(참조) 타입의 값 Object/reference type

  • 객체는 변경 가능한 값 immutable value 이다
  • 객체 값을 변수에 할당하면 메모리 공간에는 참조 값이 저장된다
  • 참조값은 생썽된 객체가 저장된 메모리 공간의 주소, 그 자체이다
  • 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다.

    재할당 없이 프로퍼티를 동적으로 추가할 수도 있고 프로퍼티 값을 갱신할 수도 있으며 프로퍼티 자체를 삭제할 수도 있다

객체의 부작용

  • 객체를 생성하고 관리하는 방식은 매우 복잡하고 비용이 많이 든다.
  • 메모리 효율적 소비가 어렵고 성능이 나빠진다
  • 여러개의 식별자가 하나의 객체를 공유할 수 있다


3. JS 함수

  • JS는 함수를 기반으로 한 언어다
  • 함수는 함수 이름으로 호출하지 않는다
  • 함수에 대한 식별자를 이용하여 호출한다

함수 function 이란

일련의 과정을 수행하기 위한 satement를 {}(중괄호)를 이용해서 하나의 실행단위로 만들어 놓은 것이다

  • 사용하는 이유 : 반복적인 코드를 이용하지 않고 함수화 시키면 유지보수가 좋다, 오류가 발생할 여지가 낮아진다 , 코드에 신뢰도가 올라간다
  • 사용방법 :
    1. 함수를 정의(defintion)해야한다 (추상메서드는 함수를 선언)

      function add(x,y) {return x + y; }

      • add: 함수이름
      • x, y: Paremeter (매개변수)
    2. 함수를 호출한다 (call, invoke)

      add(3,5);

      • 3,5 : argument (인자, 인수)

함수 리터럴 literal

JS함수는 객체 타입의 값이다. 따라서 숫자 값을 숫자 리터럴로 생성하고 객체를 객체 리턴으로 생성하는 것처럼 함수도 함수 리터럴로 생성 할 수 있다.

리터럴은 어떤 값을 표현하기 위한 기호, 변수에 저장되지 않으면 사용할 수 없다
var func = fucntion add ( x, y){ return x + y; }
fucntion add ( x, y){ return x + y; } 이 함수 리터럴이다
add 함수이름은 식별자(identyfier)이다
- 함수 이름은 함수 내에서만 사용 가능하다 (외부로 노출되지 않는다)
- name function 기명함수: 이름이 있는 함수
- anunemous function 익명 함수: 이름이 없는 함수

//기명함수
var myFunc = function add(x,y){
    return x + y;
}

//js에서 함수는 함수 내에서만 사용 가능하다
console.log(add(3,5)); //error: not defined

//식별자를 사용해야 호출이 가능
console.log(myFunc(3,5)); //8

//함수는 함수 이름으로 호출하는게 아니라 식별자로 호출한다
//무기명 함수
var myFunc = function (x,y){
    return x + y;
}

리터럴은 값을 생성하기위한 표기법이다. 따라서 함수 리터럴도 평가되어 값을 생성하며, 이값은 객체다. 즉, 함수는 객체
일반객체는 호출 할 수 없지만 함수는 호출할 수 있다


JS엔진은 생성된 함수를 호출 하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 거기에 함수 객체를 할당한다


함수를 정의 하는 방법

  1. 함수 선언문

    변수를 선언하지 않는다

    fucntion add ( x, y){ return x + y; }

  2. 함수 표현식

    var myFunc = fucntion add ( x, y){ return x + y; }

  3. Function() 생성자 함수 → 쓰지말기

    var add = new Fucntion('x', 'y') 'return x + y' }

  4. ES6 화살표 함수

    var add = ( x, y) => x + y;

  • code

    //함수 선언문
    function foo(){
        console.log('foo 함수');
    }
    
    //함수 선언문
    (function bar(){
        console.log('bar 함수');
    })
    
    foo();

자바스크립트 함수 특징

  • 자바스크립트는 오버로딩이 일어나지 않는다
  • 인자의 갯수에 상관없이 호출 가능하다
  • 만약 return이 없으면 암묵적으로 undefined가 된다
//함수 선언문
function add(x,y){
    // arguments
    return x + y;
}

console.log(add(2,5)); //7 
console.log(add(2)); //NaN(연산불가) - 호출가능
console.log(add(2,4,6)); //NaN(연산불가) - 호출가능
//함수 내부에 들어가 있는 인자를 보관하는 변수 - arguments 라는 property가 있다

함수 선언문 VS 함수 표현식 hoisting 호이스팅

  • 모든 식별자는 호이스팅이 일어난다 문제는 어떻게 일어나는지 파악하기
  • 함수 선언문: 런타임 이전에 만들어진다
  • 함수 표현식: 런타임 후에 만들어진다
    JS에서는 함수 표현식을 사용하는것이 좋다
    선언문은 호이스팅 되어서 사용될 수 있기 때문
foo(); //호출된다
add(); //error : not a function

//함수 선언문 -> 런타임 이전에 만들어짐
function foo(){
    console.log('foo 함수');
}

//함수 표현식 -> 런타임 후에 만들어진다
var add = function bar(){
    console.log('bar함수');
}


arguments : 유사배열 객체

  • length property를 가지고 배열 처럼 index를 이용해서 access가능
  • 순환 가능하다
  • 배열과 비슷하게 생겼지만 배열이 아니다

function add(){
    // arguments [2,4,6]
    let sum=0;
    for(let i=0; i<arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
}

console.log(add(2,5)); //7 
console.log(add(2));
console.log(add(2,4,6));

IIFE(Immediately Invoked Function Expression)

  • 즉시실행 함수
  • 함수를 선언함과 동시에 실행 call(invoke)
  • 함수의 재사용이 안된다
  • 한번쓰고 버리기 때문에 익명함수를 주로 쓴다
  • 쓰는 이유 : 가장 대표적인 예로 전역변수를 지역변수화 할 수 있다
//IIFE : 즉시실행 함수
(function(){
    let x = 10;
    let y = 20;

    console.log(x + y);
}());

중첩함수nested function (내부함수) inner function

중첩함수를 가지고 있는 바깥쪽 함수로 외부함수

모든 스코프는 체인으로 얽혀있다

전역변수를 계속 사용하게 되면 느려짐. 가능한한 지역 변수를 사용하도록 한다

var x = 100; //global scope (전역변수)
var y = 200; //global scope (전역변수)

//outer function
function outer(){
    let x = 0; // function level scope(지역변수)
    
    //inner function
    function inner(){
        let x = 10; // function level scope(지역변수)
        console.log(y);
    }
}

first-class citizen(object) 일급객체

  1. 익명의 literal로 생성가능하다 = 동적으로 생성이 가능하다
  2. 객체가 변수나 자료구조에 저장이 가능
  3. 일급객체를 다른 함수의 인자로 전달이 가능하다
  4. 함수의 리턴값으로 객체를 사용할 수 있다
  • 자바스크립트 함수는 일급객체
  • callback function → 고차함수
  • 코드
    //잘만든 함수가 존재하는데 이 함수의 기능을 변경하는 방법
    // 1. 원래 그 함수를 수정한다
    // 2. 함수를 새로 만든다
    // 3. 함수를 추상화 시켜서 인자로 받아들여서 사용
    // 고차함수 Higher-Ordered Function
    
    function repeat(n, f){
        for(var i=0; i<n; i++){
            //입력으로 들어온값을 추상화 시켜서 사용 
           f(i);
        }
    }
    
    //함수 표현식 
    let logAll = function(j){
        console.log(j);
    }
    
    let logOdd = function(k){
        if(k%2){
            console.log(k);
        }
    }
    
                //식별자로 주솟값을 넘겨서 실행시킨다 
    repeat(6, logOdd , logAll);


4. 스코프 Scope

  • 변수가 유효한 범위
  • js엔진이 식별자를 판단할때 스코프 체인을 가지고 판단을 한다
  • js엔진이 식별자identifer를 찾을때 사용하는 메커니즘이 scopechain 이다

Javascript Engine은 코드를 실행할때 문맥(context)을 고려해서 실행한다

현재 실행중인 코드가 어디에 있는 코드이고 코드 주변 정보를 파악해서 실행한다
⇒ lexical Enviroment → excution context

함수가 호출됐을때 Scope를

  • 함수가 호출된 것을 기준으로 설정한다 ⇒ 동적 스코프 Dynamic Scope
  • 함수가 정의된 곳을 기준으로 설정 ⇒ 정적 스코프 Static scope, Lexical Scope
    • 정적 스코프는 거의 대부분의 언어에 적용된다 (js 포함)
    • lexical, scope를 사용

렉시컬 스코프란(Lexical Scope)란?

함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정되는 것을 말한다.
즉, 함수를 어디서 선언하였는지에 따라 상위 스코프를 결정한다는 뜻이며, 가장 중요한 점은 함수의 호출이 아니라 함수의 선언에 따라 결정된다는 점이다.
다른 말로, 정적 스코프(Static scope)라 부르기도 하다.

그 이유는?

자바스크립트에서는 위와 같은 코드를 작성할 때, 이미 실행 단계에서 코드들의 스코프를 결정한다.

  • global 범위에 있는 변수 x
  • first() 함수 안에 있는 변수 x
  • second() 함수 안에 있는 변수 x

자바스크립트는 렉시컬 스코프(Lexical Scope)를 따르므로 함수를 선언한 시점에 상위 스코프가 결정된다.
즉, 이 말은 함수를 어디에서 호출하였는지는 스코프 결정에 아무런 의미를 주지 않는다는 말이다.

var x = 1; //전역 scope의 전역 변수

function foo(){
    var x = 10; //지역 scope의 지역 변수
    bar();
}

function bar(){
    console.log(x);
}

foo();


변수 스코프

전역변수를 사용하면

  1. 가독성이 나빠진다
  2. 메모리 resource를 소모
  3. 변수를 늦게 찾아 효율이 안좋다
  4. 다른 file과 변수 충돌이 생길 수 있다
  • 전역 스코프 Gloval scope
    전역에 선언되어 있어 어느 곳에서든 해당 변수에 접근이 가능하다
  • 지역 스코프 Local scope
    해당 지역 에서만 접근이 가능한 변수

호이스팅 Hoisting

함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.

변수 호이스팅

  • 자바스크립트에서 나오는 모든 식별자는 호이스팅이 된다
  • 코드 순서대로 실행이 되지 않는다. 아래에서 선언된 변수가 위에서 실행이 된다
  • 미리 변수선언이 해당 scope의 최상단으로 끌어 올려진것 같은 현상
  • 변수 선언을 runtime 이전에 구현한다

호이스팅이란

  • 자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
  • 자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
  • 함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
  • 유효 범위: 함수 블록 {} 안에서 유효
    즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것이다.
  • 실제로 코드가 끌어올려지는 건 아니며, 자바스크립트 Parser 내부적으로 끌어올려서 처리하는 것이다.
  • 실제 메모리에서는 변화가 없다.

호이스팅의 대상

  • var 변수 선언과 함수선언문에서만 호이스팅이 일어난다.
  • var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
  • let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.

변수 var, let, const

  • var: 함수레벨의 스코프(변수의 유효범위)를 잡는다 function-level scope
  • let & const: ES6에서 사용 블록레벨의 스코프를 잡는다 block-level scope const는 재할당이 불가능(메모리 주소 변경이 불가능)하며 선언과 동시에 할당이 이루어져야한다
    만약 참조타입을 할당할때 동일한 메모리 주소를 사용해야하는데 let을 사용하게 되면 주소가 변경된다




참고자료
https://ordinary-code.tistory.com/142
https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html
https://ljtaek2.tistory.com/145

profile
개발기록

0개의 댓글