변수유효범위
block scope - const, let
function scope - var
<h1>변수유효범위</h1>
<button onclick="test1();">확인</button>
// 전역공간
const a = '안녕'; // 전역변수
function test1(){
console.log(a);
const b = '잘가'; // 지역변수
console.log(b);
}
// console.log(b); // Uncaught ReferenceError: b is not defined
for(let i = 0; i < 10; i++){
let k = i;
}
// console.log(i); // Uncaught ReferenceError: i is not defined
// console.log(k); // Uncaught ReferenceError: k is not defined
body와 script에 작성 -> 전역변수
function , for문 등 안에 작성(if문 제외) -> 지역변수
지역변수는 바깥에서 사용하려고 하면 오류 발생함
함수 스코프 (function scope)
함수블럭 이외에는 무시
전역 선언된 var키워드는 window전역객체의 속성으로 등록된다.
if블럭은 함수블럭이 아니므로 안밖을 구분하지 않는다.
var키워드는 변수 중복선언을 허용한다.
<button onclick="test2();">var</button>
for(var i = 0; i < 10; i++){
}
console.log(i);
function test2(){
var m = 99;
console.log(m);
if(true) {
var m = 80;
}
console.log(m);
}
형변환
두수의 합 구하기
<fieldset>
<legend>두 수의 합</legend>
<!-- input:number[name=nums]#num$*2 -->
<input type="number" name="nums" id="num1" value="33"><br>
<input type="number" name="nums" id="num2" value="22"><br>
<button onclick="test1();">합</button>
</fieldset>
/**
* input태그의 value속성은 모두 문자열이다.
*/
function test1(){
console.log(typeof num1.value, num1.value);
console.log(typeof num2.value, num2.value);
alert(Number(num1.value) + Number(num2.value));
}



console로 타입을 확인해본 결과, string형으로 나온다.
문자열과 산술/비교 연산
string형과 number +(더하기) -> string
string형과 number -(빼기) -> number
string형과 number *(곱하기) -> number
string형과 number /(나누기) -> number
string형과 number %(나머지) -> number
숫자로 변환불가능한 문자열 연산 -> number , 값은 NaN
boolean true 는 산술연산시 1로 변환, false는 0으로 변환
== : 비교연산자
=== : 엄격비교연산자. 타입,값이 모두 같으면 true 하나라도 다르면 false
!== : 엄격비교연산자. 타입, 값중에 하나라도 다르면 true 모두 같으면 false
<button onclick="test2();">문자열과 산술/비교연산</button>
function test2(){
const a = "3";
const b = 3;
// 숫자가 문자열로 형변환
console.log(typeof(a + b), a + b); // string 33
// 문자열이 숫자로 형변환
console.log(typeof(a - b), a - b); // number 0
console.log(typeof(a * b), a * b); // number 9
console.log(typeof(a / b), a / b); // number 1
console.log(typeof(a % b), a % b); // number 0
const c = "abc"; // 숫자로 변환 불가능한 문자열
console.log(typeof(c * b), c * b); // number NaN
let bool = true; // true는 산술연산시 1로 변환
console.log(typeof(bool / b), bool / b); // number 0.3333333333333333
bool = !bool; // false는 산술연산시 0으로 변환
console.log(typeof(bool / b), bool / b); // number 0
console.log(typeof(a == b), a == b); // boolean true
console.log(typeof(a != b), a != b); // boolean false
// 엄격비교연산자
// === 타입/값이 모두 같은면 true, 하나라도 다르면 false
// !== 타입/값중에 하나라도 다르면 true, 모두 같으면 false
console.log(typeof(a === b), a === b); // boolean false
console.log(typeof(a !== b), a !== b); // boolean true
}

주석으로 단 것과 같은 결과가 나온다.
Number | parseInt | parseFloat - 문자열을 숫자로 명시적 형변환
Number : 숫자로 변환. 변환불가한 문자가 하나라도 있으면 NaN을 반환.
parseInt : 정수로 변환. 변환불가한 문자가 나오기 전까지 변환 후 정수 반환.
parseFloat : 실수로 변환. 변환불가한 문자가 나오기 전까지 변환 후 실수 반환.
<button onclick="test3();">Number | parseInt | parseFloat</button>
function test3(){
const n = "1234.56";
console.log(Number(n)); // 1234.56
console.log(parseInt(n)); // 1234
console.log(parseFloat(n)); // 1234.56
const won = "1234.56원";
console.log(Number(won)); // NaN
console.log(parseInt(won)); // 1234
console.log(parseFloat(won)); // 1234.56
}

논리형으로 형변환
값이 있는 것은 true로 변환 : "abc" , 100, -10, 23.4, {}, []
값이 없는 것은 false로 변환 : " ", 0, 0.0, undefined, null, NaN
<button onclick="test4()">논리형으로의 형변환</button>
function test4(){
console.log(Boolean("abc"), !!"abc");
console.log(Boolean(100), !!100);
console.log(Boolean(-100), !!(-100));
console.log(Boolean(1.23), !!1.23);
console.log(Boolean({}), !!{});
console.log(Boolean([]), !![]);
console.log(Boolean(""), !!"");
console.log(Boolean(0), !!0);
console.log(Boolean(0.0), !!0.0);
console.log(Boolean(undefined), !!undefined);
console.log(Boolean(null), !!null);
console.log(Boolean(NaN), !!NaN);
const elem = document.querySelector("#xyz");
if(elem){
// elem이 존재하는 경우
}
else {
// elem이 존재하지 않는 경우 (null이 반환)
}
foo(elem);
// elem이 존재하면 k에 대입
// elme이 존재하지 않으면(false로 평가되면) 우항의 요소를 대입
// let k;
// if(elem)
// k = elem;
// else
// k = document.createElement("h2");
const k = elem || document.createElement("h2");
console.log(k);
}

짧은 조건문
a && b : a가 true로 평가되면 b를 실행
a || b : a가 false로 평가되면 b를 실행
b에는 실행문과 대입문이 가능. 리턴식 불가
<button onclick="test5()">짧은 조건문</button>
function test5(){
const num = Number(prompt("정수를 입력하세요"));
num % 2 == 0 && alert("짝수입니다.");
num % 2 == 0 || alert("홀수입니다.");
let m;
num % 2 == 0 && (m = num * 100);
// 리턴식은 불가
// num % 2 == 0 && return;



홀수 짝수 입력시 제대로 알림창이 뜨는 것을 확인할 수 있다.
배열
길이제한, 타입제한이 모두 없다.
ArrayList<Object>와 비슷하다고 보면 된다.
배열 생성하기
*배열 생성하는법 3가지*
const 배열이름 = [ 요소1, 요소2, 요소3 , ...];
const 배열이름 = new Array('요소1', '요소2', '요소3');
const 배열이름 = new Array(배열길이);
배열이름[인덱스] = '값' ; 값입력하기
배열이름[인덱스] = [' ', ' ', ' '] ; 배열자리에 배열입력 (2차원배열)
* 존재하지 않는 요소를 참조해도 오류가 발생하지 않는다.
indexOf(찾을값, 시작위치) : 인덱스 위치 반환 . 없으면 -1반환. (시작위치는 생략 가능)
배열1.concat(배열2,...) : 배열3. 원본 배열에 추가하지 않고 새로운 배열을 반환함.
const 배열이름 = [...배열1]; : 배열 1 복사.
배열.join('구분자') : join(구분자), string. 배열 사이에 구분자가 들어감. 기본구분자 , (쉼표)
배열.toString() : 요소 확인가능
배열.reverse() : 배열 요소의 순서를 반대로 뒤집는다. 원본배열을 수정함.
배열.sort() : 배열 요소를 오름차순 정렬한다. 내림차순은 아래 코드 참조. 원본배열 변경함
배열.push(값) : 마지막에 요소 추가
배열.pop(값) : 마지막 요소제거
배열.unshift(값) : 0번지에 요소추가
배열.shift(값) : 0번지 요소제거
배열.slice(a,b) : 배열의 substring . 원본배열 변경안함. a부터 b미만까지. b생략시 마지막 요소까지 반환한다.
배열.splice(a, b, [new Item1, new Item2, ...]) : a인덱스에 b를 제거, newItem들을 추가 한다는 뜻.
<button onclick="test1()">배열생성</button>
<button onclick="test2()">indexOf</button>
<button onclick="test3()">concat</button>
<button onclick="test4()">join/</button>
<button onclick="test5()">reverse</button>
<button onclick="test6()">sort</button>
<button onclick="test8();">push | pop | unshift | shift</button>
<button onclick="test9();">slice</button>
<button onclick="test10();">splice</button>
function test1(){
const arr1 = [1, 2, 3];
const arr2 = new Array('a', 'b', 'c');
const arr3 = new Array(3); // 배열의 길이
console.log(arr1);
console.log(arr2);
console.log(arr3);
arr1[3] = '안녕';
arr1[4] = ['x', 'y', 'z'];
arr3[0] = '가';
arr3[1] = '나';
arr3[2] = '다';
arr3[3] = '라';
// 요소참조 - 인덱스참조
console.log(arr1[3]);
console.log(arr1[4][2]);
// 존재하지 요소를 참조해도 오류가 발생하지 않는다.
console.log(arr1[100]); // undefined
console.log(arr1[100].length); // Uncaught TypeError: Cannot read properties of undefined (reading 'length')
}

function test2(){
const arr = ["apple", "strawberry", "melon", "avocado", "melon"];
console.log(arr.indexOf("melon")); // 2
console.log(arr.indexOf("melon", 3)); // 4
console.log(arr.indexOf("mmmmmmmmmmmmmelon")); // -1
console.log(arr.lastIndexOf("melon")); // 4
}

function test3(){
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const arr3 = arr1.concat(arr2);
const arr4 = [...arr1, ...arr2];
const arr5 = [...arr1]; // clone
console.log(arr1); // [1, 2, 3]
console.log(arr2); // ['a', 'b', 'c']
console.log(arr3); // [1, 2, 3, 'a', 'b', 'c']
console.log(arr4); // [1, 2, 3, 'a', 'b', 'c']
console.log(arr5); // [1, 2, 3]
}

function test4(){
const arr = ['사과', '딸기', '바나나', '망고'];
console.log(arr.join('|')); // 사과|딸기|바나나|망고
console.log(arr.join()); // 기본구분자 , 사과,딸기,바나나,망고
console.log(arr.toString()); // 요소확인 가능하도록 오버라이드되어 있음. 사과,딸기,바나나,망고
}

function test5(){
const arr = new Array('가', '나', '다');
console.log(arr.reverse()); // ['다', '나', '가']
console.log(arr); // ['다', '나', '가']
}

function test6(){
// 기본정렬
const arr = [3, 2, 4, 5, 1];
console.log(arr.sort());
console.log(arr);
const names = ['나영길', '다락방', '가방애'];
console.log(names.sort());
// 기타정렬
// 숫자내림차순
// 음수 | 0 | 양수을 반환. 음수반환시에 자리교환.
arr.sort(function(a, b){
return b - a;
});
console.log(arr);
// 문자열 사전등재역순
names.sort(function(a, b){
if(a > b) return -1;
if(a < b) return 1;
return 0;
});
console.log(names);
}

function test8(){
const arr = [];
arr.push(1);
arr.push(2);
arr.push(3);
console.log(arr.pop()); // 3
console.log(arr.pop()); // 2
console.log(arr.pop()); // 1
arr.unshift(1);
arr.unshift(2);
arr.unshift(3);
console.log(arr.shift()); // 3
console.log(arr.shift()); // 2
console.log(arr.shift()); // 1
// queue
// 맨뒤에서 추가, 맨 앞에서 제거
arr.push('a');
arr.push('b');
arr.push('c');
while(arr.length)
console.log(arr.shift()); // c b a
// stack
// 맨뒤에서 추가, 맨뒤에서 가져오기
// 다 나 가
arr.push('가');
arr.push('나');
arr.push('다');
while(arr.length)
console.log(arr.pop()); // 다 나 가
}

function test9(){
const arr = ['java', 'javascript', 'python', 'sql'];
// const other = arr.slice(1, 3);
const other = arr.slice(1); // end생략시 마지막요소까지 반환
console.log(arr, other);
// 배열복제
const copy = arr.slice(); // start, end생략시 복제
const cocopy = [...arr];
console.log(copy, cocopy);
}

function test10(){
const arr = ['a', 'b', 'c'];
// [제거, 삽입] b를 제거, '가', '나', '다'를 추가
console.log(arr.splice(1, 1, '가', '나', '다'));
// [제거] b만 제거
// arr.splice(1, 1);
// [삽입] 1번지 '가', '나', '다'를 추가
// arr.splice(1, 0, '가', '나', '다');
console.log(arr);
}

유사배열
- Array.prototype을 상속하지 않는 배열객체
- index, length는 있지만 Array.prototype의 메소드는 사용할 수 없다.
- getElementsByXXX, querySelectoAll의 리턴 객체
- 진짜 배열로 변환하기 위해서는 const 배열이름 = Array.from(유사배열명); or const 배열이름 = [...유사배열명]; 처리.
<button onclick="test12();">유사배열</button>
function test12(){
const buttons = document.getElementsByTagName("button");
console.log(buttons);
//console.log(buttons.pop()); // Uncaught TypeError: buttons.join is not a function
// 유사배열 - 진짜배열로 변환
// const arr = Array.from(buttons);
const arr = [...buttons];
console.log(arr);
console.log(arr.pop());
buttons를 그냥 Array prototype메소드 중 하나인 pop을 쓰면

다음과 같이 오류가 발생한다.

진짜배열로 변환한 후에는 오류 없이 잘 이루어진다.
배열의 반복처리
일반 for문
for(let i = 0 ; i < arr.length; i++)
console.log( i, arr[i] );
for in문 : 열거 속성이 true인 요소를 반환. 배열 인덱스 반환
for( let i in arr )
console.log(i, arr[i] );
for of문 : 해당객체가 iterator를 구현한 경우 사용 가능. 배열은 사용 가능
for (let ch of arr) {
console.log(ch); }
for Each메소드 : 매번 요소별로 콜백 함수를 호출.
arr.forEach(function(ch, index, arr) {
console.log(ch, index, arr);});
<button onclick="test13();">반복처리</button>
function test13(){
const arr = ['a', 'b', 'c'];
// 일반for
// for(let i = 0; i < arr.length; i++)
// console.log(i, arr[i]);
// for..in : 열거속성이 true인 요소를 반환. 배열 인덱스반환
for(let i in arr){
console.log(i, arr[i]);
}
// for..of 해당객체가 iterator를 구현한 경우 사용가능. 배열은 사용가능
for(let ch of arr){
console.log(ch);
}
// forEach 메소드 - 매요소별로 콜백함수 호출
arr.forEach(function(ch, index, arr){
console.log(ch, index, arr);
});
/*
a 0 (3) ['a', 'b', 'c']
b 1 (3) ['a', 'b', 'c']
c 2 (3) ['a', 'b', 'c']
*/
}

map | filter | reduce
map : 현재 배열 요소에 어떤 작업 후 변환된 값을 새 배열에 추가한다.
filter : 현재 배열 요소중 조건에 맞는 요소만 추려내서 새 배열에 추가한다.
reduce : 모든 요소를 대상으로 특정 작업 후 하나의 값(객체)를 반환한다. reduce(콜백함수, 초기값)
<button onclick="test14();">map</button>
<button onclick="test15();">filter</button>
<button onclick="test16();">reduce</button>
function test14(){
const arr = [1, 2, 3]; // [1, 4, 9]
const result = arr.map(function(n, index){
console.log(n, index);
return `<mark>${n * n}</mark>`;
});
console.log(arr, result);
result.forEach(function(mark, index){
foo.innerHTML += mark + " ";
});
}


function test15(){
const arr = [23, 2, 23, 54, 7, 8, 10, 77];
const evens = arr.filter(function(n, index){
return n % 2 == 0;
});
console.log(arr, evens);
const str = ["안녕", "34", "700원", "$35.5", "77", "4달라", "123", "2밤"];
const nums =
str.filter(function(str, index){
return !isNaN(Number(str));
}).map(function(str){
return Number(str);
});
console.log(str, nums);
}

function test16(){
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const sum = arr.reduce(function(agg, n, index){
console.log(agg, n);
return agg + n;
}, 0);
console.log('합계 : ', sum);
}
