[front] 코딩인터뷰를 저격하는 JS코어

JS 코어

JS의 고유 개념 및 타입 (원시타입, 참조타입, 래퍼타입)

원시타입의 특징

  • 원시값을 변수에 할당하면 값이 복사되어 들어감
  • 즉, 원시값이 할당된 변수들은 모두 자기 자신만의 고유한 값을 지니게 됨.
  • 문자열, 숫자, 불리언, null, undefined 존재

typeof

  • 원시값의 종류를 알 수 있게 해주는 메서드.
  • null의 타입에 주의

참조타입의 종류

  • 객체 : {}
  • 배열 : []
  • 함수 : function
  • Date
  • 정규표현식 : RegExp
  • 원시타입 제외 전부 참조타입

참조타입의 특징

  • 참조타입은 변수에 값을 직접 넣지 않음
  • 변수에 저장되는 건 메모리 안에서 객체의 위치를 가리키는 “포인터”
  • “무엇이 저장되느냐”가 원시타입과 참조타입의 가장 큰 차이

원시타입도 참조타입 처럼 사용 가능

  • 원시 래퍼 타입 사용시 가능
  • 원시타입을 객체처럼 편리하게 사용하도록 도와줌

원시 래퍼타입의 종류

  • String
  • Number
  • Boolean

원시 래퍼타입의 특징

원시 타입을 객체처럼 사용시, js 내부에서 사용하는 데이터의 인스턴스를 만들게 됨. 이렇게 만들어진 객체는 코드 실행 후 바로 다음줄에서 파괴되고, 이러한 과정을 오토박싱(autobixing) 이라고 한다.
  • 원시 래퍼타입은 원시타입을 객체처럼 사용할 수 있도록 한다.
var one = 1;
var two = 2;

one = two;

one = 3;

console.log(two);
console.log(typeof 1);
console.log(typeof "hi");
console.log(typeof true);
console.log(typeof null);
console.log(typeof undefined);

var objOne = {one:1};
var objTwo = {two:2};

objTwo = objOne;

objTwo.one = 3;

console.log(objOne);
console.log(objTwo);


var str = "hello world";
console.log(str.length);


var name = "test";
console.log(name.concat("coin"));

var name2 = "test";
var temp = new String(name);
console.log(temp.concat("coin"));
//임시 변수 만들어서 메서드 실행하고 바로 해제해준다.->자바스크립트 내부에서 벌어지는 일

temp = null;

var name3 = "test"
name3.coin = "coin";
console.log(name3.coin); //undefined. 원시타입을 참조타입처럼 사용. 내부적으로 temp 사용

//js내부적으로 보면
var name3 ="test";
var temp = new String(name);
temp.coin = "coin";
temp = null;//객체 해제

var temp = new String(name);
console.log(temp.coin);


this 사용(call, apply, bind)

  • this 가 존재하는 이유
var myDiner = ={
    name: "김치찌개",
    menu : function(){
        console.log("오늘저녁은"+ myDiner.name);
    }
}

myDiner.menu();

위와 같은 객체가 있을 떄 menu함수는 myDiner 변수 이름이 수정 될 경우나 menu함수 자체를 다른 객체에서 사용 하고 싶은 경우 사용이 불편

  • myDiner 변수의 이름을 변경하고 싶다면, 코드 내부의 myDiner라는 문자열을 모두 수정해야 합니다. 이렇게 하면 변수 이름을 변경하는 과정에서 실수할 가능성이 있고, 모든 참조를 일일이 수정해야 함
  • 만약 다른 객체에서 menu 함수를 사용하려면, 현재의 코드에서는 myDiner.menu() 형태로만 호출할 수 있습니다. 이 함수를 다른 객체에서 사용하려면 해당 객체에 menu 함수를 복사하거나 참조를 가져와야 함
function menuGlobal() {
    console.log("오늘 저녁은 " + this.name);
}

var myDiner = {
    name: "김치찌개",
    menu: menuGlobal
}

var yourDiner = {
    name: "된장찌개",
    menu: menuGlobal
}

yourDiner.menu();

// function Diner(name) {
//     this.name = name;
// }

// Diner.prototype.menu = function() {
//     console.log("오늘 저녁은 " + this.name);
// };

// var myDiner = new Diner("김치찌개");
// myDiner.menu();

this를 통해 함수를 다른 객체에서도 재사용 가능, 일반적으로 this는 자동으로 할당

call()

  • call 메서드는 this의 값을 바꿀 수도 있고, 함수를 실행 할 때 사용할 인수를 전달 할 수도 있다.
function menuGlobal (item) {
    console.log("" + item +this.name)
 }

 var myDiner=
 {
     name: "김치찌개"
 }
 var yourDiner =
 {
     name: "된장찌개"
 }
 menuGlobal.call (myDiner, "");
 menuGlobal.call(yourDiner, "");

apply()

  • apply 메서드는 함수를 실행할 때, 인수를 배열로 묶어 한번에 전달
function menuGlobal (item1, item2) {
    [item1,item2].forEach(function(el){

    console.log("오늘 저녁은" + el + this.name)
    },this);
}

var myDiner=
{
    name: "김치찌개"
}
var yourDiner =
{
    name: "된장찌개"
}
menuGlobal.apply (myDiner, ["묵은지","삼겹살"]);
menuGlobal.apply (yourDiner, ["두부","애호박"]);

Call() 과 apply()의 차이

  • call은 함수 실행 시 전달할 인수를 하나 하나 전달한다면, apply 는 전달할 인수를 배열로 묶어 한번에 전달. 그래서 인수를 두개만 사용한다.

  • 인수를 배열로 보낸다는 점 제외하고 call과 apply는 동일한 기능을 수행한다.

bind()

  • es5에서 추가.
  • this값을 어디서 사용하든 호출 객체가 바뀌지 않도록 고정시킴.
function menuGlobal (item) {

    console.log("오늘 저녁은" +  this.name)
}

var myDiner=
{
    name: "김치찌개"
}
var yourDiner =
{
    name: "된장찌개"
}

var menuGlobalForMe = menuGlobal.bind(myDiner); //바라보는 객체가 myDiner로 고정됨
var menuGlobalForYou = menuGlobal.bind(yourDiner); //바라보는 객체가 myDiner로 고정됨

console.log(menuGlobal("삼겹살")); //undefined

myDiner.meneMine = menuGlobalForYou
myDiner.meneMine("묵은지")

화살표 함수와 this

  • 화살표 함수의 this는 일반적인 this처럼 함수를 호출한 객체를 할당하지 않고 바로 상위 스코프의 this를 할당함.
function menuGlobal (item1,item2) {

    console.log(this);
    [item1,item2].forEach((el)=>{
        console.log("오늘 저녁은 "+ el + this.name)
    })
}

var myDiner=
{
    name: "김치찌개"
}
var yourDiner =
{
    name: "된장찌개"
}

menuGlobal.apply(myDiner,["묵은지","삼겹살"])
  • this는 함수를 호출하는 객체 의미
  • call 과 apply는 this에 할당되는 객체 지정 가능
  • Bind메서드는 this에 할당되는 객체가 고정된 새로운 함수 생성
  • 화살표 함수에서 this는 상위 스코프 객체 할당 받음

유효범위 scope

var func1 = function(){
    var a = 1;
    var b = 2;

    console.log(a+b);
    return a+b;
};

var a = 20;

console.log(b);
func1();

js의 유효 범위

  1. 전역 스코프
  2. 함수 스코프
  3. 블록 스코프(es6)

전역 스코프

  • 스크립트 내 어디서든 접근이 가능하기에 사용 쉬움
  • 타인과 협업, 라이브러리 사용시 충돌 가능성 존재

함수 스코프

  • 함수 내부에서 정의된 변수와 매개변수는 함수 외부에서 접근 불가
  • 함수 내부에서 정의된 변수라면 함수 어느 부분에서라도 접근 가능
var func1 = function(){
    var a = 1;
    var b = 2;

    var func2 = function(){
        var b = 5;
        var c = 6;

        a= a+b+c;

        console.log(a);
    };
    func2();
};

func();

블록 스코프

  • 중괄호 안에서만 접근 가능
  • 블록 내부에 정의된 변수는 블록 실행 종료 후 해제
function test(){
    val = "hello";  //함수 스코프 안에 있어도 var이나 let 선언없이 사용하면 전역변수
    var val2 = "world";
}

test();

console.log(val);
// function test(){
//     val = "hello";  //함수 스코프 안에 있어도 var이나 let 선언없이 사용하면 전역변수
//     var val2 = "world";
// }

// test();

// console.log(val);


if(true){
    var value = "hello";
}

console.log(value);

if(true){
    let value = "world";//var로 수정시 world사용 가능
}

console.log(value);
  • 스코프는 변수의 접근성과 생존 기간 제어
  • 스코프는 이름 충돌 문제 덜어주고 자동으로 메모리 관리

클로저

클로저는 함수와 함수가 참조하는 변수들로 이루어진 환경을 지칭하며, 이 환경은 해당 함수가 실행 종료된 이후에도 계속해서 유지됨.

function outer() {
    var outerVar = "I'm from outer!";

    function inner() {
        console.log(outerVar);
    }

    return inner;
}

var closureFunc = outer(); // outer 함수가 실행되고 inner 함수가 반환됨
closureFunc(); // inner 함수가 실행됨, "I'm from outer!" 출력

또 다른 예시

var outer = function(){
    var a =1;

    var inner = function(){
        var b = 5;
        var c = 6;

        a = a + b + c;
        console.log(a);
    };
    inner ();
};

outer();


위와 같은 코드가 있는데 만약 만약 내부함수가 외부함수보다 오래 살아있는 경우 외부함수에 있던 변수들은 어떻게 되는가.

var outer = function(){
    var a =1;

    var inner = function(){
        var b = 5;
        var c = 6;

        a = a + b + c;
        console.log(a);
    };
    return inner;
};


// outer();
var newInner = outer(); //outer함수 결과물 넣고 실행 테스트
newInner();

//new Inner함수가 실행된다 = Inner함수가 실행된다는 의미와 동일

함수와 함수가 선언될 때의 환경(스코프)과 관련이 있습니다. 클로저는 다음과 같이 정의할 수 있습니다:

  • 클로저는 함수가 선언될 때의 환경을 기억하고, 이 환경에 접근할 수 있는 함수를 반환하는 함수

클로저의 특징

  1. 내부 함수: 일반적으로 클로저는 다른 함수 내부에서 선언됩니다. 이러한 내부 함수는 외부 함수의 지역 변수를 참조할 수 있습니다.

  2. 환경 기억: 클로저는 자신이 선언된 외부 함수의 스코프(변수와 매개변수)에 대한 참조를 유지합니다. 이러한 환경 기억은 클로저가 생성된 시점의 값들을 기억하고 나중에도 사용할 수 있게 합니다.

  3. 외부 함수에서 반환: 클로저는 주로 외부 함수에서 반환되어 외부에서도 호출할 수 있게 됩니다. 이때 클로저가 반환되면서 외부 함수의 스코프에 대한 참조를 유지하게 되므로, 외부 함수의 지역 변수는 사라지지 않고 유지됩니다.

외부함수 변수들은 더 사용이 안 되는건가?

클로저에서 외부 함수의 변수들은 사용 가능. 클로저는 외부 함수의 변수에 대한 참조를 유지하므로, 외부 함수에서 선언한 변수들은 클로저 내부에서 사용할 수 있고 변경할 수도 있다. 이를 통해 외부 함수의 변수들은 클로저 내부에서 계속 유효하게 유지된다.

결국 클로저는 “폐쇄된 공간에 대한 접근 권한을 가진 함수” 이다

  • 위 특징을 이용하면 비공개 데이터를 가진 객체를 만들 수 있다.
예시
// 즉시 실행 함수로 클로저를 생성하고 그 결과를 person 변수에 할당합니다.
var person = (function(){
    var age = 15;

    return {
        name : "Wade",

        getAge : function(){
            console.log(age);
            return age;
        },

         setAge : function(val){
            age = val;
            console.log(age)
        }
    };
})();

person.age = 30;

person.getAge();

  • js는 내부함수에서 자신을 포함하는 외부 함수의 스코프에 접근 가능
  • 내부함수가 살아있는 상태에서 외부함수가 파괴되면, 외부 함수의 변수들에 대한 접근 권한은 내부함수만 가지게 된다.
  • 이렇게 폐쇄된 공간에 대한 접근 권한을 가진 함수가 클로저다

생성자

생성자란 앞에 new 연산자가 붙은 함수를 의미하며, 인스턴스를 만들 수 있다.

  • 예를 들어 new Object(), new Array()는 js 내부적으로 존재하는 내장 생성자다.
var myArray = new Array(1,2,3);
console.log(myArray)

생성자 만드는 법

image

  • 생성자와 인스턴스 관계는 instanceof와 constructor 메서드를 통해 확인 가능
function MyOwn(){

}
var myObj = new MyOwn();

console.log(myObj instanceof MyOwn);
console.log(myObj.constructor === MyOwn);

생성자 만드는 이유

  • 생성자의 기능은 동일한 프로퍼티와 메서드를 가진 객체를 쉽게 대량생산 하기 위함
function Food(taste){
    this.taste = taste;
    this.smell = function(){
        console.log(this.taste + "냄새가 난다");
    }
}

var myFood1 = new Food("특제 파스타");
var myFood2 = new Food("해물 파스타");
var myFood3 = new Food("알리오 파스타");

myFood1.smell()
myFood2.smell()
myFood3.smell()ㅉ

생성자의 new 연산자는 매우 중요

  • new 연산자가 붙으면 함수의 this는 인스턴스를 참조하게 된다.
  • new 연산자가 자동으로 인스턴스 반환하므로 함수 안에 return 연산자도 필요 없어진다

만약 생성자 함수에 new 연산자가 없다면

  • 생성자 함수는 단순히 평범한 함수이며, this 는 전역 객체를 가르키게 된다.

  • 생성자란 앞에 new 키워드가 붙은 함수를 의미
  • 생성자의 중요 기능은 동일한 프로퍼티와 메서드를 지닌 객체를 쉽게 대량생산 하는 것.
  • 생성자 함수의 new 연산자는 인스턴스를 참조

프로토타입

  • myFood.smell 메서드와 myFood2.smell 메서드는 서로 다른 참조를 하고 있다.
  • 즉, 객체를 생성할 떄마다 별개의 함수가 계속 만들어진것.
function smell() {
    console.log(this.name + " 냄새가 난다");
}

function Food(name) {
    this.name = name;
    this.smell = smell;
}

var myFood = new Food("로제 파스타");
var myFood2 = new Food("창란젓");

myFood.smell();
myFood2.smell();

console.log(myFood.smell === myFood2.smell);

자바스크립트는 생성자의 프로토타입 프로퍼티를 통해 타입의 특징을 정의한다.

  • 앞서 본 construcotr 메소드는 Object 타입의 프로퍼티이며, 프로토타입에 의해 정의된다.
  • Object.prototype.constructor

image

모든 인스턴스는 내부에 프로토타입 프로퍼티를 가지며 이를 통해 프로토타입 프로퍼티를 추적한다.


Food.prototype.smell = function () {
    console.log(this.name + " 냄새가 난다");
}

function Food(name) {
    this.name = name;
}

var myFood = new Food("로제 파스타");
var myFood2 = new Food("청국장");

myFood.smell();
myFood2.smell();


console.log(myFood.smell === myFood2.smell);
  • smell 함수를 프로토타입에 등록 후 더 Food 생성자에 this써서 smell 함수를 만들 필요가 없어졌다.
![image](https://github.com/Soliloquiess/soliloquiess.github.io/assets/37941513/69d1da0f-b3a7-4f19-a00f-a5ac8f1fd82f)
  • 이런식으로 인스턴스에서 생성자의 프로토타입을 타고 올라가며 프로퍼티를 탐색하는 현상을 프로토타입 체인이라고 한다.

  • 자바스크립트는 생성자의 prototype 프로퍼티를 통해 타입의 특징을 정의한다.
  • 모든 인스턴스는 내부에 Prototpye 프로퍼티를 가지며 이를 통해 생성자의 프로토타입 프로퍼티를 추적한다.
  • 인스턴스에서 생성자의 프로토타입을 타고 올라가며 프로퍼티를 탐색하는 현상을 프로토타입 체인이라고 한다.

서브타입 & 슈퍼타입

function Sausage(el1, el2) {
    this.inside1 = el1;
    this.inside2 = el2;
}

Sausage.prototype.taste = function () {
    return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
}

var mySausage = new Sausage("돼지고기", "마늘");
console.log(mySausage.taste());



// 불맛 소시지 레시피
function FireSausage(el1, el2, el3) {
    this.inside1 = el1;
    this.inside2 = el2;
    this.inside3 = el3;
}

FireSausage.prototype.taste = function () {
    return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
}

FireSausage.prototype.flavor = function () {
    return this.inside3 + "의 풍미도 있다!";
}


var myNewSausage = new FireSausage("돼지고기", "마늘", "불맛");

console.log(myNewSausage.taste());
console.log(myNewSausage.flavor());
  • 위 코드는 불맛 소시지, 소시지 공정과정이 매우 겹치고 있다.
  • 개선하려면?

생성자 훔치기



function Sausage(el1, el2) {
    this.inside1 = el1;
    this.inside2 = el2;
}

Sausage.prototype.taste = function () {
    return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
}

var mySausage = new Sausage("돼지고기", "마늘");
console.log(mySausage.taste());


function FireSausage(el1, el2, el3) {
    Sausage.call(this, el1, el2);
    this.inside3 = el3;
}

var myNewSausage = new FireSausage("돼지고기", "마늘", "불맛");
console.log(myNewSausage.inside1);
console.log(myNewSausage.inside2);
console.log(myNewSausage.inside3);

  • 생성자는 함수이므로 call()메서드를 사용 가능

  • FireSausage 생성자 함수의 this는 FireSausage의 인스턴스. 그렇기 떄문에 Sausage.call 의 this는 FireSausage의 인스턴스를 가리키게 됨

  • 이렇게 call이나 apply를 이용해 인스턴스를 인수로 전달받고 프로퍼티를 상속 받는 방법을 생성자 훔치기라고 표현

프로퍼티를 상속받는 타입을 하위타입, 상속 해주는 타입을 상위타입이라고 한다.

프로토타입 상속


function Sausage(el1, el2) {
    this.inside1 = el1;
    this.inside2 = el2;
}

Sausage.prototype.taste = function () {
    return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
}

var mySausage = new Sausage("돼지고기", "마늘");
console.log(mySausage.taste());


function FireSausage(el1, el2, el3) {
    Sausage.call(this, el1, el2);
    this.inside3 = el3;
}

var myNewSausage = new FireSausage("돼지고기", "마늘", "불맛");

FireSausage.prototype = Object.create(Sausage.prototype);
FireSausage.prototype.constructor = FireSausage;

FireSausage.prototype.flavor = function () {
    return this.inside3 + "의 풍미도 있다!";
}

Object.create() 메서드는 프로토타입에 참조할 생성자의 프로토 타입 프로퍼티를 설정한다.


function Sausage(el1, el2) {
    this.inside1 = el1;
    this.inside2 = el2;
}

Sausage.prototype.taste = function () {
    return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
}

var mySausage = new Sausage("돼지고기", "마늘");
console.log(mySausage.taste());


function FireSausage(el1, el2, el3) {
    Sausage.call(this, el1, el2);
    this.inside3 = el3;
}

FireSausage.prototype = Object.create(Sausage.prototype);
FireSausage.prototype.constructor = FireSausage;

FireSausage.prototype.flavor = function () {
    return this.inside3 + "의 풍미도 있다!";
}

var myNewSausage = new FireSausage("돼지고기", "마늘", "불맛");

console.log(myNewSausage.taste());  //프로토타입 바라봄
console.log(myNewSausage.flavor()); //FireSausage 프로퍼티 재 설정

별 차이가 없어 보이나 , 코드가 길어지면 상속은 매우 유용

  • call이나 apply를 이용해 인스턴스를 인수로 전달하고 프로퍼티를 상속받는 방법을 생성자 훔치기라고 한다.
  • Object.create() 메서드를 통해 인스턴스의 프로토타입 대상 지정 가능
  • 자바스크립트에선 상속받는 타입을 하위타입, 상속하는 타입을 상위타입으라 부름

클래스

class User {
    constructor(name) {
        this.name = name;
    }
    sayName() {
        console.log(this);
        console.log(this.name);
    }
}

위와 같은 클래스가 있는데 클래스 없이 만들기 위해서는 아래의 작업을 거쳐야 한다.

var me = new User("jaehyun");
me.sayName();

//constructor 메서드는 우리가 앞에서 예기해본 Object.prototype.contructor 와는 다릅니다.
//클래스의 생성자 함수라고 할 수 있습니다.

function UserOld(name) {
    this.name = name
}

UserOld.prototype.sayName = function () {
    console.log(this);
    console.log(this.name);
}

var user = new UserOld("jaehyun");
user.sayName();

클래스는 정확히 생성자를 이용한 타입 생성과 그 결과가 일치함.

  • 자바스크립트만의 사용자 정의 타입 생성방법을 다른 언어의 클래스 문법처럼 바꿔준 것이 자바스크립트 클래스이다.

  • 내부적인 동작은 동일하나, 더 보기 좋고 편리하게 개선된 문법을 슈가 신택스라고 부른다.

  • 타입 상속처럼 클래스도 상속 가능


class Sausage {
    constructor(el1, el2) {
        this.inside1 = el1;
        this.inside2 = el2;
    }

    taste() {
        return this.inside1 + "와 " + this.inside2 + " 맛이 난다!";
    }
}

var classicSausage = new Sausage("닭고기", "양파");
console.log(classicSausage.taste());


class FireSausage extends Sausage { }

var classicFireSausage = new FireSausage("소고기", "파");

console.log(classicFireSausage.inside1);
console.log(classicFireSausage.inside2);
console.log(classicFireSausage.taste());

  • 위 예시처럼 extends 연산자를 이용해 상위 타입의 프로퍼티를 상속 받는 것이 가능
  • call, Object.create()함수를 사용 하던 것과 달리 좀 더 명시적임


class FireSausage extends Sausage {
    constructor(el1, el2, el3) {
        this.inside3 = el3;
    }

    flavor() {
        return this.inside3 + "의 풍미도 있다!";
    }
}

var classicFireSausage = new FireSausage("소고기", "파", "불맛");

console.log(classicFireSausage.taste());
console.log(classicFireSausage.flavor());

//------------------------------------//

class FireSausage extends Sausage {
    constructor(el1, el2, el3) {
        super(el1, el2);
        this.inside3 = el3;
    }

    flavor() {
        return this.inside3 + "의 풍미도 있다!";
    }
}

var classicFireSausage = new FireSausage("소고기", "파", "불맛");

console.log(classicFireSausage.taste());
console.log(classicFireSausage.flavor());

  • 위 예시 코드에서 위 코드는 에러 나나 아래코드는 정상이다.
  • 이유는 자식 클래스에 constructor 함수 선언 시 부모 클래스의 construtor 함수를 덮어쓰기 떄문

    • 이를 해결하기 위해 super메서드가 필요함.
    • super 메서드는 슈퍼타입의 생성자를 호출한다.
  • 자바스크립트의 타입 방법을 다른 언어와 비슷하도록 보기 쉽게 개선한 것이 클래스
  • extends연산자를 통해 상위 타입의 프로퍼티를 상속받는다
  • super메서드를 통해 자식 클래스의 생성자 함수가 부모클래스의 생성자함수를 덮어 씌우는 것을 방지할 수 있다.

호이스팅

test1
console.log(test());
console.log(testValue());

function test(){
    return "test";
}

var testValue = function(){
    return "testValue";
}

위 코드가 오류나는 이유는 함수를 변수 안에 넣었는데, 호이스팅으로 이름만 끌어올려지고 값을 알 수 없어서 (값이 들어가있지 않아서) 오류 발생)

image

test2
console.log(testValue);
console.log(undeclared); //선언하지 않은 변수는 에러남.
//선언한 변수도 "값"까지 끌어올려지지는 않음

var testValue = 100;
test3
console.log(testValueVar());

var testValueVar = function testValue(){ //안에 값이 뭔지 몰라 실행 불가
    return "hoist test";
}
  • 변수는 함수와 달리 선언만 끌어올려짐.
  • 값은 끌어올려지지 않음
test4
console.log(test);
var condition = false;

if(condition){  //if문 안에서 변수 선언 및 초기화
    var test = "this is test";
}
  • 함수 내에서 변수 선언과 초기화
  • var test로 전역으로 선언 되고 값이 들어 가기 전 호이스팅 되어 위로 올라가서 “undefined”가 나온다.
test5
console.log(test());
console.log(value);

function test(){ // 함수 안에서 변수의 선언과 초기화가 이뤄지는 경우
    var value = "hoist";
    return value + "test";
}

  • 함수 안에서 변수의 선언과 초기화가 이뤄지는 경우
  • test 함수 선언은 위로 끌어 올려져서 결과 출력
  • value안의 변수는 함수 안에 있음(함수 스코프 내). 함수,변수도 자신이 속해있는 공간의 최상단으로 끌어올려짐

변수 선언 역시 코드를 실행할 때 변수를 포함하는 스코프 최상단으로 끌어올려진다.

  • 함수 안에 선언된 변수는 함수 스코프 안에서 최상단으로 끌어올려진다.
test6
console.log(test1);
console.log(test2);

console.log(Tester);

let test1 = "let value";
const test2 = "const value";

class Tester{
    constructor(){
        this.name = "test";
    }
}

let tester = new Tester();
호이스팅이 되지 않는 함수
  • 블록 스코프를 생성하는 let, const는 호이스팅이 되지 않는다. class 또한 마찬가지.

  • var로 선언된 변수는 호이스팅 되지만 let, const로 선언된 변수와 상수는 TDZ(Temporal Dead Zone, 임시접근 불가구역) 에 배치된다.
  • 이 값들은 선언이 실행 후 TDZ에서 제거 되어 사용 가능한 상태가 된다.
정리
  • 함수 선언과 변수 선언은 코드 실행시 해당 선언 스코프 최상단으로 끌어올려짐. 이런 현상을 호이스팅이라고 함.
  • 선언한 변수의 값은 끌어올려지지 않음
  • let, const, class 선언은 호이스팅 현상이 일어나지 않음.






© 2021.03. by yacho

Powered by github