[JS] ES2022 신기능 중 4가지

[JS] ES2022 신기능 중 4가지

이채현

노션에서 보기

Top level await

기존 await를 사용하려면 async 함수 내에서만 가능했다.

1
2
3
(async function () {
await foo();
})();

하지만, ES2022부터 이러한 규칙이 사라지고, awaitasync함수없이 모듈에서 아래와 같이 작성가능해졌다.

1
await foo();

Error Cause

이 기능을 통해 오류의 원인을 설명하여, 더 나은 오류 메시지를 만들 수 있다.

기존 오류를 만들 때는 오류 메시지를 작성하는 것 밖에 할 수 없었다.

1
new Error("This is the Error Message!");

하지만 ES2022부터 무엇이 오류를 발생시켰는지에 대해 설명할 수 있다. 그래서 정확히 무엇이 잘못되었는지 구체적으로 알 수 있으며, 동일한 오류메시지를 사용하지만 다른 원인을 작성할 수 있다.

또한, .cause를 액세스할 수 있다.

1
2
3
4
const err = new Error("This is the Error Message!", { cause: "Test Message" });

err.message; // This is the Error Message!
err.cause; // Test Message

.at()

.at을 활용하면, 배열의 모든 인덱스에 액세스할 수 있다.

1
2
3
const number = ["1", "2", "3", "4", "5"];

number.at(2); // 2

이전에도 대괄호를 사용하여 액세스할 수 있었지만, 대괄호와의 차이점은 뒤로 검색가능하다는 점이다. 대괄호는 -1 로 검색할 수 없었지만, .at을 통하면 가능하다.

1
2
3
4
5
const number = ["1", "2", "3", "4", "5"];

number.at(2); // 2
nubmer.at(-1); // 5
~~number[-1]; // 불가능~~

Class Fields

이것을 통해, 자바스크립트가 조금 더 OOP스럽게 느껴지게 한다. 이전에는 불가능했던 Private 메서드 및 속성을 가질 수 있으며, static 메서드를 사용할 수 있다.

그리고 속성을 초기화하기 위해 constructor를 사용할 필요도 없어진다.

Private 메서드 및 속성

private 메서드나 속성을 만들려면 이름 앞에 # 기호를 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
class Message {
#destruct() {
console.log("booom!!");
}
}

const but = new Message();
~~btn.#destruct(); // 작동하지 않는다~~

class Message {
#text = "Hi";
}

위 코드처럼 private한 메서드 및 텍스트를 만들 수 있으며, constructor를 사용하지 않는다.

1
2
3
4
5
class Message {
constructor() {
this.text = "Hi";
}
}

Static 메서드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Message {
// body
}

Message.build(){
// body
}

====

class Message {
static build() {
// body
}
}

출처

방금 출시된 ⚡️자바스크립트 미친 신기능 4개!

[JS] ESLint 알고쓰기 : 설정 설명

[JS] ESLint 알고쓰기 : 설정 설명

이채현

노션 링크

이 문서는 eslint.org를 참고하여 eslint 7.32.0 버전에서 작성되었으며, 아래 프로젝트를 기반으로 작성했습니다.

https://github.com/chlee1001/react-typescript-simple-boilerplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"airbnb",
"airbnb-typescript",
"airbnb/hooks",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
"./tsconfig.json"
],
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint",
"import"
],
"rules": {
"import/prefer-default-export": "off",
"import/no-unresolved": 0,
"import/extensions": [
"off"
],
"react/function-component-definition": [
2,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
]
},
"ignorePatterns": [
"paths.js",
"webpack.*.js",
"dist/*",
"node_modules/*"
],
"settings": {
"react": {
"version": "detect"
}
}
}

ENV

  • browser - browser global variables : true를 하게되면 **console.log()**를 에러없이 사용할 수 있다.
  • node - Node.js global variables and Node.js scoping : true를 하게되면 전역에서 require를 에러없이 사용할 수 있게된다.
  • es2021 - adds all ECMAScript 2021 globals and automatically sets the ecmaVersion parser option to 12.

EXTENDS

extends는 추가한 플러그인에서 사용할 규칙을 설정한다. 플러그인을 설치하여도, 플러그인은 일련의 규칙집합이며 플러그인을 추가하여도 규칙은 적용되지 않는다. 규칙을 적용하기 위해서는 추가한 플러그인 중, 사용할 규칙을 extends 내에 추가해야한다. 보통 대부분의 플러그인은 recommendedstrict, all 등의 자체 설정을 제공한다.

  • recommended: 프로젝트에 권장하는 규칙 집합
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
"extends": [
"airbnb", // airbnb의 규칙 사용
"airbnb-typescript", // TS를 지원하는 airbnb 규칙 구성 향상
"airbnb/hooks", // React hooks를 위한 airbnb 규칙사용
"plugin:@typescript-eslint/recommended", // ESLint가 TypeScript를 지원할 수 있도록 하는 모든 도구를 위한 Monorepo
"plugin:@typescript-eslint/recommended-requiring-type-checking", // 일부 highly valuable rules를 올바르게 구현하기 위해 유형 검사를 위한 추천 요구 유형 검사
"plugin:import/recommended", // import명이나 잘못 작성한 파일 경로에 대한 이슈를 방지해주는 플러그인 (아래 errors와 warnings의 집합)
// "plugin:import/errors",
// "plugin:import/warnings",
"plugin:import/typescript", // TS에서 `eslint-plugin-import`를 사용하기 위해 추가
"plugin:jsx-a11y/recommended", // JSX 요소에 대한 접근성 규칙
"plugin:prettier/recommended", // prettier 규칙을 적용하여 틀릴 경우 eslint 문제로 처리
"plugin:react/recommended", // eslint-plugin-react의 추천 규칙 사용
"plugin:react-hooks/recommended"
],
...

PARSER

코드를 분석하기 위한 파싱툴이다. 기본값은 espress이고, 보통 js 워크스페이스에서는 @babel/eslint-parser를 사용하고 ts 워크스페이스인 경우 @typescript-eslint/parser를 사용한다. 사실 plugin:@typescript-eslint/recommended를 포함시키면 @typescript-eslint/parser가 자동으로 포함되기도 한다.

1
"parser": "@typescript-eslint/parser" 

PARSER OPTIONS

parserOptions은 ESLint 사용을 위해 지원하려는 Javascript 언어 옵션을 지정할 수 있습니다.

  • project: 이 옵션을 사용하면 제공된 tsconfig에서 정의한 프로젝트에 포함되지 않은 파일이 허용되도록 요청할 수 있다.
  • ecmaVersion: 사용할 ECMAScript 버전을 설정
  • sourceType: parser의 export 형태를 설정
  • ecmaFeatures: ECMAScript의 언어 확장 기능을 설정
    • globalReturn: 전역 스코프의 사용 여부 (node, commonjs 환경에서 최상위 스코프는 module)
    • impliedStric: strict mode 사용 여부
    • jsx: ECMScript 규격의 JSX 사용 여부
1
2
3
4
5
6
7
8
9
10
"parserOptions": {
"project": [
"./tsconfig.json"
],
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},

PLUGIN

플러그인 패키지를 설치하고, 해당 플러그인을 plugins에 추가하여 사용할 수 있다.

1
2
3
4
5
"plugins": [
"react",
"@typescript-eslint",
"import"
],

RULES

ESLint에는 프로젝트에서 사용하는 규칙을 수정할 수 있다. 규칙을 변경하는 경우, 다음과 같은 방법으로 설정해야한다.

  • "off" 또는 0: 규칙을 사용하지 않음
  • "warn" 또는 1: 규칙을 경고로 사용
  • "error” 또는 2: 규칙을 오류로 사용

규칙에 추가 옵션이 있는 경우에는 배열 리터럴 구문을 사용하여 지정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"rules": {
"import/prefer-default-export": "off",
"import/no-unresolved": 0,
"import/extensions": [
"off"
],
"react/function-component-definition": [
2,
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
]
}

규칙 무시하기

파일 디렉토리 제외

ignorePatterns 필드 또는 .eslintignore 파일을 작성하여 파일 및 디렉토리를 제외하도록 지정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// .eslintrc 파일 ignorePatterns 설정

"ignorePatterns": [
"paths.js",
"webpack.*.js",
"dist/*",
"node_modules/*"
],

//.eslintignore 파일 생성
config/
dist/
node_modules/

대체파일 사용

.eslintignore를 현재 작업 디렉토리가 아닌 다른 파일을 사용하려면 --ignore-path 옵션을 사용하여 명령행에 파일을 지정할 수 있다.

1
$ eslint --ignore-path .gitignore file.js

인라인으로 규칙 비활성화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
**// 전체 파일 규칙 경고 비활성화, 파일 맨위에 아래 블록 주석 추가**
/* eslint-disable */
...
...
/* eslint-enable no-alert, no-console */

**// 경고 비활성화 블록 주석**
/* eslint-disable */
alert('foo');
/* eslint-enable */

**// 특정 규칙 경고 비활성화**
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');

**// 다음 한줄 경고 비활성화**
// eslint-disable-next-line

참고

Configuring ESLint - ESLint - Pluggable JavaScript Linter

https://velog.io/@kyusung/eslint-config-2

ESLint 알고 쓰기

[JS] 선언한 모듈로 이동하기 (alias) - Go to declaration

[JS] 선언한 모듈로 이동하기 (alias) - Go to declaration

이채현

문제

많은 사람들은 선언한 모듈들을 command/ctrl + click으로 해당 파일로 바로 이동하거나 자동완성이 되게하는 IDE나 Editor의 기능을 사용할 것이다. 그리고 babel-plugin-module-resolver을 통해 모듈의 경로를 별칭으로 바꿔서 사용할 것이다. 하지만 별칭으로 바꾸면서 위 기능이 깨지는 문제가 종종 있다. 그리고 이 문제는 플러그인쪽에서는 해결되지 않고 있다. npm에 올라온 최신버전은 이미 2년이 지났다.

babel-plugin-module-resolver

해결

우리는 jsconfig.json을 사용하여 IDE가 사용자 지정 resolve규칙을 따르도록 하는 것이 좋다. 이 접근 방식은 WebstormVS Code 모두 작동한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#api/*": [
"./src/api/*"
],
"#assets/*": [
"./src/assets/*"
],
"#common/*": [
"./src/common/*"
],
"#component/*": [
"./src/component/*"
],
"#constant/*": [
"./src/constant/*"
],
"#container/*": [
"./src/container/*"
]
}
}
}
[JS] babelrc와 webpack.config

[JS] babelrc와 webpack.config

이채현

Webpack으로 React 프로젝트를 초기 설정하다가 ,

1
2
3
4
5
6
7
8
9
10
11
12
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 5% in KR', 'last 2 chrome versions'],
},
debug: true,
},
],
'@babel/preset-react',
],

위 코드의 presets가 과연 .babelrc에 있어야 하는지, webpack.config.js에 있어야하는지 잘 모르겠어서 각 파일의 목적을 정리해보았다.

babelrc

.babelrcbabel의 설정을 위해 사용한다.

1
2
3
4
{
"presets": [...],
"plugins": [...]
}

webpack.config

물론 webpack.config.jswebpack의 설정을 위해 사용한다. 프로젝트 파일의 번들링과 관련된 설정들을 작성해준다. 그리고 babel과 관련된 설정들을 .babelrc가 아닌 webpack.config.js에서 babel-loader를 설정한 부분에 작성해줄 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...

module.exports = {

...

module: {
rules: [
{
test: /\\.js?/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 5% in KR', 'last 2 chrome versions'],
},
debug:true,
},
],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-proposal-class-properties',
'react-refresh/babel',
[
'module-resolver',
{
root: ['./src'],
alias: {
'#api': './src/api/',
'#assets': './src/asset/',
'#common': './src/common/',
'#component': './src/component/',
'#constant': './src/constant/',
'#container': './src/container/',
},
},
],
],
exclude: /node_modules/,
},
},
],
},

...

}

결론

결론은, babelpresetswebpack.config.js.babelrc 파일 둘 중 한 곳에만 있으면 된다! 그러나 babel cli를 이용하여 직접 코드 변환을 수행하거나 babel test 등을 돌릴 때에는 webpack을 거치지 않기 때문에 .babelrc에 작성하는 방식이 권장된다.

나는 webpack.config.js 내에 적어서 사용한다.

[JS] Babel로 별칭 경로 설정하기

[JS] Babel로 별칭 경로 설정하기

이채현

프로젝트의 규모가 커지면 디렉토리 구조도 복잡해진다. 그 때문에 아래와 같이 컴포넌트의 위치를 찾기 어려워진다.

1
import { whereIsThis } from "../../../../../aaa/bbb/ccc";

위와 같이 작성한 것을 상대경로라고 한다. 상대 경로를 사용해서 모듈을 불러오면 모듈이 어느 경로에 위치하는지 파악하기가 난해해지는 경우가 생긴다. 뿐만 아니라, 이 자바스크립트 파일을 다른 디렉토리로 옮기려면 상대 경로를 그에 따라 모두 수정해줘야 해서 코드 리펙토링(refactoring)이 상당히 불편하다.

물론 절대경로를 사용하면 되지 않을까 생각할 수 있지만, 개발자들마다 해당 프로젝트를 다른 디렉토리에 저장해놓을 것이기 때문에 현실적으로 적용하기 어려운 방법이다.

별칭 경로

위와 같은 문제는 자바스크립트 트랜스파일(transpile) 도구인 Babel(바벨)을 사용하면 이 문제를 비교적 간단하게 해결할 수 있습니다.

Babel의 플러그인을 사용해서 별칭(alias) 경로를 설정해주면 된다.

1
$ yarn add -D babel-plugin-module-resolver

Babel의 module resolver 플러그인을 개발 의존성으로 설치 후, .babelrc설정 파일을 열고, plugins항목에 module-resolver설정을 추가해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
presets: ['@babel/preset-env', ...],
plugins: [
...
[
'module-resolver',
{
root: ['./src'],
alias: {
'#api': './src/api/',
'#assets': './src/asset/',
'#common': './src/common/',
'#component': './src/component/',
'#constant': './src/constant/',
'#container': './src/container/',
},
},
],
...
],

alias 부분에서 ./src/api#api로 표기함에 따라

1
2
3
4
5
import { alias } from "./src/api/.../alias";

// 위 코드를 아래와 같이 작성할 수 있습니다.

import { alias } from "#api/alias";

마치면서

이상으로 Babel의 module resolver 플러그인을 이용한 별칭 경로 설정 방법이였습니다.

만약 본인이 Webpack 설정과 겹쳐 고민이 있다면 다음 글[JS] babelrc와 webpack.config을 참고해주세요.

[JS] 클로저 간단 정리

[JS] 클로저 간단 정리

이채현

  • 클로저는 먼저 자바스크립트 변수의 유효범위를 이해해야한다.
  • 클로저를 명확히 무엇이다라고 말하기는 어렵다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function returnX(){
return 'x';
}

const x = returnX()
console.log(typeof x) // string

----------------------------------------------

function returnX() {
let x = 'x';
return function returnY() {
return x + 'y';
}
}

const x = returnX()
console.log(typeof x) // function => return 값이 함수 덩어리이기 때문에

const x = returnX()();
console.log(typeof x) // string
function sum(num1) {
return function (num2) {
return num1 + num2;
};
}

const sum5 = sum(5); // 숫자5가 계속 바인딩되어 있는 상태
console.log(sum5(10)); // 15

은닉화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function privateData() {
let temp = 'a';
return temp;
}

const result = privateData(); // privateData를 실행시켜야만 temp값을 알 수 있다.
console.log(result);

-------------------------------------

function privateData() {
let temp = 'a';
return {
value: () => {
return temp;
},
changeValue: (newVal) => {
temp = newVal;
}
};
}

const private = privateData();
console.log(private.value()); // a
private.changeValue('b');
console.log(private.value()); // b

활용사례

  • 고민해봤을 때 debounce와 throttle에서 …사용

    • debounce: 어떤 이벤트를 실행할 때 과하게 실행되는 것을 지연시켜주는 역할 (클릭지연..무한스크롤 지연)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    buttonElement.addEventListener(
    'click',
    debounce(handleClick, 500),
    )

    function debounce(func, timeout = 300) {
    let timer;

    return (...args) => {
    clearTimeout(timer);

    timer = setTimeout(() => {
    func.apply(this, args);
    })
    }
    }
[JS] Class 간단 정리

[JS] Class 간단 정리

이채현

클래스

  • class 선언은 프로토타입 기반 상속을 사용
  • 정의: 함수 정의방법과 동일하게 가능, 함수 표현식과 함수 선언을 class표현식에서 사용 가능
1
2
3
4
5
6
7
8
9
10
11
function Person(name, age) {
this.name = name;
this.age = age;
}

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}

인스턴스

  • 싱글리터럴로 만든 객체도 각자의 인스턴스를 뜻함..객체이지만 인스턴스
  • 생성자 함수와 클래스를 활용하여…new 연산자와 더불어 만듬
1
2
3
4
5
6
function Func() {} // 생성자함수의 이름은 Pascal case로..

class Class {}

const newInstance = new Func();
const newInstance2 = new Class();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Person(name, age) {
this.name = name;
this.age = age;
this.location = location;
}

Person.prototype.getName = function () {
return this.name + ' 입니다.';
}

=============================================

class Person {
constructor(name, age) {
this.name = name;
this.age = age;
this.location = location;
}

getName() {
return this.name + ' 입니다.';
}
}

const one = new Person('one', 1, 'Korea');
const two = new Person('two', 2, 'Korea');

console.log(one.getName()); // one 입니다.
  • 클래스는 뿐만 아니라 Private키워드, 정적메서드 등 수 많은 기능을 제공

클래스 확장 (extends, 상속)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Super Class
class Animal {
constructor(name, sound) {
this.name = name
this.sound = sound;
}

getInfo() {
return this.name + '가(이)' + this.sound + '소리를 낸다.';
}
}
// Sub Class
class Friends extends Animal {
constructor(name, sound) {
super(name, sound); // 부모의 생성자함수를 호출가능
}
}

const dog = new Friends('개', '멍멍');
const cat = new Friends('고양이', '냐옹');

console.log(dog.getInfo()); // 개가(이)멍멍소리를 낸다.
console.log(cat.getInfo()); // 고양이가(이)냐옹소리를 낸다.

-------------------------------------------------

dog.contructor.name // Friends
cat.contructor.name // Friends

dog instanceof Friends // true
dog instanceof Animal // true
[JS] 프로토타입 간단 정리

[JS] 프로토타입 간단 정리

이채현

자바스크립트는 프로토타입 기반의 언어다.

constructor (생성자)

1
2
3
4
5
6
7
8
9
10
function Person(name, age) {
this.name = name;
this.age = age;
}

class Paerson {
constructor() {

}
}

생성자함수는 프로토타입이 모든 자바스크립트에 들어있듯이 생성자도 모든 자바스크립트에서 확인가능하다.

1
2
3
4
5
const one = new Person('one', 1);
const two = new Person('two', 2);

console.log(one.constructor); // [Function: Person]
console.log(two.constructor.name); // Person

어떠한 생성자로부터 생성되었는지 유추할 수 있다.

instanceof로 식별

object instanceof constructor

proto

브라우저에서 비표준으로 제공했던…

1
array.__proto__ ...로 array의 프로토타입에 접근

자바스크립트의 프로토타입에 직접 접근이 아니라 접근제어자로 접근할 수 있도록 도와주는 것으로 생각하면 됨. ⇒ 하지만 사용하지 않는 것이 좋음

ECMA Script2015부터는 표준화 된

  • getPrototypeOf()
  • setPrototypeOf()

를 사용하는 것을 추천

프로토타입 체인

1
2
3
4
5
6
7
8
9
const animal = {
sayName() {
return 'ANIMAL';
}
}

console.log(animal.sayName()); // ANIMAL
const dog = Object.create(animal);
console.log(dog.sayName()); // ANIMAL

프로토타입 확장 (extends, 상속)

부모 ⇒ 자식 … 상속보단 확장이란 개념이 더 이해하기 쉽다. 부모가 가진 기능보다 자식이 더 많이 가질 수 있기 때문

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Super Class
function Animal(name, sound) {
this.name = name
this.sound = sound;
}

Animal.prototype.getInfo = function () {
return this.name + '가(이)' + this.sound + '소리를 낸다.';
}

// Sub Class
function Friends(name, sound) {
Animal.call(this, name, sound); // 명시적 바인딩 -> Animal함수의 this를 Friends로 바인딩
}

Friends.prototype = Object.create(Animal.prototype);
Friends.prototype.constructor = Friends;

const dog = new Friends('개', '멍멍');
const cat = new Friends('고양이', '냐옹');

console.log(dog.getInfo()); // 개가(이)멍멍소리를 낸다.
console.log(cat.getInfo()); // 고양이가(이)냐옹소리를 낸다.

-------

dog.contructor.name // Friends

dog instanceof Friends // true
dog instanceof Animal // true
[JS] this 간단 정리

[JS] this 간단 정리

이채현

JavaScript에서 함수의 this 키워드는 다른 언어와 조금 다르게 동작한다.

엄격모드와 비엄격 모드에서도 일부 차이가 있다.

  • this는 scope와 관계가 있다.
  • 객체에도 영향을 준다.
  • this가 어디에 묶여있냐를 아는 것이 코드를 작성하는 시점, 동작하는 시점에 차이가 있을 수 있다.

(함수를 어떻게 호출했는지 상관하지 않고 this값을 설정할 수 있는 bind메서드를 도입했고, ES2015는 스스로의 this 바인딩을 제공하지 않는 화살표 함수 를 추가했습니다.)

암시적 바인딩

암시적인 this 바인딩.. 사용자가 생각하지 않은대로 동작할 수 있다.

전역 공간에서의 this

  • node.js 환경에서의 this는 global
  • 브라우저에서의 this는 window

함수

  • 함수에서의 this는 window ⇒ 전역공간에서의 this와 다르지 않다.

객체 (메서드)

  • this는 호출되는 대상의 객체를 가리키고 있다.
1
2
3
4
5
6
7
8
const obj = {
name: 'obj',
method: function() {
return this.name
}
}

obj.method() // 'obj'

명시적 바인딩

  • call(), bind(), apply()
1
2
3
4
5
6
7
8
9
10
11
12
13
const person = {
name: 'Lee',
sayName: function () {
return this.name + '입니다';
}
}

const zero = {
name: '베이스',
sayName: function () {
return this.name + '입니다';
}
}
  • call()
1
2
3
4
5
function sayFullName(firstName) {
return firstName + this.sayName()
}
const result = sayFullName.call(person, 'Chaehyeon ');
// Chaehyeon Lee입니다.
  • apply()
1
2
3
4
5
6
function sayFullName(firstName) {
return arguments[1] + this.sayName()
}

const result = sayFullName.apply(person, ['Chaehyeon ','채현 ']);
// 채현 Lee입니다.
  • bind()
    • this를 묶어서 사용가능한다.

    • React Class Component에서 사용했다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      function sayFullName(firstName) {
      return firstName + this.sayName()
      }

      const sayFullNamePerson = sayFullName.bind(person);
      const sayFullNameZero = sayFullName.bind(zero);
      console.log(sayFullNamePerson('Chaehyeon'));

      // ChaehyeonLee입니다
[JS] 스코프 간단 정리

[JS] 스코프 간단 정리

이채현

전역 스코프 (Global)

  • 그냥 가장 바깥쪽
  • 언제 어디서나 접근 가능하기 때문에 재정의가 가능하다 ← 큰 문제
    • 그 결과, 프로그램의 실행 결과 때 내가 만든 변수들의 결과를 예측하기 어려워짐 → 팀 단위로 개발할 때 최악

지역 스코프

함수 스코프

블록 스코프

1
2
3
4
5
6
7
8
9
{
// 블록
}

function func() { // 함수 스코프 블록
}

if (true) { // 블록 스코프 블록
}

전역 객체

브라우저

⇒ window

NodeJS

⇒ Global

// this

  • 브라우저에서 호출하면 window불러옴

호이스팅 (Hoisting)

1
2
3
4
5
6
7
8
9
function foo() {
console.log(hoist); // undefined

var hoist = '호이스팅';

console.log(hoist); // 호이스팅
}

foo();
  • 첫번 째 console.log가 오류나지 않는 이유는

    • 변수 선언을 직접적으로 끌어올림
    • 그래서 위 코드와 아래 코드랑 같다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function foo() {
    var hoist; // 1. 변수 선언
    console.log(hoist); // undefined // 2. 실행

    hoist = '호이스팅'; // 3. 재할당
    console.log(hoist); // 호이스팅
    }

    foo();

애초부터 var를 안쓰면 된다.

1
2
3
4
5
6
7
8
9
function foo() {
console.log(hoist); // Cannnot access 'hoist' before initialization

let/const hoist = '호이스팅';

console.log(hoist); // 호이스팅
}

foo(); // Cannnot access 'hoist' before initialization
  • 임시적 사각지대 (TDZ)가 생긴다.
  • 내부적으로 호이스팅이 일어나지만, 사용자에게는 보이지 않는것처럼 에러를 준다.

IIFE (즉시 실행 함수 표현)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function func() {

}

func();

==>

(function () {

})();

(function (num) {
console.log(num); // 1
})(1);

함수를 괄호안에 넣고 바로 실행

  • 함수 공간을 완전히 분리할 수 있기 때문에 사용한다.
    • 그래서 let/const가 없을 때에 사람들이 외부에서 접근할 수 없게 블록스코프를 흉내내게 사용했다.