본문 바로가기
  • 삽질하는 자의 블로그
JavaScript

이론 용어정리(2) [44~75] - 자바 스크립트 되짚기

by 이게뭐당가 2022. 12. 1.
[INDEX]=====================================================================================

<기본이론>
 
44. 제어문
45. 객체
46. 인스턴스
47. 객체 리터럴
48. 프로퍼티의 키 와 "" 의 관계
49. 함수
50. 매개변수(parameter), 인수(argument)
51. 함수와 식별자 와의 관계 with "정의"
52. "함수 선언문"과 "호이스팅"
53. 함수 호이스팅, 변수 호이스팅
54. 함수에서, 객체를 호출, 변경 할때에도, "참조에 의한 전달" 이 되기 때문에, 객체의 원본은 훼손된다.
55. 재귀함수
56. 중첩함수 (nested function) ***
57. 콜백함수 (callback function) ***
58. 순수함수와 비순수함수
59. 스코프
60. let, const 와 var
61. 프로퍼티와 프로퍼티 어트리뷰트
62. "데이터 프로퍼티"의 "프로퍼티 어트리뷰트 의 확인", 프로퍼티 디스크립터 : Object.getOwnPropertyDescriptor()
63. "접근자 프로퍼티" ... 어렵다 아직 이해 불가능
64. 그래서 이거 알아서 뭐해? => "프로퍼티를 정의" 한다. => 중요한 프로퍼티를 제어할 수 있다. : Object.defineProperty()
65. 프로퍼티의 속성을 다루었으니, 이젠, "객체" 의 속성을 다루어보자.
66. 생성자 함수
67. 생성자 함수의 인스턴스 생성 과정 with "new"
68. new 연산자
69. 생성자 함수에, 명시적 객체를 반환한다면?
70. 생성자 함수에, 명시적 원시값을 반환한다면?
71. 함수는 "객체이다"
72. 함수는 내부 메서드를 가지고 있다.
73. 오로지 일반함수 만이 construct 내부메서드를 갖는다. 화살표함수 같은건 Contruct 내부메서드가 없다.
74. 모든 함수는 new 만 붙어있으면 생성자 함수 취급 당한다. 단, construct 내부메서드를 가지고 있어야한다.
75. new.target 으로 "강제로 생성자 함수로 만들기"
 

[MAIN]======================================================================================

44. 제어문
    : 조건에 따라 코드블록을 실행(조건문), 반복실행(반복문) 을 말한다.

45. 객체
    : "객체"는 "원시값을 제외한" "자바크스립트를 구성하는 거의 모든 것들" 이다.
       
        객체는, "프로퍼티" 로 구성되고, "프로퍼티" 는 "키와 밸류" 로 구성된다.
            "프로퍼티" 안에 "함수" 가 있다면 "메서드" 라고 부른다.

        객체는, "타양한 타입의 값"을 "하나의 단위로 구성한" 복잡한 자료구조 이며,
        객체는, 배열과 같이 "변경이 가능한 값" 으로 저장된다. 이유는, 원시값과 달리, 변수에 저장시
"객체의 위치(메모리 공간의 주소)"를 정확히 저장하기 때문에
            스프레드연산자(...) 없이, 배열이나 객체를 참조한다면, "그것은 새 값으로 저장되는 것이 아니라, 객체 자체의 값을 바꿔버린다."

            * 원시값 복사 할때 "메모리 공간 안에 원시 값의 원본 이 복사되어 저장"
            * 객체,배열 은 복사 할때 "객체의 위치(메모리 공간의 주소) 가 복사되어 저장"


    <여러개의 식별자(변수) 가 "하나의 객체" 를 공유하는 예시>

            "어? 나는 obj2 안에,  obj1 의 값을 넣어서 obj2 를 바꿨는데, 왜 const인 obj1 이 바뀔까?"

                const obj1 = { x: 1, y: 2 };

                let obj2 = obj1;

                obj2.z = 3;

                console.log(obj2);      // {x: 1, y: 2 , z: 3}
                console.log(obj1);      // {x: 1, y: 2 , z: 3}
           
            ==> obj1 은 "객체의 위치" 를 저장한 것이기 때문이다.
                obj2 는 결국 obj1 의 "객체의 위치" 를 할당했고, obj2 의 값을 바꾸면 obj1 의 값도 바뀌는것이다.

46. 인스턴스
    : 클래스에 의해 생성되어, "메모리에 저장된 실체"

        "객체 지향 프로그래밍"에서 "객체" 는 "클래스" + "인스턴스" 를 말한다.
        "클래스" 는 "인스턴스" 를 생성하기 위한 템플릿이다.

        ==>     "클래스"    => 객체 + 함수             [ 빵틀 ]
                "인스턴스"  => 클래스에 의한 결과물     [ 실제 빵]


47. 객체 리터럴
    : 있어 보이는 말이지만, 그냥 "객체" 를 "사람이 이해 가능한 말로 만든다" 라는것 => "객체 만들기"다.

        const person = {
            name: "와우",
            sayHello: function () {
            console.log(`say ${this.name}`);
            },
        };
       
        person.sayHello();

-   메서드를 만들때 "화살표 함수" 가 아니고, "기본 함수형" 으로 객체 안에 넣도록 하자
        * 이는, this 바인딩 방식이 다르고, prototype 프로퍼티 가 없으며,  argument 객체를 생성하지 않아서 그렇다는데, 아직 잘 모르겠다.

48. 프로퍼티의 0키 와 "" 의 관계
    : 원칙적으로, "키" 는 "문자열" 을 주로 사용하기 때문에, "" 안에 넣어 사용해야한다.

        "name" : "와우"

    하지만, 생략이 가능하므로

        name : "와우"

    이렇게 사용하는 것이다.

    그러나 "네이밍 규칙"을 정확히 따르지 않는 "my-name" 같이 "-" 가 있는 경우 라던가 하는 것들은
        반드시 "" 안에 감싸서 하도록 하자.

49. 함수
    : 일련의 과정을 구현하고, "코드블록 으로 감싸 하나의 실행단위로 정의한것"

    함수는 "코드의 신뢰성, 가독성(재사용), 편의성" 을 위해 사용된다.

    함수는 "객체"이다. 단, 호출 가능한 "특별한 객체"
     
50. 매개변수(parameter), 인수(argument)
    : 매개변수는 함수를 "정의"할 때, "내부로 입력 값을 전달받는 변수"    => 여기에 이거 넣을 거에요
    : 인수 는 함수를 "사용"할때, "실제 입력하는 값" => 이거 넣었다.

51. 함수와 식별자 와의 관계 with "정의"

    : 함수는 왜 "선언"이 아니고 "정의" 인가?
            ==> 대부분 식별자를 "선언" 하지 않았기 때문에, "변수와는 다르게!"

        함수를 이렇게 "정의" 하고 "사용" 했다고 생각해보자

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

            add(2,3)

        이 상황에 "이상함을 느껴야 한다"

        우리는 함수를 만들었지, 함수를 가르키는 "식별자" 를 생성 한 적은 없으며,
            함수는 "식별자도 없이" 그저 "함수 이름" 만으로, 호출되었다. ***

        이는 사실, "자바스크립트가 함수 이름과 동일한 식별자를 암묵적으로 생성하고, 함수객체를 할당하였기 때문에" 가능한 일이다.

            const add = function add(x,y){
                return x+y
            }

            add(2,3)

        ==> 결과는 같지만, 이게 생략된 것의 원본이다. 이것은  "함수 표현식" 이라고 한다. (변수에 할당하였기 때문에)

52. "함수 선언문"과 "호이스팅"

    : 함수 선언문 으로 "정의한" 함수를 사용할 때,
        "정의하기 이전에" 호출 할 수 있다. ("함수 표현식 과는 다르게")

        이는 "함수 호이스팅" 이라는 현상 때문이다.

        호이스팅은 마치, 코드의 선두로 "끌어올려진" 것 처럼 동작하기 때문에 붙여진 이름이고,
            이는, "런타임 이전에 함수의 선언이 먼저 실행되기 때문에" "함수의 선언이, 실행 코드 이후에 있더라도", "사용 가능"한 것이다.

53. 함수 호이스팅, 변수 호이스팅

    : 변수도 호이스팅 된다. (var 키워드의 경우에만)
        단, 런타임 이전에 변수는 이름만 있고, undefined 로 초기화되지만

        함수 호이스팅의 경우는, 함수 객체로 초기화 되어 "하여튼 사용 할 수 있다".


        즉, "함수 표현식" 으로 정의된 함수 (cosnt add = function() {...} )
        들은, "변수 호이스팅" 이 발생하므로, "코드 줄을 이전에 적으면 사용 불가능"하다.

54. 함수에서, 객체를 호출, 변경 할때에도, "참조에 의한 전달" 이 되기 때문에, 객체의 원본은 훼손된다.
    : 함수나, 일반이나 똑같다.

55. 재귀함수
    : 함수는 자기 자신을, 자신 안에서 스스로 호출 할 수 있다.

56. 중첩함수 (nested function) ***
    : 함수 안에 새로운 함수를 만들 수 있다.
        이를, 내부함수 혹은 중첩함수(nested function) 이라고 한다.

57. 콜백함수 (callback function) ***
    : "함수의 매개변수를 통해", "다른 함수의 내부로 전달되는 함수"

        function ms(i, x) {                 => 고차함수
            x = i + x;
            return x;
        }
       
        const nested = function (i) {       => 콜백함수
            return i * 200;
        };
       
        console.log(ms(nested(1), 5));
     

58. 순수함수와 비순수함수
   
    : 순수함수는 "외부의 어떤 영향 없이, 매개변수에 같은 값을 넣으면 그 값이 나오는 함수"
        비순수 함수는 " 외부에 의해 영향을 받거나 주는 함수이다."

        * 비순수함수는 console.log() 가 아주 대표적이다 (함수 안에 같은 count 를 넣더라도)
            외부에서의 count 가 다르게 정의되있다면, 값이 달라지므로.

59. 스코프
    : 자신이 선언된 위치에 의해, 다른 코드가, 자신을 "참조 할 수 있는 유효범위"

            let y           ==>y의 스코프는 "코드 전체이다" (전역변수)

            function(){
                let x       ==> x의 스코프는 함수 안이 전부이다. (지역변수)
            }

60. let, const 와 var

    var :   중복선언 가능,
            변수 호이스팅 된다.
            함수레벨스코프 사용 (오로지 함수안에서만 지역변수)

            => "선언", "초기화"가, "런타임 이전에 동시에실행된다."

    const,let : 중복선언 불가!
                변수 호이스팅 안된다.
                블록 레벨 스코프 (모든 블록 안에서는 지역변수)

            => "선언과 초기화가" 분리되어 진행된다.
                "초기화 단계 이전"에 변수에 접근하려고 하면 "참조에러" 가 발생한다.
                    (선언은 했지만, 초기화가 안되어, 접근 불가하므로)

        * const 는 "선언과 함께 초기화를 동시에 진행해야한다"

            let x;          가능
            const x;        불가능
            const x = 1;    가능

61. 프로퍼티와 프로퍼티 어트리뷰트

    1) 프로퍼티는 "데이터 프로퍼티", "접근자 프로퍼티" 로 구별한다.

    2) 자바스크립트 엔진 은 "프로퍼티(객체 안의 데이터)" 를 생성할때, 프로퍼티의 상태를 나타내는 "프로퍼티 어트리뷰트"를 기본값으로 자동 정의한다.

62. "데이터 프로퍼티"의 "프로퍼티 어트리뷰트 의 확인", 프로퍼티 디스크립터 : Object.getOwnPropertyDescriptor()

            const obj = {
                x:1, y:2
            }

            console.log(Object.getOwnPropertyDescriptor(obj,"x"))       // 프로퍼티의 키 안에 "" 를 빼먹는 것을 조심

            ==>  {value: 1, writable: true, enumerable: true, configurable: true}

    데이터프로퍼티는 이와같이 4개 "프로퍼티 어트리뷰트" 속성을 가진다.

        1) value        : 값
        2) writable     : 값의 변경 가능 여부
        3) enumerable   : 프로터티의 열거 가능 여부 ( for...in, map, filter 전부 열거 하는것이다.)
        4) configurable : 프로퍼티 어트리뷰트 의 "재정립" 가능 여부 [어트리뷰트 안에는 "값"도 포함되므로, 해당 프로퍼티는 삭제도 불가능하다.]

63. "접근자 프로퍼티" ... 어렵다 아직 이해 불가능

64. 그래서 이거 알아서 뭐해? => "프로퍼티를 정의" 한다. => 중요한 프로퍼티를 제어할 수 있다. : Object.defineProperty()
    : 프로퍼티 어트리뷰트를 "명시적으로 정의하거나", "재정의" 할 수 있다.

            let obj = {
                x: 1,
                y: 2,
            };
           
            Object.defineProperty(obj, "x", {               // 프로퍼티 x 에 대해서, "value" 를 바꾸고, "writable : false" 로 두어, 변경 불가하게 만들었다.
                value: "lol",
                writable: false,
                enumerable: true,
                configurable: true,
            });
           
            obj.x = 3;
            obj.y = 3;
           
            console.log(obj);   // {x: 'lol', y: 3}

65. 프로퍼티의 속성을 다루었으니, 이젠, "객체" 의 속성을 다루어보자.
   
    1) Object.preventExtensions(obj이름) => 프로퍼티 추가               금지
    2) Object.seal(obj이름)              => 프로퍼티 추가, 삭제         금지,      프로퍼티 어트리뷰트 재정의금지
    3) Object.freeze(obj이름)            => 프로퍼티 추가, 삭제, 값 쓰기 금지,      프로퍼티 어트리뷰트 재정의금지
           
            let obj = {
                x: 1,
                y: 2,
            };

            Object.preventExtensions(obj)

66. 생성자 함수
    :  생성자 함수는 "객체를 찍어내는 틀" 이다. "인스턴스를 생성(값을 낼 때)할 때에는" 반드시 "new" 를 붙여준다.
    : 일반적으로 "프로퍼티" 와 "메서드" 를 포함한다.
       
        < 사용 >
       
            function MakeObj(parameter){
                this.name = parameter;
                this.getName = function(){
                    return  ("hello" + this.name)
                }
            }

            new MakeObj("ms")

            "단점" : 불편함
            "장점" : "동일한 프로퍼티를 갖는 객체를 여러개 생성해야 할 경우", "아주 간편하게 객체를 복사 할 수 있다."

        <일반 적인 경우 : "객체 리터럴" 을 이용한 객체 생성>

                const circle1 = {
                    radius :5,
                    getDiameter(){
                        return 2 * this.radius
                    }
                }

                const circle2 = {
                    radius :10,
                    getDiameter(){
                        return 2 * this.radius
                    }
                }

                ...
               
        <여러개 뽑을 경우 : "생성자 함수" 를 이용한 객체 생성>

                function Circle(radius){
                    this.radius = radius;
                    this.getDiameter = function(){
                        return this.radius *2
                    }
                }

                new Circle(5)
                new Circle(10)
                ...


67. 생성자 함수의 인스턴스 생성 과정 with "new"

    : 생각해보면, "생성자 함수 어디에도 return 따위가 없다", 이는 아무것도 반환되는 값이 없어야 한다.

        그렇지만,
       
            const circle1 = new Circle(5)
       
        를 하면, circle1 에는, 객체가 반환된다.

            function Circle(radius) {
                this.radius = radius,
                this.getRound = function () {
                    return radius * 2;
                };
            }
           
            const circle1 = new Circle(5);
           
            console.log(circle1);               // Circle {radius: 5, getRound: ƒ}
           
            console.log(circle1.getRound());    // 10

       " 이는 사실 이상한 일이다."

    => 생성자 함수는 자동으로 인스턴스를 반환한다
       
    1) 인스턴스 생성과 this 바인딩

        "생성자 함수"를 만들면, 암묵적으로 "빈 인스턴스가 생성되고", "this 를 생성자함수에 바인딩"한다

    2) 인스턴스 초기화

        "this에 바인딩 되어있는 인스턴스를 초기화한다."

    3) 인스턴스 반환
       
        생성자 함수의 내부처리(인스턴스 생성과 초기화) 가 끝나면, "완성된 인스턴스(초기화 했으니 사용가능)가 바인딩된" "this"가 반환된다.

68. new 연산자
    : new 연산자는, 생성자 함수를 "호출"할때, "암묵적 인스턴스를 생성, 초기화, 반환" 하는 역할을 한다.

69. 생성자 함수에, 명시적 객체를 반환한다면?

        function Circle(radius) {
            this.radius = radius,
            this.getRound = function () {
                return radius * 2;
            };
            return {}
        }

        console.log(new Circle(1))  // {}

    => "명시된 객체가 반환된다".
    ==> 훼손되므로, 생성자 함수에서는 "반드시 return 을 생략"

70. 생성자 함수에, 명시적 원시값을 반환한다면?


        function Circle(radius) {
            this.radius = radius,
            this.getRound = function () {
                return radius * 2;
            };
            return 13023
        }

        console.log(new Circle(5))   // Circle {radius: 5, getRound: ƒ}


    => "원시값은 무시된다."


71. 함수는 "객체이다"

    : 객체이므로, "프로퍼티와 메서드를 소유 할 수 있다."

        function ms(){}
            ms.prop = 10                // 빈 함수에, 프로퍼티를 생성
            ms.method = function(){     // 빈 함수에, 메서드를 생성
                console.log(this.prop)
        }

        ms.method(prop)                 // 10

72. 함수는 내부 메서드를 가지고 있다.

    : "Call", "Construct" 내부 메서드

        함수가 일반 함수로 호출될때는 "Call" 내부메서드에 의해, 호출되고
        함수가 "생성자함수" 로 호출될때에는 "Contruct" 내부 메서드에 의해, 호출된다
 
73. 오로지 일반함수 만이 construct 내부메서드를 갖는다. 화살표함수 같은건 Contruct 내부메서드가 없다.

    <일반함수>

        "함수 표현식" : const add = function(){ ... }
        "함수 선언문" : function add(){ ... }

            ==> 이것만이 메서드로서의 사용이 가능한 것이다.

    <화살표함수>

        const add = (x) => {
            console.log(x);
          };
         
            ==> 이런 화살표 함수는 "메서드로서 기능하지 못한다."  == "non-Contruct"
                    * 함수의 내부메서드 Construct 가 없고, Call 만 있으므로
         
74. 모든 함수는 new 만 붙어있으면 생성자 함수 취급 당한다. 단, construct 내부메서드를 가지고 있어야한다.

    그리고, 생성자함수는 "객체를 반환" 하므로, "객체가 반환되지 않는 함수""빈 객체만 반환된다."

        function add(x, y) {
            return x + y;
        }
        const inst = new add(2, 3);
        console.log(inst);          //   {} "객체가 반환되지 않았음"


        function Add2(x, y) {
            this.z = x + y;
        }
        const inst2 = new Add2(2, 3);
        console.log(inst2);        //  Add2 {z: 5}  "객체가 반환되었음"

75. new.target 으로 "강제로 생성자 함수로 만들기"
    : new.target 은, "생성자함수로 호출되었는지, 일반함수로 호출되었는지 알려준다."

        new.target 은,  "생성자 함수로 호출시"  => 함수 자신을 가르키고
                        "일반 함수로 호출시"    => undefined 을 나타낸다.


        <강제로 생성자 함수 만들기>

            function Circle(radius) {

                if(!new.target){
                    return new Circle(radius)
                }

                this.radius = radius,
                this.getRound = function () {
                    return radius * 2;
                    };
            }

        ==> 만약 "일반함수로 호출" 되어도,

            new.target 이 "undefined" 를 반환하고, [ !undefined == true ] 가 되기 때문에
                강제로 "new Circle()" 이 호출되어, "일반함수로 호출해도 생성자 함수가 호출된다."



댓글