자유변수 & 클로져 함수
자유변수 (Free Variable)
함수 내에 선언되지 않은 변수
const test1 = () => {
const greeting = '오늘 날씨 정말 좋다~';
// say의 지역변수 : name, word
const say = (name) => {
const word = '안녕,' + name;
console.log(word);
console.log(greeting);
};
say('영희');
};
여기서 say의 지역변수는 name과 word. 그렇다면 greeting은 ? 함수 내에 선언되지 않은 자유변수이다.
클로져 함수 (Closure Function)
필요한 변수를 모두 갖고 외부로부터 닫힌 함수. (지역변수, 자유변수)
const test2 = () => {
const num = 200;
const too = foo();
// const too = () => {
// console.log(`num = ${num}`);
// }; // 참조하는 자유변수 num을 가지고 리턴
console.dir(too);
too(); // 100
};
function foo(){
const num = 100;
return () => {
console.log(`num = ${num}`);
};
}
test2에서 보면, num=200으로 이 값을 참조할 것 같지만, 실제로는 foo안에서 선언된 num을 참조한다. (가까운 변수값 참조)
전역변수를 이용한 카운터
let cnt = 0;
const test3 = () => {
globalCounter.innerHTML = ++cnt;
};
클로져를 활용한 카운터
const counterMaker = () => {
let cnt = 0;
return () => {
closureCounter.innerHTML = ++cnt;
};
};
const test4 = counterMaker();
console.dir(test4);
둘다 똑같이 작동하는 것을 알 수 있다.
다만, 클로져 함수는 변수를 안전하게 사용할 수 있다는 점이 다르다!
전역변수를 이용한 카운터 : 변수를 그대로 함수로 선언
클로져를 활용한 카운터 : 변수를 클로져 함수로 선언 (함수 안에 변수 cnt 존재) , test4에 다시 대입.
클로져를 활용한 가산기 만들기
<form action="javascript:test5();">
<fieldset>
<legend>가산기</legend>
<input type="number" name="num" id="num">
<h2>누적합 : <span id="sum">0</span></h2>
<button type="button" onclick="test6();">초기화</button>
</fieldset>
</form>
const calcMaker = () => {
let sum = 0;
return [
() => {
console.log('add');
sum += Number(num.value);
document.querySelector("#sum").innerHTML = sum;
num.value = '';
},
() => {
console.log('reset');
sum = 0;
document.querySelector("#sum").innerHTML = sum;
}
];
};
const calcFuncs = calcMaker();
console.log(calcFuncs); // [f, f]
const test5 = calcFuncs[0]; //배열 0번지 함수 배정
const test6 = calcFuncs[1]; //배열 1번지 함수 배정
가산기가 제대로 작동하는 것을 알 수 있다.
calcMaker안에서 sum 변수를 선언하고 , 더하는 함수랑 초기화하는 함수를 만들었다.
개발자 콘솔창에서는 add세번, 리셋한번, add한번, 리셋한번이 제대로 등록된 것을 확인할 수 있다.
클로져 함수 변수 더 알아보기
<button onclick="aoo()();">aoo</button><!-- 100 -->
<button onclick="boo()();">boo1</button><!-- undefined -->
<button onclick="boo()(999);">boo2</button><!-- 999 -->
<button onclick="coo(3)(5);">coo1</button><!-- 15 -->
<button onclick="coo()(5);">coo2</button><!-- NaN -->
const a = 1;
const aoo = () => {
const a = 100;
return () => console.log(a); //자유변수 a가 프린트됨
}
const b = 9;
const boo = () => {
const b = 99;
return (b) => console.log(b); //boo가 리턴할 함수는 b. 여기는 자유변수가 없음. b가 지역변수. boo() (여기)에 적어야함.
}
const coo = (c) => {
return (n) => {
console.log(c * n);
}//c는 자유변수, n은 선언되었음. c라는 자유변수를 가진 클로져. 3을 줬으므로 5랑 곱해져서 15출력. 아랫줄 c자리 전달x
}
다음과 같이 버튼을 만들고, 변수가 무엇이 들어가는지 확인해보았다.
<button onclick="aoo()();">aoo</button>
자유변수인 a를 가지는 클로져함수이다. a=100;이 프린트된다.
<button onclick="boo()();">boo1</button>
boo가 리턴할 함수는 b이고, 여기에는 자유변수가 없다. b가 지역변수일뿐. 그래서 매개변수자리에 넣을 값이 없기 때문에 undefined출력
<button onclick="boo()(999);">boo2</button>
boo가 리턴할 b에 999가 대입되었기 때문에 999가 출력된다.
<button onclick="coo(3)(5);">coo1</button>
coo함수에는 c가 자유변수이다. n은 선언되었다. c라는 자유변수를 가진 클로져 함수이므로
c에 3, n에 5가 곱해져서 15가 출력되었다.
<button onclick="coo()(5);">coo2</button>
이 경우 c가 전달되지 않아 NaN이 출력되었다.
객체
객체 생성하는법
- {}
- new Object()
속성 참조하는법
- dot notation
- bracket notation
속성 제거하는법
- undefined -값만 제거
- delete - 속성 제거
<button onclick="test1();">객체생성</button>
const test1 = () => {
const obj1 = {
id : 'honggd',
name : '홍길동',
age : 33,
married : true,
hobby : ['축구', '야구', '농구'],
pet : {
name : '구리구리',
breed : '푸들',
age : 5
},
'phone number' : '01012341234',
'ss-number' : '900909-1234567',
123 : 456
}; // 리터럴
const obj2 = new Object();
obj2.name = '세종대왕';
console.log(obj1);
console.log(obj2);
console.log(obj1['id']);
console.log(obj1['name']);
console.log(obj1['age']);
console.log(obj1['married']);
console.log(obj1['hobby'][0], obj1['hobby'][1], obj1['hobby'][2]);
console.log(obj1['pet']['name'], obj1['pet'].breed, obj1['pet'].age);
console.log(obj1[123], obj1['123'], obj1['phone number'], obj1['ss-number']); // 456 456 '01012341234' '900909-1234567'
console.log(obj1.car); // undefined
console.log(obj1.car.name); //오류발생
// 동적으로 속성추가
obj1.friend = {
name : '신사임당'
};
// 속성 제거
obj1.age = undefined; // 값만 제거
delete obj1.age; // 속성 제거
객체 전체를 부르면 { } 안에 객체들이 전부 나온다.
하나하나 부르면 위와 같이 나온다.
obj1.pet.age 처럼 부르는 것을 dot-notation이라고 한다.
dot-notation은 특수문자가 포함되거나 띄어쓰기가 있으면 사용이 불가능해서 bracket notation을 사용한다.
obj1['pet'].age 처럼 부르는 것을 bracket-notation이라고 한다.
없는 속성명 car를 부를 경우 undefined로 나오고, car의 또다른속성 name을 부르면 오류가 발생한다. (car가 undefined 이기 때문)
obj1.friend = { name : '신사임당 }; 처럼 동적으로 추가도 가능하다.
obj.age=undefined; 는 값만 제거한다.
delete obj.age; 는 속성 자체를 제거한다.
메소드
객체의 속성타입이 함수일때, 이를 메소드라고 한다.
this용법 5. 메소드(일반함수)안에서 this는 현재 객체이다.
메소드 작성시에는 화살표 함수를 지양한다.
메소드 단축 문법이 존재한다.
const test2 = () => {
const pet = {
petname : '복실이',
run : function(){
// this용법5. 메소드(일반함수)안에서 this는 현재객체이다.
console.log(this); // 현재객체 pet
console.log(`${this.petname}가 달린다.`);
},
// 메소드 작성시에는 화살표함수를 지양한다.
jump : () => {
// this - window
console.log(`${this.petname}가 점프한다.`);
},
bark(){
// 메소드 단축문법
console.log(`${this.petname}가 짖는다.`);
},
eat(food){
console.log(`${this.petname}가 ${food}를 먹는다.`);
}
};
console.log(typeof pet.run, pet.run);
// console.log(typeof pet['run'], pet['run']);
pet.run(); // 복실이가 달린다.
// pet['run']();
pet.jump(); // undefined가 점프한다.
pet.bark(); // 복실이가 짖는다.
pet.eat('개껌'); // 복실이가 개껌을 먹는다.
};
Object API
for (const _ in 객체명) : 객체속성 순회
Object.keys( ) : [ ] : 객체의 속성명+내용 조회
Object.values( ) : [ ] : 객체의 속성내용 조회
const test3 = () => {
const obj = {
name : '아이폰',
price : 1_000_000,
color : ['red', 'black', 'white'],
}
// 객체속성 순회
// for..in
for(const name in obj){
console.log(name, obj[name]);
}
// Object.keys():[]
const keys = Object.keys(obj);
console.log(keys);
keys.forEach((key) => {
console.log(key, obj[key]);
});
// Object.values():[]
const values = Object.values(obj);
console.log(values);
}
단축속성문법 (ES6)
속성명 : 속성값
속성으로 변수를 전달하면 , 자동으로 '변수병 : 값' 으로 처리된다.
const test5=()=>{
const name='홍길동';
const lang='Javascript';
const dev={
name:name,//위의 name과 아무 관련없음
lang:lang
};
console.log(dev);
}
dev가 제대로 전달한 것을 확인할 수 있다.
const test5=()=>{
const name='홍길동';
const lang='Javascript';
// const dev={
// name:name,//위의 name과 아무 관련없음
// lang:lang
// };
const dev={name,lang}; //위랑 같음
console.log(dev);
}
위랑 똑같이 나온다!
const test5=()=>{
const name='홍길동';
const lang='Javascript';
const dev={
name,lang,career:10
};
console.log(dev);
}
없는 변수를 추가해서 선언 후 넣어도 값이 제대로 나오는 것을 확인할 수 있다.