Front-end/JavaScript Language

JavaScript - Intermediate1 (변수, null, undefined, 함수)

prden 2022. 11. 5. 10:11

1. 변수(var, let, const)

var

1) 한 번 선언된 변수를 다시 선언할 수 있다.
2) 선언하기 전에 사용할 수 있다.(hoisting, 호이스팅), 선언은 호이스팅 되지만 할당은 호이스팅 되지 않는다. 아래 예시
// 호이스팅 관련해서 -
호이스팅 기능이 있기 때문에 변수를 선언하기 전에 사용해도 오류가 생기지 않는다. undefined만 뜰뿐(let, const는 이렇게 undefined도 안 나오고 오류 뜬다)
--------------------------------------------------------------------------------------------------------------------------
console.log(name); //undefined
var name = 'Mike';
--------------------------------------------------------------------------------------------------------------------------
var name; // 선언
console.log(name); // undefined
name = 'Mike'; // 할당
--------------------------------------------------------------------------------------------------------------------------
cf) let,const는 호이스팅 되지 않는다? => 된다. TDZ(Temporal Dead Zone) 때문에 에러가 나는 것
console.log(name); //ReferenceError
let name = 'Mike';

https://www.youtube.com/watch?v=4_WLS9Lj6n4&t=2s

3) 함수 영역의(cf. 블록영역의 스코프) 스코프이다.(함수 내에서 선언된 변수만 지역변수가 된다.)

var age = 100; // 전역변수 선언
test();
document.write("myAge is" + age);

function test() {
	var age = 30; // 지역 변수 선언
  }

//결과 : myAge is 100
test() 함수 밖에 변수 age가 전역으로 선언되어 있고 함수 안에 있는 age는 test함수 안에서만 사용
따라서 결과 찍으면 100이 나온다.

함수 안에서 새로 전역 변수를 선언하려면 변수 이름 앞에 var를 붙이지 않으면 된다.

let, const

1) let, const는 선언 전에 사용할 수 없다. - 호이스팅 기능 없다. (엄밀하게 말하면 있다. TDZ 때문에 에러나는 것)
2) 블록 영역{}의 스코프이다. 코드 블록 내에서 선언한 변수는 지역변수로 외부에서 접근 불가능하다. (함수, if문, for문, while문, try/catch문)

function calcSum(n) {
	let sum =0; // 블록 변수 선언
    for(let i =1; i<n+1; i++) {
    	sum+=i;
        }
        console.log(sum);
   }
 calcSum(10);
 
 //sum은 calcSum()의 블록 {} 안에서만 사용할 수 있고 변수 i도 let을 사용해서 
 for문 안에서만 사용할 수 있다.

변수는 1. 선언, 2. 초기화, 3 할당 단계를 거친다.

var는 선언과 초기화(undefined를 할당해주는 단계)가 동시에
let은 선언과 초기화가 분리되어서 실행됨. let은 재할당은 가능하지만, 재 선언은 불가능하다.
const는 선언, 초기화, 할당 동시에 진행됨. const는 재선언, 재할당 할 수 없다.

정리 :
1) 전역 변수는 최소한으로 사용한다.
2) for 문에서 카운터 변수를 사용할 때는 블록 변수를 사용해라(위에 calcSum 내 for문 참조)

TDZ 란→ https://www.youtube.com/watch?v=19d31GvhqHE

1-1) if

https://ko.javascript.info/ifelse

 

if와 '?'를 사용한 조건 처리

ko.javascript.info

if (…) 문은 괄호 안의 표현식을 평가하고 그 결과를 불린 값으로 변환합니다.
형 변환 챕터에서 배운 형 변환 규칙을 잠시 상기해 봅시다.

  • 숫자 0, 빈 문자열"", null, undefined, NaN은 불린 형으로 변환 시 모두 false가 됩니다. 이런 값들은 ‘falsy(거짓 같은)’ 값이라고 부릅니다.

1-2) Null, undefined, NaN

https://weicomes.tistory.com/132

 

Javascript null, undefined, NaN

다른 언어들을 공부하다가 자바스크립트를 공부하다가 의문에 빠지게 하는 null, undefined, NaN 보통 다른 언어들의 경우 null만을 제공하는데 비슷한듯 비슷하지 않은 세가지의 타입을 제공해 다소

weicomes.tistory.com

선언은 되었지만 값이 할당되지 않은 변수에 접근할 경우 undefined 가 된다. 
var temp;    // undefined
temp = null;     // null 

객체 환경에서는 선언되지 않은 객체 프로퍼티도 undefined이다.

function TempObject(){
  this, i;
}
var tempObject = new TempObject();
tempObject.i;    // 선언은 되었으나 값이 할당되지 않은 객체 프로퍼티: undefined
tempObject.j;    // 존재하지 않는 객체 프로퍼티 역시 undefined
Boolean 문맥에서 null 과 undefined는 실제로 다른 값이지만 참/거짓(Boolean)으로 평가되어야 하는 경우 모두 false로 형변환이 된다. 
var temp;
if(temp) // undefined가 자동으로 false로 변환됨.{
}
숫자 문맥에서 두 값이 차이를 보이는데 null은 0으로 undefined의 경우 NaN으로 변환된다. 
var temp1 = null;
var temp2;
Number(temp1); // 강제형변환 : 0
Number(temp2); // 강제형변환: NaN
NaN
자바스크립트의 NaN 값은 not a number라는 뜻으로 즉 숫자가 아니라는 의미이다. 
typeof NaN === 'number'    // true
typeof로는 NaN와 숫자를 구분할 수 없거니와 자신과의 비교도 불허한다.
NaN === NaN         // false
NaN !== NaN        // true
결국, Javascript 에서는 숫자와 NaN을 구분하는 isNaN 함수를 제공하고 있다.
isNaN(NaN)    // true
isNaN(0)    // false
isNaN('oops')    // true
isNaN('0')    // false
결국, 숫자를 구별하는 가장 확실한 방법으로 다음과 같은 함수가 쓰일 수 있다.
 
function isNumber(value) {
    return typeof value === 'number' && isFinite(value);
}
isFinite() 함수는 주어진 숫자가 NaN이 아닌 동시에 양의 무한대나 음의 무한대가 아닌지의 여부를 검사한다. 유한한 숫자인경우 true, NaN이거나 무한수인경우 false를 반환.

1-3) get, set

getter 메서드는 obj.propName을 사용해 프로퍼티를 읽으려고 할 때 실행되고,
setter 메서드는 obj.propName = value으로 프로퍼티에 값을 할당하려 할 때 실행된다
https://ko.javascript.info/property-accessors

 

프로퍼티 getter와 setter

ko.javascript.info

################################################################################################

2. 생성자 함수

// 생성자 함수는 붕어빵 틀
// 생성자 함수는 첫 글자를 대문자로 하는게 관례

function User(name, age){
	// this = {};
	this.name = name;
    this.age = age;
    // return this
    }
    
let user1 = new User('Mike', 30);
let user2 = new User('Jane', 22);
let user3 = new User('Tom', 17);

function User(name, age){
	this.name = name;
    this.age = age;
    this.sayName = function(){
    	console.log(this.name);
        }
    }
 let user5 = new User('Han', 40);
 user5.sayName(); // Han

################################################################################################

3. Computed property

let a = 'age';
const user = {
	name : 'Mike';
    [a] : 30 //age:30과 같은 의미 이를 computed property라고 함(계산된 프로퍼티)
    }
    
const user = {
	[1+4] : 5;
    ["안녕"+"하세요"] : "Hello"
    }

 

4. 객체에서 사용 가능한 Methods(객체 복제 assign, keys, values, entries, ..)


const user = {
name: 'Mike',
age: 30 }
const cloneUser = user; // 이때 객체가 복제되는 게 아니라 참조값만 복사된다. 아래 그림처럼 동일한 변수가 하나의 객체를 참조하게 된다.

https://www.youtube.com/watch?v=4_WLS9Lj6n4&amp;t=2s

example1)
Object.assign(); // 객체 복제
const newUser = Object.assign({}, user); 
//초기값은 {}, 두 번째가 초기값에 병합된다.

example2)
Object.assign({gender:'male'}, user);
이때 gender: 'male',
	 name: 'Mike',
     age:30,

Object.keys();
// 키 배열 반환
const user ={
	name:'Mike',
    age:30,
    gender:'male',
    }
    
Object.keys(user); //배열로 반환됨 ["name", "age", "gender"]

Object.values(); // 위와 다르게 값 배열로 반환

Object.entries(); // 키와 값을 모두 배열로 반환
const = user={
	name: 'Mike'
    age: 30,
    gender: 'male',
    }
    
    
Object.entries(user);
[
	["name", "Mike"],
    ["age", 30],
    ["gender", "male"]
]

Object.fromEntries(); // 키/값 배열을 객체로
const =arr =
[
	["name", "Mike"],
    ["age", 30],
    ["gender", "male"]
];


Object.fromEntries(arr);
{
	name:'Mike',
    age:30,
    gender : 'male',
}

4-1) assign

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

 

Object.assign() - JavaScript | MDN

Object.assign() 메서드는 출처 객체들의 모든 열거 가능한 자체 속성을 복사해 대상 객체에 붙여넣습니다. 그 후 대상 객체를 반환합니다.

developer.mozilla.org

################################################################################################

5. 심벌(Symbol)

Symbol은 new를 붙이지 않는다.
const a = Symbol();

1) 유일성 보장

//Symbol은 유일한 식별자 만들 때 사용한다. 

const a = Symbol();
cosnt b = Symbol();

console.log(a)
Symbol()

console.log(b)
Symbol()

a===b; //false
a==b; // 자료형 달라도 내용일치하면 되는 것도 false

Ex) Symbol을 객체의 key로 사용

const id = Symbol('id');
const user = {
	name: 'Mike',
    age: 30,
    [id] : 'myid'
    }
Object.keys(user); ["name", "age"] //이렇게 심볼은 찍히지 않는다.
Object.values(user); ["Mike", 30] //이렇게 심볼은 찍히지 않는다.
Object.entries(user); [ Array(2), Array(2)] //이렇게 심볼은 찍히지 않는다.


Symbol을 사용하면 특정 객체에 원본 데이터는 건드리지 않고 프로퍼티를 추가할 수 있다.
const user = {
	name: 'Mike',
    age: 30
    }
const id = Symbol('id')
user[id] = 'myid';

2) Symbol.for(): 전역 심볼

- 하나의 심볼만 보장받을 수 있다. ( 없으면 만들고 있으면 가져오기 때문에)
- Symbol 함수는 매번 다른 Symbol 값을 생성하지만, Symbol.for 메소드느 하나를 생성한 뒤 키를 통해 같은 Symbol을 공유
const id1 = Symbol.for('id');
const id2 = Symbol.for('id');
id1 === id2; // true

Symbol.keyFor(id1) // "id"

3) 숨겨진 Symbol key 보는 법

const id = Symbol('id');
cosnt user = {
name: 'Mike',
age: 30,
[id]: 'myid'
}
Object.getOwnPropertySymbols(user); [Symbol(id)]
Reflect.ownKeys(user); // ["name", "age", Symbol(id)]

Symbol예시

// 다른 개발자가 만들어 놓은 객체
 const user = {
  name: "mike",
  age: 30
  };
  
  //나의 작업
  const showName = Symbol("show name");
  user[showName] = function () {
   console.log(this.name);
   };
   
   user[showName](); //Mike
   
   for(let key in user) {
    console.log(`His ${key} is ${user[key]}.`);
    }

################################################################################################

6. 숫자, 수학(Number, Math)

1) toString()

10진수 -> 2진수/16진수
let num = 10;
num.toString(); // "10"
num.toString(2); // "1010" 괄호 안에 넣은 숫자의 진수로 변경된다.

2) Math.ceil() : 올림, Math.floor(): 내림, Math.round(): 반올림

소수점 둘째 자리까지 표현
Math.round(userRate * 100) / 100 // 3.12
아니면 toFixed(2); 로 사용
userRate.toFixed(2);
** toFixed는 문자열을 반환한다 따라서 반환 후 Number(userRate.toFixed(2));로 반환하는 경우가 많다.

3) isNaN() // NaN인지 아닌지 판단하기

x == NaN //false
x===NaN // false
NaN == NaN //false, 자기 자신도 같은 것으로 인식하지 않음
isNaN만 NaN인지 아닌지 판단할 수 있다.

4) parseInt() //문자를 숫자로 바꿔준다. 문자가 혼용되어 있어도 동작을 한다. (읽을 수 있는 부분까지만 읽고 읽지 못하는 부분은 읽지 않는다.)

let redColor = 'f3';
parseInt(redColor, 16); //243 16진수로 변경해서 보이게

5) parseFloat() // 부동 소수점을 반환한다.

let padding = '18.5%';
parseInt(padding); // 18
parseFloat(padding); // 18.5

6) Math.random()

0 ~ 1 사이 무작위 숫자 생성
1~100 사이 임의의 숫자를 뽑고 싶으면?
Math.floor(Math.random()*100) + 1

7) Math.max() / Math.min(), Math.abs() : 절댓값

 

8) Math.pow(n, m): 제곱 : n의 m승

 

9) Math.sqrt(16) // 4

################################################################################################

7. 문자열

let result = `My name is ${name}.` // My name is Mike.

1) length : 문자열 길이

2) toUpperCase() / toLowerCase()

3) str.indexOf(text)
문자열을 인수로 받아 몇 번째 인지 위치 반환
let desc = "Hi guys. Nice to meet you.";
desc.indexOf('to'); // 14 앞에 t를 기준으로 0부터 시작
//없으면 -1을 반환
if(str.indexOf("콜라")>-1) // true이면 들어있는 거니까

4) str.slice(n, m) //특정 범위의 문자열만 뽑기
n : 시작점, m : 없으면 문자열 끝까지, 양수면 그 숫자까지(포함하지 않음), 음수면 끝에서부터 셈

5) str.substring(n, m) // n과 m사이 문자열 반환
let desc = "abcdefg";

6) str.substr(n, m) // n부터 시작, m개를 가져옴

7) str.trim(): 앞 뒤 공백 제거

8) str.repeat(n) : 문자열 n번 반복

9) includes //문자가 있으면 true, 없으면 false
################################################################################################

8. 배열

push(): 뒤에 삽입
pop(): 뒤에 삭제
unshift(): 앞에 삽입
shift(): 앞에 삭제

1) arr.splice(n, m) : 특정 요소 지움 // n : 시작, m : 개수
let arr = [1,2,3,4,5];
arr.splice(1,2);
console.log(arr); // [1,4,5]

2) arr.splice(n, m, x) : 특정 요소 지우고 추가
let arr = [1,2,3,4,5];
arr.splice(1,3,100,200);
console.log(arr); // [1, 100, 200, 5]

3) arr.splice() : 삭제된 요소 반환
let arr = [1,2,3,4,5];
let result = arr.splice(1,2);

console.log(arr); // [1,4,5]
console.log(result); //[2,3]

4) arr.concat(arr2, arr3) : 합쳐서 새배 열 반환

5) forEach는 함수를 인수로 받는다.
let users =['Mike', 'Tom', 'Jane'];
users.forEach((item, index, arr) => {
});
item // 첫 번째는 해당 요소
index //두 번째는 인덱스
arr / 세 번째는 해당 배열 자체를 의미

6) arr.indexOf / arr.lastIndexOf (앞에서부터 뒤로, 뒤에서부터 앞으로)
let arr = [1,2,3,4,5,1,2,3];
arr.indexOf(3); // 2
arr.indexOf(3,3) // 7
arr.lastIndexOf(3); // 7

7) arr.includes() : 포함하는지 확인

8) arr.find(fn) / arr.findIndex(fn) fn : 함수
첫 번째 true값만 반환하고 끝, 만약 없으면 undefined를 반환
let arr =[1,2,3,4,5];

const result = arr.find((item) => {
return item % 2===0;
});
console.log(result); //2

객체가 들어있을 때 find이용

let userList = [
{ name: "Mike", age: 30},
{ name: "Jane", age: 27},
{ name: "Tom", age:10},
];
const result = userList.find(() => {
if(user.age < 19){
return true;
} else {
return false;
});
console.log(result);

9) arr.filter(fn) 만족하는 모든 요소를 배열로 반환

10) arr.reverse() : 역순으로 재정렬
let arr = [1,2,3,4,5];
arr.reverse(); // [5,4,3,2,1]

11) arr.map(fn)
함수를 받아 특정 기능을 시행하고 새로운 배열을 반환
let userList = [
{ name: "Mike", age: 30},
{ name: "Jane", age: 27},
{ name: "Tom", age:10},
];
let newUserList = userList.map((user, index) => {
return Object.assign({}, user, {
isAdult: user.age > 19, });
});
//
[
{name:"Mike", age: 30, isAdult: true},
{name:"Jane", age: 27, isAdult: true},
{name:"Tom", age: 10, isAdult: false},
]

8-2. 배열 2

1) arr.sort() : 배열 재정렬, 배열 자체가 변경되니 주의
함수를 인수로 받는다.

let arr = [27, 8, 5, 13];

arr.sort((a, b) => {
return a-b;
});

console.log(arr);
//[5, 8, 13, 27]

Lodash라는 라이브러리 사용하면
_. sortBy(arr);
동일한 기능 구현 가능

2) reduce
// 배열의 모든 수 합치기
let arr =[1,2,3,4,5];

let result =0;
arr.forEach((num) => {
result += num;
});
console.log(result);

##위와 동일한 것은
//prev는 현재까지 누적된 계산 값, cur = 현재 값
const result = arr.reduce((prev, cur) => {
return prev + cur;
}, 0)
console.log(result);

3) Arrayi.isArray() - 배열인지 구분해주는 것, typeof쓰면 Array도 Object로 나온다.