컴퓨터 공부/🕸️ Web

Javascript 중급 - 4) IIFE (Immediately Invoked Function Expression), Intersection observer, 순수 함수, 커링, strict mode

letzgorats 2023. 12. 11. 21:03

< IIFE (Immediately Invoked Function Expression) >

즉시 실행 함수 표현(IIFE, immediately Invoked Function Expression) 은 정의되자마자 즉시 실행되는 Javascript Function을 말한다.

기본적인 형태는 아래와 같다.

(
    function () {
        // pass
    }
)()
  • 첫 번째() 소괄호 => 전역 선언 막고, IIFE 내부 안으로 다른 변수 접근 막는다.
  • 두 번째() 소괄호 => 즉시 실행 함수를 생성하는 괄호, 이를 통해 자바스크립트 엔진은 함수를 즉시 해석 및 실행한다.

[ IIFE의 주된 사용목적 ]

IIFE를 사용하는 주된 이유는 변수를 전역(global scope)으로 선언하는 것을 피하기 위해서이다.

또한 IIFE 내부 안으로 다른 변수들이 접근하는 것을 막을 수도 있다.

예제를 살펴보자.

(function () {
    var dogName = "ALLU";
})();
// IIFE 내부에서 정의된 변수는 외부 범위에서 접근이 불가능하다.
console.log(dogName)
// throws "Uncaught ReferenceError: dogName is not defined"

외부에서 내부 변수 접근 불가

 

위 코드처럼, 표현 내부의 변수는 외부로부터의 접근이 불가능하다.

var result = (function () {
    var name = "ALLU";
    return name;
})();
// 즉시 결과를 생성한다.
console.log(result);
// "ALLU"

변수에 IIFE 할당하면 결과는 저장됨

 

IIFE 를 변수에 할당하면 IIFE 자체는 저장되지 않지만, 함수가 실행된 결과만 저장된다.

 

[ 이름 없는 함수를 위해서도 사용 가능 ]

먼저 함수 리터럴(Function Literal)을 봐보자. 함수 리터럴은 함수를 정의하는 표현식이다.

함수 리터럴

 

여기서 함수이름은 없어도 되지만, 이름이 없으려면 두 가지 조건을 충족해야 한다.

 

1. 이 함수를 할당받을 변수를 지정해야 한다.

2. 이 함수를 즉시 호출해야 한다.

 

※ 이름 없는 함수로 변경(조건 충족 시키기)

 

1. 할당받을 변수를 지정 -> 이름 없는 함수 가능

const minus = function (a,b) {
    return a-b;
}
// 할당받을 변수를 지정(minus)

 

2. 함수를 즉시 호출 -> 이름 없는 함수 가능

(function (a,b) {
    return a-b;
})(1,2); 
// 함수를 즉시 호출

 

아래와 같이 하면, 함수가 즉시 호출되어서 값이 출력된다.

(function (a, b) {
    return console.log(a - b);
})(1, 2);

함수 값이 바로 출력

 

[ IIFE 는 앞에 연산자를 붙여서 사용하는 것도 가능 ]

연산자를 사용하는 것이 가능하지만, 화살표 함수에서는 무조건 "("로 시작해야 한다.

!function() { return console.log("ALLU") }() 
void function() { return console.log("ALLU") }() 
+function() { return console.log("ALLU") }() 
-function() { return console.log("ALLU") }() 
~function() { return console.log("ALLU") }() 
*function() { return console.log("ALLU") }() 
^function() { return console.log("ALLU") }() 
&function() { return console.log("ALLU") }();

연산자로 시작한&nbsp; IIFE 함수

 

더 심화된 예제를 살펴보자.

const score = () => {
    let count = 0;
    return {
        current: () => { return count },
        increment: () => { count++ },
        reset: () => { count = 0 }
    }
};

console.log(typeof score);
console.log(score);
console.log(score().current());  // 현재는 0
score().increment();  // count 1 증가
console.log(score().current()); // 그렇다면, 이 결과는 1?

 

score() 이라는 함수에서 current 함수를 호출하고, increment 함수를 호출한 뒤, 다시 current 함수를 호출하면 count 값은 0에서 1 증가한 1 이 될까?

결과는 아래와 같다.

 

값이 안 바뀜

값은 그대로 0이다. 

이유는 간단하다. 다시 호출하면 다시 count가 0으로 초기화 된 채로 호출이 되기 때문이다. 1로 올라가게 하고 싶으면 이 때 "즉시 실행 함수"를 사용하면 된다.

const score = (() => {
    let count = 0;
    return {
        current: () => { return count },
        increment: () => { count++ },
        reset: () => { count = 0 }
    }
})();

console.log(typeof score);
console.log(score);

console.log(score.current());  // 현재는 0
score.increment();  // count 1 증가
score.increment();  // count 1 증가
score.increment();  // count 1 증가
score.increment();  // count 1 증가
console.log(score.current()); // 그렇다면, 이 결과는 4?
score.reset();  // count 리셋
console.log(score.current()); // 그렇다면, 이 결과는 0?

값이 4가 됐다가 0으로 초기화 됨.

 

즉시 실행 함수 IIFE 를 변수에 할당하면, IIFE 자체는 저장되지 않고, 함수가 실행된 결과만 저장된다.

 

또 다른 예제를 살펴보자.

const increment = () => {
    let counter = 0;
    console.log(counter);
    const number = (num) => console.log(`it is ${num} number`);
    return () => { counter++; number(counter); }
}

increment(); // 0 
increment(); // 1 이 나올까?

똑같이 0이 나온다.

increment() 가 호출됨과 동시에 counter는 다시 0으로 초기화되기 때문에, 역시 0이 나온다.

1로 올라가도록 즉시실행함수를 사용하면 아래와 같다.

const increment = (() => {
    let counter = 0;
    console.log(counter);
    const number = (num) => console.log(`it is ${num} number`);
    return () => { counter++; number(counter); }
})();

increment(); // 0, 1 
increment(); // 2 
increment(); // 3 
increment(); // 4

 

counter가 호출할 때마다 1씩 증가한다.

 

IIFE 로 Closure 가 가능하게 만든 후에, 내부 함수에서 외부함수에 있는 변수를 접근되게 해준다.


< Intersection observer >

Intersection Obeserver는 기본적으로 부라우저 뷰포트(Viewport) 와 설정한 요소(Element)의 교차점을 관찰하며, 요소가 뷰포트에 포함되는지 포함되지 않는지, 더 쉽게는 사용자 화면에 지금 보이는 요소인지 아닌지를 구별하는 기능을 제공한다.

 

이 기능은 비동기적으로 실행되기 때문에, scroll 과 같은 이벤트 기반의 요소 관찰에서 발생하는 렌더링 성능이나 이벤트 연속 호출 등을 문제 없이 사용할 수 있다.

 

원리는 아래와 같다.

예를 들어 스크롤을 내리다가 뷰포트와 요소간의 교차점 발생
50%가 겹침
0->50%->100%->50%->0

 

예를 들어서, threshold 가 1이라고 해보자.

전체가 다 보여지면(=1,100%) 더 많은 리스트 가져와서 보여주기

 

코드를 통해 봐보자.

우선, html 코드와 js 예시는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Intersection Observer</title>
    <style>
      .item {
        text-align: center;
        padding: 20px 0px;
        margin: 0px;
      }

      .item:nth-child(even) {
        background-color: lightcoral;
      }
    </style>
  </head>

  <body>
    <div class="list"></div>
    <p class="end"></p>
    <script src="script.js"></script>
  </body>
</html>
const count = 20 // 한 번 새로운 item들이 추가될 때 추가되는 item의 갯수
let itemIndex = 0 // item의 index

let observer = new IntersectionObserver(entries => {

    console.log('entries',entries);
    entries.forEach(entry => {
        const list = document.querySelector('.list')

        // 타겟 요소와 루트 요소가 교차하면 isIntersecting true
        if (entry.isIntersecting) {
            for (let i = itemIndex; i < itemIndex + count; i++) {
                // item을 count 숫자 만큼 생성하고 list에 추가해주기
                let item = document.createElement('p')

                item.textContent = i
                item.className += 'item'
                list.appendChild(item)
            }

            // itemIndex를 +count해서 갱신
            itemIndex = itemIndex + count
        }
    })
}, { root: null, threshold: 0.1 })
// null을 설정하거나 무엇도 설정하지 않으면 브라우저 viewport가 기준이 된다.
// threshold 0.1은 타겟 요소의 10%가 루트 요소와 겹치면 콜백을 실행한다.

// list의 끝부분을 알려주는 p 타겟 요소를 관찰 시작
observer.observe(document.querySelector('.end'))

 

위 코드를 실행하면, 아래와 같은 결과가 나타난다.

 

한 번 리스트를 만들 때 20개씩 item을 만드는데, threshold를 0.1 로 줬기 때문에 타겟 요소의 10%만 루트 요소와 겹쳐도 콜백을 실행한다. 콘솔창을 보면 아래와 같다.

새로 observe 될 때 마다 entries가 찍힌다.

 

또 다른 예제를 살펴보면, Interaction Observer를 이용해서 이미지 lazyloading 도 처리 가능하다.

html 코드는 아래와 같다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Lazy Loading</title>
    <style>
        img {
            width: 400px;
            height: 300px;
            display: block;
            margin: 10px auto;
        }
    </style>
</head>

<body>

    <img src='https://via.placeholder.com/400x300'  
        data-src='https://ik.imagekit.io/demo/img/image4.jpeg?tr=w-400,h-300'>
    </img>

    <img src='https://via.placeholder.com/400x300'
        data-src='https://ik.imagekit.io/demo/img/image5.jpeg?tr=w-400,h-300'>
    </img>

    <img src='https://via.placeholder.com/400x300'
        data-src="https://ik.imagekit.io/demo/img/image6.jpeg?tr=w-400,h-300">
    </img>

    <img src='https://via.placeholder.com/400x300'
        data-src='https://ik.imagekit.io/demo/img/image7.jpeg?tr=w-400,h-300'>
    </img>

    <script>
        // Intersection Observer 인스턴스
        const observer = new IntersectionObserver(function (entries, observer) {
            entries.forEach(entry => {
                // 루트 요소와 타겟 요소가 교차하면 dataset에 있는 url을 src 에 넣어주기.
                if (entry.isIntersecting) {
                    entry.target.src = entry.target.dataset.src

                    // Lazy Loading 후에는 unobserve 해주기.
                    observer.unobserve(entry.target)
                }
            })
        }, { threshold: 1 })
        // 타겟 요소의 100%가 루트 요소와 겹치면 콜백을 실행.

        // 모든 img들을 관찰하기
        const imgs = document.querySelectorAll('img')
        imgs.forEach((img) => {
            observer.observe(img)
        })
    </script>

</body>

</html>

 

위 코드에서는 threshold가 1이기 때문에, 스크롤이 다 안내려가면 즉, 100% 겹치는 부분이 아니라면, 아직 사진을 보여주지 않는다.

스크롤 아직 다 안내림 -> 사진 안 보여짐
비로소 다 보여짐

 

위 코드에서는 이미지가 여러개라서 img 전체를 observe할건데, forEach를 통해 모든 이미지를 관찰할 수 있다.

console.log(entries)를 찍어보면 이미지가 여러개 나오는 것을 확인할 수 있다.

entries

여기에서 forEach를 통해 교차가 됐다면, src를 data-src로 바꿔주면 된다. img의 data-src는 dataset.src로 표현한다.

if (entry.isIntersecting) {
    ...
    entry.target.src = entry.target.dataset.src
    ...
}

 

dataset.src를 다 넣어줬으면 이제 더 이상 관찰할 필요가 없으니까, 관찰을 멈추기 위해서 observer.unobserver(관찰대상)을 해준다.


< 순수 함수(Pure Function) >

함수형 프로그래밍 패러다임의 한 부분이며, 순수 함수는 2가지 규칙을 가지고 있다.

 

1. 같은 입력값이 주어졌을 때, 언제나 같은 결괏값을 리턴한다. ( same input => same output )

// Same input => Same output
const add = (x,y) => x + y;
console.log(add(10,20));

const fullName = (first,last) => `${first} ${last}`;
console.log(fullName("Allu","Coding"));

10,20을 넣으면 항상 30이 나오겠고, "Allu", "Coding"을 넣으면 항상 "Allu Coding"이 나온다.

 

2. 사이드 이펙트를 만들지 않는다. ( no side effect )

// No Side Effects
const z = 1;
const sum = (x,y) => x+y+z;
console.log(sum(10,20));

이런 식으로 함수 밖에 스코프에 접근하는 것도 이 함수를 impure 함수로 만든다. 이런 side effect가 없어야 한다!

 

 

Impure 함수의 예시

: Pure 함수는 외부에서 선언된 상태(state)를 수정하면 안 된다.

 

(ex1) impure function 

// Impure Function Example
let x = 0;
const numberUp = () => x +=1 ;
console.log(numberUp());
console.log(x);

외부에서 선언된 변수 x가 변경되었다.

 

(올바른 pure function)

// Impure to Pure Function

let x = 0;
const pureNumberUp = (num) => num +=1 ;
console.log(pureNumberUp(x));
console.log(x);

 

(ex2) impure function 

// Impure Function Example
const alphabetArray = ['A','B'];
const addItemToArray = (originalArray, newItem) => {
    originalArray.push(newItem);
    return originalArray;
}
console.log(addItemToArray(alphabetArray, 'c')); // ['A','B','C']
console.log(alphabetArray);   // ['A','B','C']

 

alphabetArray 까지 ['A','B','C'] 가 돼버렸다. side effect가 발생한 셈이다.

 

// Impure to Pure Function
const alphabetArray = ['A','B'];
const pureAddItemToArray = (originalArray, newItem) => {
    return [...originalArray, newItem]
}
console.log(pureAddItemToArray(alphabetArray, 'C'));  // ['A','B','C']
console.log(alphabetArray);  // ['A','B']

spread operator를 사용해서 얕은 복사를 하고 기존 배열과는 다른 새로운 배열을 만든다. 이렇게 되면, 원본 배열은 유지가 된다.

 

Pure Function을 사용하는 이유는?

  • 클린 코드를 위해서
  • 테스트를 쉽게하기 위해서
  • 디버그를 쉽게하기 위해서
  • 독립적인 코드를 위해서 ( Decoupled / Independent )

결론적으로, 프로젝트를 생성하기 위해서 Impure 함수도 당연히 필요하다. 하지만, 그래도 순수 함수를 사용하면,

1. 특정 함수가 다른 함수에 미치는 예기치 못한 영향을 최소화 하고

2. 또한 함수를 만들고 실행할 때 어떤 결괏값을 리턴할지 예측할 수 있다는 장점이 있기에

 

Pure 함수로 처리할 수 있다고 생각되는 부분최대한 Pure 함수로 만들어서 사용할 수 있도록 노력하는게 추천된다.


< 커링(Curry Function) >

커링(Currying)은 

- 함수와 함께 사용하는 고급기술이다.

- 이 기술은 오직 자바스크립트에만 존재하는 것이 아닌 다른 언어에도 존재한다.

 

커링은 f(a,b,c) 처럼 단일 호출로 처리하는 함수를 f(a)(b)(c) 와 같이 각각의 인수가 호출 가능한 프로세스로 호출된 후 병합될 수 있게 변환하는 것이다. 커링함수를 호출하는 것이 아닌 변환하는 것이다.

 

예시를 살펴보자.

const sum = (x,y) => x + y;

const curriedSum = x => y => x + y;

console.log(sum(10,20)); // 30
console.log(curriedSum(10)); // y => x + y
console.log(curriedSum(10)(20)); // 30

const tenPlus = curriedSum(10);
console.log(tenPlus);  // y => x + y
console.log(tenPlus(100)); // 110

좀 더 예를 들어보자.

const makeFood = (ingredient1) => {
    return (ingredient2) => {
        return (ingredient3) => {
            return `${ingredient1}, ${ingredient2}, ${ingredient3}`;
        }
    }
}

const hamburger = makeFood("Bread")("Patty")("Lettuce")
console.log(hamburger);

3개 인수를 다 넣어줘야지 ingredient가 다 나온다. 두 개만 호출한다면, 

위 사진처럼, ingredient3 도 필요하다는 걸 알려주고 있다.

해당 코드를 더 깔끔하게 하려면, 아래와 같이 표현할 수 있다.

const cleanMakeFood = ingredient1 => ingredient2 => ingredient3 => 
  `${ingredient1}, ${ingredient2}, ${ingredient3}`;

const hamburger = cleanMakeFood("Bread")("Patty")("Lettuce")
console.log(hamburger);

 

결과는 두 코드 모두 다 아래와 같이 나온다.

 

항상 같은 값을 가지는 값을 고정한채로 나머지 인수만 줘도 된다.

예를 들어 아래와 같은 코드가 있다고 해보자.

function log(date, importance, message) {
        alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
    }

function curry(f) { // 커링 변환을 하는 curry(f) 함수
    return function (a) {
        return function (b) {
            return function (c) {
                return f(a, b, c);
            }
        };
    };
}

const curriedLog = curry(log);
curriedLog(new Date())("DEBUG")("some debug");

// logNow 는 log 의 첫 번째 인수가 고정된 partial이 된다.
let logNow = curriedLog(new Date());
// use it
logNow("INFO", "message"); // [HH:mm] INFO message

여기서 logNow는 log의 첫번째 인수를 newDate()로 고정한 것이다. 이는 'partially 적용된 함수' 또는 짧게 말하면 'partial' 이라고 한다.

logNow

 

그렇다면, 매개변수가 3개가 아니고 매개변수가 4개, 5개, 6개... 쭉 늘어나면 계속해서 함수를 고쳐야하는 것일까?

커링 변환할 때 다이나믹하게 처리할 수 있는 방법을 알아보자!

 

(ex1) 파라미터가 2개일 때,...

const sum = (x,y) => x + y;
function curry(f) {
    return function(a){
        return function(b){
            return f(a,b);
        };
    };
}
curry(sum);

 

(ex2) 파라미터가 3개일 때,...

const sum = (x,y) => x + y;
function curry(f) {
    return function(a){
        return function(b){
            return function(c){
                return f(a,b,c);
            };
        };
    };
}
curry(sum);

 

매개변수가 이렇게 계속 늘어나면 함수를 계속 바꿔줘야 하는 것일까? 아래와 같은 함수를 사용하면 그럴 필요없다.

파라미터가 몇 개 인지 상관 없이 한 번에 처리하려면?

아래와 같은 함수를 다 해석하려고 하기 보다는 이 curry 함수를 이용하면 매개변수가 몇개이든 어떠한 함수든 curry가 된 함수로 바꿔줄 수 있다는 것을 알면 된다.

const sum = (x, y, z, j) => x + y + z + j;
function curry(func) {

    return function curried(...args) {
        if (args.length >= func.length) {
            return func.apply(this, args);
        } else {
            return function (...args2) {
                return curried.apply(this, args.concat(args2));
            }
        }
    };

}
const curried = curry(sum);
console.log(curried(1)(2)(3)(4));

1,2,3,4
1,2,3,4,5

 

이렇듯, 매개변수를 호출할 때 추가만 해주면, 따로 curry 함수를 고치지 않아도 처리가 가능하다.


< strict mode(엄격모드) >

ECMAScript 5에서 소개된 JavaScript의 엄격모드는 JavaScript의 제한된 버전을 선택하여 암묵적인 "느슨한 모드(sloppy mode)" 를 해결하기 위한 방법이다.

엄격 모드는 평범한 자바스크립트 시맨틱스에 몇 가지 변경이 일어나게 한다.

 

1. 기존에는 조용히 무시되던 에러들을 throwing 한다.

2. 자바스크립트 엔진의 최적화 작업을 어렵게 만드는 실수들을 바로잡는다. 가끔씩 엄격 모드의 코드는 비-엄격 모드의 동일한 코드보다 더 빨리 작동하도록 만들어진다.

 

※ strict mode 적용 방법

1) 파일에 'use strict' 지시자 입력

"use strice"

 

이렇게 지시자만 이용하면, 파일 자체가 바로 느슨한 모드에서 스트릭트 모드로 된다.

 

2) 함수 안에 'use strict' 사용해서 그 함수만을 위해서 strict mode 적용

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

 

함수 내부에  'use strict' 를 사용함으로써 해당 함수만 엄격한 모드가 되도록 할 수 있다.

 

3) class를 사용하면 자동으로 strict mode 가 적용

class Dog{

}

 

클래스는 strict mode 이다.

 

4) 자바스크립트 파일의 타입을 Module로 사용하면, strict mode가 적용

<script src = "script.js" type="module">

 

그렇다면, strict mode 의 특징에 대해서 살펴보자.

[ sloppy mode 와 strict mode 의 비교 ]

(1)

let greeting = 'Hello';

greating = "How are you?"; // greating으로 일부러 오타를 낸다면?

console.log(greeting);

greeting이 제대로 출력

실행을 해보면, 아무런 에러없이 그냥 greeting이 출력되는 것을 확인할 수 있다.

하지만, strict mode 에서는 엄격하게 greating is not defined 에러가 난다.

"use strict"

let greeting = 'Hello';

greating = "How are you?"; // greating으로 일부러 오타를 낸다면?

console.log(greeting);

greating is not defined

(2)

let greeting = 'Hello';

greating = "How are you?"; // greating으로 일부러 오타를 낸다면?

console.log(greeting);
console.log(greeting, window.greating);

자동적으로 window 객체에 속성으로 할당

실행을 해보면, window.greating을 하면, 자동적으로 greating은 윈도우 객체에 속성을 할당되어서 잘 출력된다.

'use strict';

let greeting = 'Hello';

greating = "How are you?"; // greating으로 일부러 오타를 낸다면?

console.log(greeting);
console.log(greeting, window.greating);

greating is not defined

(3)

undefined = 8
NaN = 10;

console.log(undefined);
console.log(NaN);

 

아무런 에러가 안 난다.

실행을 해보면, undefined 값과 NaN 등에 다른 값을 할당해도 아무런 에러 없이 undefined, NaN 이 각각 출력된다.

'use strict';

undefined = 8
NaN = 10;

console.log(undefined);
console.log(NaN);

Cannot assign to read only property 'undefined'

strict mode 에서는 Undefined 에 할당을 할 수가 없고, NaN 에도 할당할 수 없으니까, 위와 같이 에러가 올바르게 나온 것이다.

 

(4)

const obj = {};

Object.defineProperty(obj, "readOnly", {
    writable: false, value: 7
})

console.log(obj);

obj.readOnly = 10;  // 10으로 변경 시도

console.log(obj);

readOnly이기에 값 변경 x

 

실행을 해보면, 값이 readOnly이기 때문에, writable이 false라서 값이 안 바뀐다.

'use strict'

const obj = {};

Object.defineProperty(obj, "readOnly", {
    writable: false, value: 7
})

console.log(obj);

obj.readOnly = 10;  // 10으로 변경 시도

console.log(obj);

strict mode 에서는 값 변경 시도조차 오류

 

할당할 수 없는 것에 할당을 하려고 하니까 에러가 나는 것이다.

 

(5)

const obj = {
    get readOnly(){
        return 7;
    }
}

console.log(obj.readOnly);

obj.readOnly = 10;

console.log(obj.readOnly);

get에서도 readOnly니까 변경 x

'use strict'

const obj = {
    get readOnly(){
        return 7;
    }
}

console.log(obj.readOnly);

obj.readOnly = 10;

console.log(obj.readOnly);

strict mode에서는 역시 에러가 난다.

 

getter 도 setter 가 아니니까 얘는 수정을 할 수가 없기 때문에, 값 변경 시도시 에러가 난다.

 

(6)

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

console.log(add(1,2,3));

제대로 나온다.

 

실행을 해보면, a라는 매개변수가 중복되었는데도, 잘 인식해서 결과가 제대로 나온다.

'use strict'

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

console.log(add(1,2,3));

strict mode에서는 파라미터 중복을 불허한다.

(7)

"string".prop = 7;

console.log("string".prop);

undefined

실행을 해보면, attr()과 비슷하게 속성의 값을 가져오는 prop()은 true 혹은 false 로 반환하는데, string에 prop()에 7을 넣을 수가 없으니까 undefined가 나온다.

'use strict'

"string".prop = 7;

console.log("string".prop);

strict mode에서는 error가 뜬다.

(8)

function sum(a,b){
    console.log(this);
    return a + b;
}

console.log(this);
sum(1,2);

 

function 함수 내부의 this는 윈도우 객체를 가리키고 script scope에서의 this도 윈도우를 가리킨다.

'use strict'

function sum(a,b){
    console.log(this);
    return a + b;
}

console.log(this);
sum(1,2);

함수 내부의 this는 undefined

console.log(this)는 윈도우 객체를 가리키게 되지만, 

sum(1,2)를 타고 들어가서 호출되는 console.log(this)는 undefined 를 출력한다.

그럼, strict mode 에서도 함수 내부의 this가 객체를 가리키게 하려면 어떻게 해야 할까?

이 때, 바로 bind(), call(), apply()를 사용하면 된다.

'use strict'

function sum(a,b){
    console.log(this);
    return a + b;
}

console.log(this);
sum.bind(this)(1,2); // bind 한 것을 호출

sum 내부의 this도 window객체를 가리킨다.

(9)

function sum(a,b) {
    a = 10
    return [a+b, arguments[0] + arguments[1]];
}

console.log(sum(1,2));

 sloppy mode에서는 알아서 인식해서 [12,12] 로 출력되지만, strict mode에서는 [12,3] 으로 제대로 출력된다.

'use strict'

function sum(a,b) {
    a = 10
    return [a+b, arguments[0] + arguments[1]];
}

console.log(sum(1,2));

strict mode에서는 제대로 인자를 인식


참고 자료

따라하며 배우는 자바스크립트 A-Z

반응형