<script>
//전개 연산자(Spread)
const fruits = ['Apple', 'Banana', 'Cherry', 'Orange']
console.log(fruits)
console.log(...fruits)
//console.log('Apple','Banana', 'Cherry')와 동일하게 호출
//c(last매개변수)는 ['Cherry','Orange'] 인자를 받는다
// function toObject(a,b,...c){
// return{
// //a: a, b: b, c: c
// a, b, c //키,값변수가 같으면 1번만 명시해도 됨
// }
// }
const toObject = (a, b, ...c) => ({
a,
b,
c
})
console.log(toObject(...fruits)); //호출 인자가 많을 때 유리함
//console.log(toObject(fruits[0],fruits[1],fruits[2],fruits[3])); 와 동일하게 호출
</script>
4. 불변성
<script>
//데이터 불변성(Immutability)
//원시 데이터 : String, Number, Boolean, undefined, null
//(값이 같으면 같은 참조값을 갖는다.)
//(결국, 원시 데이터는 참조값보다는 상수처럼 이해하면 된다.)
//참조형 데이터: Object, Array, Function
//(참조형은 불변성이 없다.)
//(결국, 참조형의 새로운 객체는 새로운 참조값을 갖는다. )
//----------------------------------------------
//1번지: 2번지: 3번지: 4번지:
//----------------------------------------------
// let a=1
// let b=4
// console.log(a,b, a===b)
// b=a //참조값이 복사된다.
// console.log(a,b, a===b)
// b=7 //7의 참조값이 복사된다.
// console.log(a,b, a===b)
// let c=1
// console.log(a,b, b===c)
let a = {
k: 1
}
let b = {
k: 1
}
console.log(a, b, a === b)
a.k = 7
b = a //객체값복사가 아니라 참조값이 복사된다.(주의)
console.log(a, b, a === b)
a.k = 2 //b객체의 k속성값도 2로 변경되니 주의하자.
console.log(a, b, a === b)
let c = b
console.log(a, b, c, a === c)
a.k = 9
console.log(a, b, c, a === c)
</script>
5. 얕은 복사와 깊은 복사
<script>
//얕은 복사(Shallow copy), 깊은 복사(Deep copy)
const user = {
name: "kim",
age: 40,
emails: ['thekim@gmail.com']
}
//const copyUser =user //얕은복사
//const copyUser =Object.assign({}, user) //깊은복사
let copyUser = {
...user
} //전개연산자 활용 깊은복사같지만 emails는 얕은복사가 된다.
let copyUser = {
name: user.name,
age: user.age,
email: user.emails
}
console.log(copyUser)
console.log(copyUser === user) //false 깊은 복사
console.log(copyUser.email === user.emails) //true 그러나 emails는 얕은복사
user.age = 22
console.log('user', user)
console.log('copyUser', copyUser)
console.log('-------------');
console.log('-------------');
user.emails.push('neo@naver.com')
console.log(user.emails, copyUser.emails); //얕은복사이므로 같은요소값이 출력됨
console.log('user', user);
console.log('copyUser', copyUser);
//deep copy는 lodash 라이브러리의 cloneDeep()를 이용해서 쉽게 할수 있지만
//실력을 위해 직접구현해 보자
copyUser = {}
deepCopy(user, copyUser)
console.log('deepCopy call after')
console.log(user.emails === copyUser.emails); //깊은복사가 되어 false
user.emails.push('xxx@naver.com')
console.log('user', user); //['thekim@gmail.com','neo@naver.com','xxx@naver.com']
console.log('copyUser', copyUser); //['thekim@gmail.com','neo@naver.com']
function deepCopy(source, target) {
target.name = source.name
target.age = source.age
target.emails = []
//문제> source.emails 배열의 값을 순차적으로 target.emails배열로 복사하시오
for (let email of source.emails) {
target.emails.push(email)
}
//source.emails.forEach(email => target.emails.push(email));
//target.emails.push(...source.emails)
}
</script>
<script>
function random() {
return Math.floor(Math.random() * 10)
}
const a = random()
if (a === 0) {
console.log('a is 0')
}else if(a===2){
console.log('a is 2')
}else{
console.log('rest...')
}
</script>
<script>
function random() {
return Math.floor(Math.random() * 10)
}
const a = random()
switch(a){
case 0:
console.log('a is 0')
break;
case 2:
console.log('a is 2')
break;
default:
console.log('rest...')
}
</script>
4. 반복문
<script>
const ulEl=document.querySelector('ul')
for(let i=0; i<10; i++){
const li=document.createElement('li')
li.textContent=`list-${i+1}`
if((i+1)%2===0){ //짝수번째 클릭시
li.addEventListener('click',function(){
console.log(li.textContent)
})
}
ulEl.appendChild(li)
}
// 나중에 추가적으로 배울 것
</script>
5. 변수 유효범위
<script>
//var: 함수레벨 scope, 의도하지 않는 범위에서 사용될수 있다.메모리누수
//let, const: 블록레벨 scope
function scope(){
//console.log(a) // let,const: not defined에러, var: undefined출력
if(true){
//console.log(a) // let,const: not defined에러, var: undefined출력
var a =123
//console.log(a) //모두 정상
}
console.log(a) //let,const: not defined에러, var: 123
}
scope()
</script>
<script>
const a = 7; // 전역변수
function double(){
console.log(a*2);
}
double(); // 밑에 즉시실행함수가 있으면 꼭 세미콜론(;)을 붙여줘야한다.
// 즉시실행함수
// IIFE, Immediately-Invoked Function Expression
(function(){
console.log(a*3);
})(); // 두 덩어리
(function(){
console.log(a*4);
}()); // 한 덩어리 (권장)
</script>
10. 함수 호이스팅
<script>
// 호이스팅(Hoisting): 위로 끌어올리다.
// 함수 선언부가 유효범위 최상단으로 끌어올려지는 현상
// function double(){}
const a=7;
function double(){
console.log(a*2);
}
const square=function(){
console.log(a*2);
}
const square2= ()=> console.log(a*a);
// 익명함수는 호이스팅 불가
double()
square()
square2()
</script>
11. 변수 호이스팅
<script>
//호이스팅(hoisting)이란
//자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
//자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
//함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
//유효 범위: if,for단위 블록{}내에 변수를 선언해도 유효범위는 function단위 블록 {}이다.,
//호이스팅의 대상
//var 변수 선언과 함수선언문에서만 호이스팅이 일어난다. 함수 표현식은 호이스팅 안됨.
//var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
//let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.
//java처럼 if, for단위 블록{}내에 변수를 선언하면 해당{}이 유효범위다.
//지역변수>전역변수
const pi = 3.14; //전역 상수변수(global v)
fct1();
fct2(3,5);
function fct1() {
//var a,b; 함수의 상단에 호이스팅
//console.log('a: ',a) //var:undefined, let,const:error
//console.log('b: ',b) //var:undefined
let a = 100,b = 200; //지역변수(local variable)
if (1) {
let a = 30,b = 40; //java error, 위의 const와 let을 var로 변경해 보자.
console.log("1=" + a);
console.log("1=" + b);
}
console.log(a); //var는 마지막에 선언된 변수가 위의 변수를 덮어버린다.
console.log(b); //let,const는 100, 200
console.log('전역변수:' + pi)
}
function fct2(a, b) { //함수정의부
console.log('fct2 call:', a, b)
console.log('gv:' + pi);
}
//메소드 오버로딩은 없지만 유연하다.
fct2()
fct2(10)
fct2(10,20,30)
//함수선언부는 호이스팅 되지 않음
// const fct=function(){ //익명 함수
// console.log("함수 출력");
// };
// fct();
// console.log(typeof fct);
function test(show) {
show();
}
//ES6 화살표함수=> , 자바 람다(lambda) ->
test(() => {
console.log('function call');
console.log('second line');
});
// test(function() {
// console.log('function call');
// console.log('second line');
// });
</script>
12. 타이머 함수
<script>
//타이머 함수: JS 전역함수(어디서든 호출가능한 함수)
//setTimeout(함수, 시간): 일정 시간 후 함수실행
//setInterval(함수, 시간): 시간 간격바다 함수 실행
//clearTimeout(): 설정된 Timeout 함수를 종료
//clearInterval(): 설정된 Interval 함수를 종료
// setTimeout(function(){
// console.log('hello!')
// }, 3000)
// const timer=setTimeout(()=>{
// console.log('hello!')
// }, 3000)
console.log('비동기 처리')
const timer = setInterval(() => {
console.log('hello!')
}, 3000)
//h1태그를 클릭하면
const h1El = document.querySelector('h1')
h1El.addEventListener('click', () => {
//clearTimeout(timer) //setTimeout함수가 작동하지 않음
clearInterval(timer) //setInterval함수가 작동하지 않음
})
</script>
13. 콜백
<script>
//콜백(Callback)
//함수의 인수로 사용되는 함수
//setTimeout(함수, 시간)
// function timeout(){
// setTimeout(()=>{
// console.log('hello!')
// },3000)
// }
// timeout()
// console.log('Done!') //Done먼저 출력후 3초뒤 hello출력
function timeout(cb){
//아래 익명함수는 setTimeout의 콜백함수임
setTimeout(()=>{
console.log('hello!')
cb()
},3000)
}
//콜백 함수 사용 목적
//1.익명함수가 timeout의 인자로 사용됨
//2.timeout실행시 특정 위치 실행 보장하기 위해
timeout(()=>{
console.log('Done!')
})
</script>
14. 생성자 함수
<script>
//리터럴({},[],"") 방식의 객체 생성
// const kim={
// //필드
// //property
// firstName: 'kim',
// lastName: 'dong',
// //method
// getFullName: function(){ //=>함수 금지(this가 상위객체를 의미함)
// //this: 현재 소속된 객체데이터를 의미
// return `${this.firstName} ${this.lastName}`
// //return `${kim.firstName} ${kim.lastName}`
// }
// }
// console.log(kim.getFullName())
// const lee={
// firstName: 'lee',
// lastName: 'na',
// getFullName: function(){
// return `${this.firstName} ${this.lastName}`
// }
// }
// console.log(lee.getFullName())
//생성자 함수를 이용한 객체 생성
//java의 클래스와 유사(?)
//new와 사용하는 생성자함수는 대문자로 지정
function User(first, last) {
this.firstName = first //this생략 안됨
this.lastName = last
//메모리 비효율적(객체마다 함수객체를 생성함)
// this.getFullName=function(){
// return `${this.firstName} ${this.lastName}`
// }
}
//메모리 효율적
//함수객체를 user함수의 prototype에 1번만 생성한다.
User.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`
}
//생성자 함수를 통한 kim인스턴스 생성
const kim = new User('kim', 'dong')
const lee = new User('lee', 'na')
console.log(kim)
console.log(lee)
console.log(kim.getFullName())
console.log(lee.getFullName());
//javaScript는 prototype(원형)기반 언어임
const arr = [1, 2, 3];
console.log(arr)
//배열객체의 prototype의 includes메소드 확인
console.log(arr.includes(4)) //false
console.log(arr.includes(2)) //true
</script>
15. this
<script>
//this
//일반 함수는 (호출 위치!)에서 따라 this정의!
//화살표 함수는 자신이 (선언된 함수 범위!)에서 this정의!
const kim={
name: 'kim',
normal: function(){
console.log(this.name)
console.log(this) //kim객체
},
arrow:()=>{ //특정 함수범위에 선언되고 있지 않음
console.log(this.name)
console.log(this) //window객체
}
}
kim.normal() //kim
kim.arrow() //'' or undefined
const lee={
name: 'lee',
normal:kim.normal,
arrow: kim.arrow
}
//호출위치가 여기! 그래서 this는 lee객체 참조함
lee.normal();
//선언된 위치(범위)는 그대로임! this는 window객체 참조함
lee.arrow();
// 생성자 함수에서 getFullName을 화살표함수로
// 만들어서 this값을 확인해보자
const timer={
name: 'kim',
timeout: function(){
//setTimeout의 내부에서 콜백을 호출중이라서 name출력안됨
//setTimeout(function(){
// console.log('t:', this.name) //window 객체
//}, 2000)
//timer객체의 timeout메소드에 선언되었으므로 name출력됨
//setTimeout함수에서는 화살표함수를 쓰는것이 좋다.
setTimeout(()=>{
console.log('t:', this.name) //timer객체
}, 2000)
}
}
timer.timeout()
</script>
16. ES6 Classes
<script>
const hong = {
name: 'hong',
//normal: function(){
// console.log(this.name)
// },
//위 메소드의 간소화 표현
normal() {
console.log(this.name)
},
//화살표함수 간소화 안됨
arrow: () => {
console.log(this.name)
}
}
hong.normal()
hong.arrow()
////ES6 Classes
//생성자 함수활용을 class로 간소화 할 수 있음
//class는 react에서 많이 활용함
class User {
constructor(first, last) {
this.firstName = first //this생략 안됨
this.lastName = last
}
//prototype에 1번만 생성한다.
getFullName() {
return `${this.firstName} ${this.lastName}`
}
} //end class
//생성자 함수를 통한 kim인스턴스 생성
const kim = new User('kim', 'dong')
const lee = new User('lee', 'na')
console.log(kim)
console.log(lee)
console.log(kim.getFullName())
console.log(lee.getFullName());
</script>