[JavaScript] 핵심 개념과 주요 문법

Seungmin Lee·2022년 7월 11일
1

JavaScript

목록 보기
7/14
post-thumbnail

1. 스코프(Scope)

JavaScript에서 스코프는 변수의 유효범위로 사용된다.

1-1. 스코프의 정의와 규칙

규칙 1) 안쪽 스코프의 변수는 바깥쪽 스코프에서 사용할 수 없다.

  • 바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능하지만 안쪽 스코프에서 선언한 변수는 바깥쪽 스코프에서 사용 할 수 없다.

규칙 2) 스코프는 중첩이 가능하다.

  • 스코프는 중첩이 가능하다.

규칙 3) 전역 스코프(Global scope)

  • 가장 바깥쪽의 스코프는 특별히 전역 스코프(Global scope)라 하고 전역이 아닌 다른 스코프는 모두 지역 스코프(Local scope)이다.

규칙 4) 지역 변수는 더 높은 순위를 가진다.

  • 지역 스코프에서 선언한 변수는 지역 변수, 전역 스코프에서 선언한 변수는 전역 변수라 한다. 이 때, 지역 변수는 전역 변수보다 더 높은 우선 순위를 가진다.
let name = '김코딩'; // 전역 변수

function showName(){
  let name = '박해커'; // 지역 변수
  console.log(name);
}

console.log(name); // 김코딩

showName(); // 박해커 
// 지역변수와 전역변수의 이름이 같지만 지역변수의 우선순위가 높으므로 지역변수 name이 출력
// 동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는 쉐도잉 현상

console.log(name); //김코딩

1-2. 변수 선언과 스코프

1) 스코프의 종류

스코프의 종류에는 블록 스코프(block scope)함수 스코프(function scope)가 있다.

2) 블록 스코프에서 letvar 방식의 차이

///	let으로 선언
for ( let i = 0; i < 5; i++ ){
  console.log(i) // 다섯번 반복
}
console.log('final i:', i); // ReferenceError
// 블록스코프 안에서 정의된 변수 i는 블록 범위를 벗어나는 즉시 접근할수 없음

👉 var 선언 방식은 블록 스코프를 무시하고, 함수 스코프만 따른다. 하지만 화살표 함수의 블록 스코프는 무시하지 않는다.

// var로 선언
for ( var i = 0; i < 5; i++ ){
  console.log(i) // 다섯번 반복
}
console.log('final i:', i); // final i: 5

그냥 let 선언 방식을 사용하자!

3) 그렇다면 const 선언 방식은?

  • let과 동일하게 블록 스코프를 따른다.
  • 값을 새롭게 할당할 일이 없거나, 변하지 않는 값 상수(constant)를 정의할 때에는 const를 권장한다.
  • 값을 재할당할 경우 TypeError가 발생하기 때문에 의도하지 않은 값의 변경을 막을 수 있다.

4) Lexical scope

  • 렉시컬 스코프에 의해 함수가 호출된 위치가 아닌 함수가 선언되는 위치에서 변수가 정해진다.
let num = 1;

function a(){
  let num = 10;
  b()
}

function b(){
  console.log(num);
}

a(); // 1

2. 클로저(Closure)

외부 함수의 변수에 접근할 수 있는 내부 함수를 클로저 함수라고 한다.

2-1. 클로저 함수의 특징

1) 함수를 리턴하는 함수

  • 함수를 리턴하는 함수가 클로저의 형태를 만든다.

2) 리턴하는 함수에 의해 스코프가 구분됨

  • 내부 함수는 외부 함수에 선언된 변수에 접근 가능하다.

3) 데이터를 보존하는 함수

  • 외부함수(adder)의 실행이 끝나더라도, 외부 함수 내 변수(x)를 사용할 수 있다.
// 예제) HTML 문자열 생성기
const tagMaket = tag => content => `<${tag}>${content}</${tag}>`

const divMaker = tagMaker('div');
divMaker('hello') // '<div>hello</div>'

const anchorMaker = tagMaker('a');
anchorMaker('go') // '<a>go</a>'
anchorMaker('urclass') // '<a>urclass</a>'

4) 클로저 모듈 패턴

함수의 재사용성을 극대화하여 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화라고 한다. 즉, 클로저는 모듈화에 유리하다.

  • 클로저를 이용해 내부 함수를 단 하나만 리턴하는 것이 아닌, 객체에 담아 여러개의 내부 함수를 리턴할 수 있다.
  • '외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다'는 규칙에 의해 어떤 경우에도 value직접 수정이 불가능하다. 하지만, 리턴하는 객체가 제공하는 메서드를 통해 간접적 조작은 가능하다.
// 예제) 재활용 가능한 makeCounter 함수
const counter1 = makeCounter();
counter1.increase();
counter1.increase();
counter1.decrease();
counter1.getValue(); // 1

const counter2 = makeCounter();
counter2.decrease();
counter2.decrease();
counter2.decrease();
counter2.getValue(); // -3
  • counter1counter2의 value는 서로에게 영향을 끼치지 않는다.

3. ES6(ECMA Script6) 주요 문법

3-1. spread / rest 문법   IMMUTABLE

1) spread 문법

  • 배열을 풀어서 인자로 전달하거나, 배열을 풀어서 각각의 요소로 넣을때 사용한다.
  • 인자 앞에 ... 을 붙인다.
function sum(x, y, z) {
  return x + y + z;
}
const numbes = [1, 2, 3];
sum(...number) // 6

2) rest 문법

  • 파라미터를 배열의 형태로 받아서 사용할 수 있다.
  • 파라미터의 개수가 가변적일 때 유용하다.
  • 파라미터 앞에 ... 을 붙인다.
function sum(...theArgs) {
  return theArgs.reduce((prev, curr) => {
    return prev + curr;
  });
}
sum(1,2,3) // 6
sum(1,2,3,4) // 10

✍️ reduce(콜백함수, 초기값) 메서드

  • 배열에 대해 주어진 콜백함수를 실행하고, 마지막 콜백의 결과값을 리턴한다.
  • 리턴된 결과값은 prev에 누적된다.
  • prev는 초기값을 제공한 경우에는 초기값이 할당되고, 초기값을 제공하지 않을 경우에는 배열의 첫번째 값이 할당된다.
  • curr에는 초기값을 제공하지 않을 경우 배열의 두번째 값을 할당하고, 초기값을 제공할 경우 배열의 첫번째 값을 할당한다.
    MDN reduce() 메서드

3-2. 배열에서 사용하기

1) 배열 합치기

let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];
console.log(lyrics) // ['head', 'shoulders', 'knees', 'and', 'toes']

let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
console.log(arr1) // [0, 1, 2, 3, 4, 5]

2) 배열 복사 ( arr.slice() 와 유사 )

let arr = [1, 2, 3];
let arr2 = [...arr]; // arr.slice()와 유사
arr2.push(4); // [1, 2, 3, 4] // arr2를 수정해도 arr은 바뀌지 않는다.
console.log(arr) // [1, 2, 3]
console.log(arr2) // [1, 2, 3, 4]

3-3. 객체에서 사용하기

✍️ 키가 같을 경우 뒤의 값으로 덮어 씌워진다. 그렇지 않을 경우, 각각의 키와 값이 모두 그대로 전달된다.

let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };

let clonedObj = { ...obj1 };
let mergedObj = { ...obj1, ...obj2 };
console.log(clonedObj) // { foo: 'bar', x: 42 }
console.log(margedObj) //  { foo: 'baz', x: 42, y: 13 }

3-4. 함수에서 나머지 파라미터 받아오기

function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a);
  console.log("b", b);
  console.log("manyMoreArgs", manyMoreArgs);
}

myFun("one", "two", "three", "four", "five", "six");
// a one
// b two
// manyMoreArgs ["three", "four", "five", "six"]

4. 구조 분해 할당

구조 분해 할당은 spread문법을 이용하여 값을 해체한 후, 개별 값을 변수에 새로 할당하는 과정을 말한다.

4-1. 분해 후 새 변수에 할당

배열

const [a, b, ...rest] = [10, 20, 30, 40, 50]
console.log(a) // 10
console.log(b) // 20
console.log(rest) // [30, 40, 50]

객체

const {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
console.log(a) // 10
console.log(b) // 20
console.log(rest) // {c: 30, d: 40}
// 예제) 함수에서 객체 분해
function whois({
  displayName: displayName, 
  fullName: {firstName: name}
}){
  console.log(displayName + " is " + name);
}

let user = {
  id: 42,
  displayName: "jdoe",
  fullName: {
      firstName: "John",
      lastName: "Doe"
  }
};

whois(user) // jdoe is John
profile
<Profile name="seungmin" role="frontendDeveloper" />

0개의 댓글