[웹 프론트엔드를 위한 자바스크립트 첫 걸음] day3

swimming·2023년 6월 25일
0
post-thumbnail

📁 함수와 지역변수, 외부변수

🖊️ 함수

함수 예시

function add(num1, num2) {
  console.log("함수 호출");
  return num1 + num2;
}
console.log(`두 숫자를 더한 결과는 ${add(10, 15)} 입니다.`); //25

🖍️ Early Return

if/else 대신에 if/return 구조를 사용하여 들여쓰기를 최소한으로 줄이는 패턴이다.
유의점은 조건문의 범위 및 순서를 잘 고려하면서 배치하지 않으면 망한다.

//--------기존에 자주 쓰던 패턴-----------
function func(num) {
  if (num > 0) {
    if (num >= 10) {
      console.log("num의 값이 10보다 크거나 같습니다.");
    } else {
      console.log("num의 값이 0보다 크고 10보다 작습니다.");
    }
  } else if (num === 0) {
    console.log("num의 값 0");
  } else {
    console.log("num의 값이 0보다 작습니다.");
  }
}

func(15);

//-----------[Early Return]-----------

function func(num) {
  if (num === 0) return "num의 값이 0입니다.";
  if (num < 0) return "num의 값이 0보다 작습니다.";
  if (num >= 10) return "num의 값이 10보다 크거나 같습니다.";
  return "num의 값이 0보다 크고 10보다 작습니다. ";
}

console.log(func(15));
//num의 값이 10보다 크거나 같습니다.

🖍️ IIFE =Immediately Invoked Function Expression

즉시 실행 함수는 동시에 즉시 실행되는 함수를 의미한다.

함수 리터럴을 () 로 감싼 뒤
바로 실행하는 형태가 일반적.

(function () { 
  console.log('Hello World');
})(); 
// Hello World
함수 리터럴 자바스크립트에서 함수를 정의하는 표현식을 "함수 리터럴" 이라고 한다. 함수 리터럴은 아래 4개의 요소로 구성된다.
  1. 예약어 function (필수)
  2. 함수이름 (선택)
  3. 매개변수 집합 (필수)
  4. 함수 본문 (필수)

명칭은 거창하지만, 실제로는 일반적으로 다들 알고 있는 자바스크립트의 함수 선언을 위한 문법을 의미한다.

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

아래처럼 이름 없는 함수로 작성하면... 에러 발생.

  function (a, b) { return a + b } // Uncaught SyntaxError: Unexpected token 

함수 이름은 선택사항이라고 했지만, 함수 이름이 없이 정의하는 경우에는 아래 조건이 충족되어야 한다.

  1. 이 함수를 할당 받을 변수를 지정
  2. 이 함수를 즉시 호출.

그러니까, 결국 다음과 같이 되어야 한다

const add = function (a, b) { return a + b };
(function(a, b) { return a + b })(1, 2); // 3

위와 같은 함수 리터럴 표현식을 통해 즉시 실행 함수를 정의할 수 있다.

그리고 즉시 실행 함수라는건 위의 예제코드들처럼
즉시 실행되어 값으로 평가되는 함수를 의미한다.

자바스크립트의 IIFE - doondoony


🖊️ 지역변수, 외부변수

함수는 어디에서 호출되는지에 따라 순서가 달라진다.

  • 지역변수
  • 전역변수





📁 스코프

🖊️ 스코프

범위, 변수 혹은 함수가 갖게 되는 유효범위

스코프 종류

  • 전역 스코프
  • 지역 스코프
  • 함수 스코프
  • 블록 스코프

🖊️ 전역 스코프와 지역 스코프

const num = 10; //전역 스코프

function print() {
  const num = 100; //지역 스코프
  console.log(`지역스코프 : ${num}`); //지역스코프 : 100
}

print();
console.log(`전역스코프 : ${num}`); //전역스코프 : 10

🖊️ 블록 스코프

같은 블록에서만 접근 가능한 범위.
여기서 블록이란, 중괄호{} 내부를 가리킨다.

function print() {
  for (let i = 0; i < 10; i++) {
    console.log(`블록스코프 : ${i}`);
  }
  console.log(i); //ERROR
}

print();


letvar 차이점

let은 같은 이름의 변수를 재선언하면 에러

var는 오류 없이 가장 마지막에 작성된 값으로 변수의 값이 변경된다.

❓ 왜 let 을 이용해 변수 선언하려 하는가

var 로 선언된 변수는 기존에 선언했던 변수는 무시되면서 같은 이름의 변수를 여러번 선언할 수 있기 때문에 더 유연하다.

그러나 자바스크립트 특성 상 특정 변수가 이미 선언되어 있는지 여부를 파악하기 어렵고, 어디서 어떻게 사용되었는지 파악이 힘들어지면서 에러 발생 확률이 높아진다는 치명적인 단점이 존재한다.

고로 중복 선언이 불가능 한 let 선호

let num1 = 10;
var num2 = 20;

num1 = 100;
num2 = 200;

console.log(num1); //100
console.log(num2); //200

//--[case 01: let]----
let num1 = 10;
let num1 = 100;
console.log(num1); //ERROR: SyntaxError

//--[case 02: var]----
var num2 = 20;
var num2 = 200;
console.log(num2); //200

❗️ var는 함수스코프, let은 블록스코프

포괄하는 범위가 다른 걸 느낄 수 있다.

function print() {
  for (var i = 0; i < 10; i++) {
    console.log(`블록스코프 : ${i}`);
  }
  console.log(i); //10
}
print();

그러나 for문 안에 선언된 변수가 var일 경우,
해당 for문이 종료되더라도 같은 함수 내부에서 계속 접근 가능하기 때문에 여러오류 발생 시킬 수 있다.





📁 호이스팅 Hoisting

인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.

이로 인해 변수선언/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상.

var로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화한다.
반면, letconst로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.

console.log(num); //undefined
var num = 10;

// js 엔진이 위의 2줄 코드를 다음과 같이 해석함.
var num; //변수의 선언문만 해당 스코프의 최상단으로 올려 해석하는 방식
console.log(num); //indefined
num = 10;

/* let, const */
console.log(num); //ERROR
let num = 10;

console.log(num); //ERROR
const num = 10;



❗️ 왜 let, const로 선언한 변수는 ERROR 발생하나?

TDZ(Temporal Dead Zone, 일시적인 사각지대) : 변수 사용하는 것을 허용하지 않는 공간

호이스팅이 발생하지 않는 것이 아니라, 변수스코프 맨 위에서 변수의 초기화가 완료될 때까지 TDZ라는 공간에 있기 때문에 호이스팅이 발생하지 않는 것처럼 보인다.

❗️❗️ TDZ에 머물러 있는 이유는?

var는 변수 생성한 후 바로 메모리에 변수의 공간을 미리 할당을 한다. 그러나 letconst는 그렇지 않기 때문에 초기화될 때까지, 메모리 공간이 확보되지 않은 상태가 되어서 해당 키워드로 생성된 변수들은 변수를 사용할 수 없는 공간(TDZ)에 들어가게 된다.


다시말해 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것.

따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있다. 다만 ⚠ 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨을 주의

참고 글 01) [JavaScript] 호이스팅(Hoisting)이란?
참고 글 02) JavaScript 변수와 함수 호이스팅(Hoisting)에 대해 알아보자





📁 함수 표현식

🖊️ 함수 선언식과 함수 표현식

🖍️ 함수 선언식과 함수 표현식 차이점


🖊️ 함수 표현식과 화살표형 함수

화살표형 함수란?

  • function 키워드 사용하지 않고  =>  를 통해 변수의 함수를 값처럼 저장한다.
  • 함수 표현식과 동일하게 변수의 이름을 통해 함수 호출 가능.
  • 호이스팅의 대상이 아니므로 순서를 잘 지켜서 작성해야 한다.

🖊️  콜백함수

자바스크립트에서 함수는 객체다. 함수의 파라미터로서 객체를 전달할 수 있다는 말이다.

그렇듯이 다른 함수에 파라미터로 넘겨준(=전달하는) 함수를 콜백함수라 칭한다.





📁 객체

🖊️ 객체 생성 방법

객체 중괄호 안에 있는 값은 '객체 프로퍼티' 또는 '객체 속성' 이라고 부른다.

1. 객체 생성자

let person = new Object();

console.log(person); //{}

2. 객체 리터럴

객체 프로퍼티는 왼쪽은 key 값, 오른쪽은 value 값으로 구성됨.
key 값을 통해 객체를 찾기 때문에 객체 프로퍼티의 key 값은 고유해야 한다.
그러나 객체 프로퍼티의 value 값은 어떠한 자료형으로 작성되어도 상관없다.

let person = {
	name: "홍길동"
};

console.log(person); //{}

🖊️ 객체의 값 사용 방법

1. 점 표기법

. 이용해 객체의 값을 꺼냄
객체 이름 뒤에 .을 찍고 객체의 프로퍼티에 key 값을 작성하면 key값에 해당하는 value의 값을 가져온다.

let person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

console.log(person.name); //mac
console.log(person.age); //20
console.log(person.pet); //cat

2. 괄호 표기법

객체 이름 뒤에 대괄호([]) 안에 key 값을 작성한다.

대괄호 안에 큰 따옴표("")로 문자열임을 명시해 줘야 함.

let person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

console.log(person["name"]); //mac
console.log(person["age"]); //20
console.log(person["pet"]); //cat

보통 객체 프로퍼티 값을 꺼낼 때는 점 표기법을 많이 사용한다.

그러나 다음과 같은 겨웅는 괄호 표기법을 이용한다.

  • 객체의 key 값이 고정적이지 않거나
  • 특정 함수의 매개변수가 key 값을 결정하거나
  • 값이 계속 바뀌는 동적인 경우

다음은 객체의 key 값을 매개변수가 결정하는 경우의 예제다.

let person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

const getValue = (key) => { //매개변수에 key 값 받기
  console.log(person[key]); //key 값에 해당하는 person 객체의 프로퍼티 value 값을 출력하는 함수
};

//호이스팅 방지를 위해 제일 마지막에 호출문 작성. 
getValue("name"); //person 객체의 프로퍼티 key 값 중 name을 인수로 넘김.


//mac

객체 프로퍼티 생성, 수정, 추가, 삭제

점 표기법, 괄호 표기법 둘 다 사용 가능하다.

추가, 생성

let person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

person.phone = "010-123-123"; //점 표기법으로 phone 프로퍼티 추가
person["height"] = 180; // 괄호 표기법으로 key에 대한 정보 생성

console.log(person);

/*
[output]
{name: "mac", age: 20, pet: "cat", phone: "010-123-123", height: 180}
name: "mac"
age: 20
pet: "cat"
phone: "010-123-123"
height: 180
*/

수정

해당 프로퍼티에 원하는 값 입력.

person.age = 25;
person["pet"] = "dog";

/*
[output]
{name: "mac", age: 25, pet: "dog"}
name: "mac"
age: 25
pet: "dog"
*/

앞에서 const 로 선언된 상수는 수정이 불가능 하다고 했지만,
객체의 프로퍼티 값 수정할 때는 상수로 선언된 객체의 프로퍼티도 변경 가능.

why?
: 객체 프로퍼티 값 수정이 해당 객체 자체를 수정하는 행위가 아니기 때문에 가능하다.
객체는 생성될 때 고유한 id를 갖게 되는데 프로퍼티 갑 수정은 id 값에 영향을 미치지 않으므로 const든, let이든 상관없다.

const person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

person.age = 22;
person["pet"] = "rabbit";

console.log(person);

/*
[output]
{name: "mac", age: 22, pet: "rabbit"}
name: "mac"
age: 22
pet: "rabbit"
*/

[error] 객체 고유 id 값 변경 시도

person객체 자체에 새로운 프로퍼티를 저장하려 하면 객체의 고유한 id를 변경하는 것이므로 read-only 라는 에러 발생

const person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

person = { 
  pet: "dog"
};
console.log(person);

삭제

delete 키워드 사용

const person = {
  name: "mac",
  age: 20,
  pet: "cat"
};

delete person.pet; //{name: "mac", age: 20}
delete person["age"]; //{name: "mac"} name: "mac"

console.log(person);



객체 프로퍼티가 함수일 경우 = "메서드"

key값 = print, value값 = "hello world"를 출력하는 함수인 프로퍼티 작성하는 예시

const person = {
  name: "mac",
  age: 20,
  pet: "cat",
  print: function () {

    console.log("hello world");
  }
};

person.print(); //print의 value 값으로 저장된 함수 호출(점 표기법)
person["print"](); // " (괄호 표기법)

console.log(person);

/*
[output]
> hello world 
> {name: "mac", age: 20, pet: "cat", print: ƒ print()}
  name: "mac"
  age: 20
  pet: "cat"
  print: ƒ print() {}
  <constructor>: "Function"
  name: "Function"
*/

위와 같이 객체 프로퍼티 값이 함수일 경우 이를 '메서드' 라고 부름.
메서드는 객체 내부 프로퍼티에 접근할 수 있다.

다음은 person객체의 print 매서드에서 key 값이 name인 프로퍼티의 value 값 출력하는 예시다.

const person = {
  name: "mac",
  age: 20,
  pet: "cat",
  print: function () {
    console.log(`제 이름은 ${this.name} 입니다`); //제 이름은 mac 입니다 
  }
};

person.print();
person["print"]();

console.log(person);

this 키워드 이용해 자신이 속해있는 객체를 가리킬 수 있다.

메서드 생성 시 주의할 점
화살표형 함수가 아닌 function 키워드를 통해 함수를 선언해야한다.
또한, this 키워드를 통해 객체 프로퍼티 값을 꺼내올 수 있다.
단,화살표형 함수는 자신이 속한 객체를 가리키기 못하기 때문에 this 키워드와 맞지 않음.





📁 배열

순서가 있는 요소들의 집합이며, 여러 개의 항목들이 모여 있는 리스트.

🖊️ 배열 생성 방법

1. 배열 생성자

객체 생성 방법과 마찬가지로, new 키워드 사용.

let arr = new Array();
let arr1 = new Array(1, 2, 3);
let arr2 = new Array(3);

console.log(arr); //[]
console.log(arr1); //[1, 2, 3]
console.log(arr2); //[undefined, undefined, undefined]

2. 배열 리터럴

대괄호('[ ]') 이용

let arr = [];
let arr1 = [1, 2, 3];
let arr2 = [3];

console.log(arr); //[]
console.log(arr1); //[1,2,3]
console.log(arr2); //[3]

배열 리터럴을 통해 배열 생성 후 값을 넣게 되면, 배열요소로 순서대로 저장된다.
객체 프로퍼티와 같이 타입 상관없이 모든 요소를 넣을 수 있다.

let arr = [
  { name: "MAC" },
  1,
  "array",
  function () {
    console.log("hello,world");
  },
  null,
  undefined
];

console.log(arr);
//[Object, 1, "array", ƒ (), null, undefined]

🖊️ 배열 접근 방법

배열은 순서 있는 요소들의 집합으로, 객체와 달리 데이터를 구분하는 key 값이 존재하지 않는다.
대신 데이터가 위치하는 순서인 index를 통해 배열 요소에 접근 가능.

let arr = [1, "hello", null];

console.log(arr[0]); //1
console.log(arr[1]); //hello
console.log(arr[2]); //null

🖊️ 배열 요소 추가, 수정, 삭제

추가 >> push / unshift

내장함수 push 메서드 사용한다.
해당 배열의 맨 마지막 요소로 추가한다.

그리고, unshift 메서드는 해당 배열의 맨 앞 요소로 추가한다.

/* push */
arr.push(4); 
console.log(arr); 
//[1, "hello", null, 4]

/* unshift */
arr.unshift(0); 
console.log(arr); 
//[0, 1, "hello", null, 4]

수정

index으로 배열에 직접 접근해서 수정 가능하다.

배열은 객체로 분류되는 자료형에 속하므로, 객체와 동일한 이유로 const로 배열 선언해도 수정 가능하다.

arr[0] = 5;
arr[2] = undefined;

console.log(arr);
//[5, "hello", undefined]

삭제 >> pop / shift

pop 배열의 맨 마지막 요소 삭제 가능하다.
shift 배열의 맨 앞 요소 삭제 가능하다.

/* pop */
arr.pop(); 
console.log(arr); // [1, "hello"]

/* shift */
arr.shift();
console.log(arr); //["hello", null]





📁 반복문

🖊️ for, while

for문은 특정 변수의 초기값과 조건문을 비교하고 해당 조건문이 참이라면 변수의 값을 증감 시키는 반복문.
while문은 단순하게 괄호 안의 조건문만 확인하여 반복한다.

다음은 while문 사용 예시이다.

let i = 1;
while(i < 6) {
  console.log(i);
  i++;
}

다음은 for문을 이용해 배열의 모든 요소에 접근하는 반복문의 예시다.

let arr = [1, 2, 3, 4, 5];

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

반복문을 통해 배열뿐만 아니라 객체 프로퍼티도 접근 가능하다.
다만, 객체 프로퍼티를 순회하기 위해서는 해당 객체를 배열 형태로 변경해줘야 한다.

🖊️ 객체프로퍼티 -> 배열 변경 방법

1. Object.keys()

자바스크립트의 Object 객체 매서드로, 매개변수로 받은 객체의 key를 모두 찾아 배열 형태로 반환한다.

let person = {
  name: "mac",
  age: 20,
  height: 100
};

//01) 
let newArr = Object.keys(person);

//02) 
for (let i = 0; i < newArr.length; i++) {
  let nowKey = newArr[i];
  console.log(`key: ${nowKey}, value: ${person[nowKey]}`);
}


console.log(Object.keys(person));

/*
[OUTPUT]
> key: name, value: mac 
> key: age, value: 20 
> key: height, value: 100 

> ["name", "age", "height"] //Object.keys
*/

01) 객체를 key 값으로만 이루어진 객체로 변경.

02) for문 사용한 객체 프로퍼티 순환.
: person 객체프로퍼티의 key 값을 nowKey라는 변수를 통해 얻어올 수 있고, 괄호표기법을 통해 대괄호 안에 nowKey 변수를 작성하여 해당 key 값에 해당하는 value 값을 얻었다.
또한, newArr 라는 요소가 person 객체의 key 값을 알고 있기 때문에 객체의 프로퍼티를 모두 출력할 수 있었다.

2. Object.values()

매개변수로 객체 넘기면 해당 객체의 value를 모두 찾아 배열로 반환한다.

let person = {
  name: "mac",
  age: 20,
  height: 100
};

let newArr = Object.values(person);

for(let i = 0; i < newArr.length; i++){
  console.log(`value: ${newArr[i]}`);
}


console.log(Object.values(person));

/*
[OUTPUT]
> value: mac 
> value: 20 
> value: 100 

> ["mac", 20, 100] //Object.values
*/

key값 없이 바로 객체프로퍼티의 value 값 확인 가능하다 .

3. Object.entries()

객체 받으면 key와 value 쌍의 배열을 반환한다.

key와 value 값을 배열에 담아 새로운 배열로 반환해주는 메서드다.

let person = {
  name: "mac",
  age: 20,
  height: 100
};

let newArr = Object.entries(person);

for (let i = 0; i < newArr.length; i++) {
  console.log(`key: ${newArr[i][0]}, value: ${newArr[i][1]}`);
}

console.log(Object.entries(person));
/*
[OUTPUT]
> key: name, value: mac 
> key: age, value: 20 
> key: height, value: 100 

> [Array(2), Array(2), Array(2)] //Object.entries
*/

만약 value: ${newArr[i][0]} 일 경우,
key: name, value: name
key: age, value: age
key: height, value: height

만약 value: ${newArr[i][2]} 일 경우,
key: name, value: undefined
key: age, value: undefined
key: height, value: undefined

더 자세한 건 '이차원배열' 을 찾아보자


🖊️ 또다른 반복문

for of

주로 배열의 모든 요소에 접근해야할 때 사용된다.

let arr = [1, 2, 3, 4, 5];

for (let i of arr) {
  console.log(i);
}

for in

주로 객체에서 사용된다.
객체를 배열로 변환하는 과정없이 한번에 객체의 모든 프로퍼티에 접근 가능하다.

let person = {
  name: "mac",
  age: 20,
  height: 200
};

for (let key in person) {
  console.log(`key: ${key}, value: ${person[key]} `);
}
/*
[OUTPUT]
key: name, value: mac  
key: age, value: 20  
key: height, value: 200  
*/

0개의 댓글