JavaScript (JS)
Closer (클로저)
지역 변수를 외부에서도 참조(By Reference)할 수 있는 함수
함수 중첩을 이용해 함수 호출이 종료되더라도 그 함수의 지역 변수 및 지역 변수 체인 관계를 유지할 수 있는 구조를 갖는다.
내부에 선언된 함수 객체가 반환되어 계속 유지되는 상태 -> 그 함수 객체에 딸린 [[scope]]에서도 참조를 계속 유지하는 상태
부모 함수가 종료된 후에도 부모 함수의 Variable(Activation) Object는 가비지 콜렉팅 되지 않고 유지된다.
간단하게 생각하면 자바의 캡슐화와 유사하다고 생각하면 된다. 밖에서 사용하지 못하도록 감추는 것이다.
function func() {
var x = 1;
return {
increase : function() {
x++;
},
getX : function() {
return x;
}
}
}
var result = func();
result.increase;
console.log(result.getX());
result.increase;
console.log(result.getX());
위와 같은 방식으로 실행한다.
다른 사람이 개발할 때 변수 x 이름을 써야한다고 가정한다. 그런데 변수 x가 이미 존재하는지 모르고 사용해버려서 원하는 결과 값이 안 나오게 되는 것이다.
변수 x를 은닉화하고 함수명도 겹치지 않게 할 수 있다.
사용자 정의 객체
생성자 함수
사용자 정의 객체는 일반적인 함수 사용과 차이점이 있다.
함수와 구분하기 위해 이름의 첫 글자를 대문자로 한다.
this로 객체의 속성을 지정하고, this를 사용하면 해당 속성은 public 프로퍼티가 된다. (this 사용 시 public 개념이고, this가 없으면 private 개념이다.)
var Person = function(name) {
this.name = name;
this.intro = function() {
return 'I am ' + this.name;
}
}
var minsu = new person('minsu');
minsu.intro();
prototype
프로토타입 사용은 모든 객체에 동일한 내용이 적용되는 경우에 메모리를 낭비하지 않기 위해 사용한다.
이때 복사하지 않고 참조하여 사용하기 때문에 메모리 낭비가 되지 않는 것이다.
var Person = function(name) {
this.name = name;
Person.prototype.intro = function() {
return 'I am ' + this.name;
}
var minsu = new Person('minsu');
var suji = new Person('suji');
var jack = new Person('jack');
minsu.intro();
suji.intro();
jack.intro();
intro() 함수를 프로토타입으로 정의했다.
만약 프로토타입으로 정의하지 않았다면 minsu.intro();, suji.intro();, jack.intro(); 이렇게 총 세 번의 intro() 함수 호출 때문에 메모리에 intro() 함수가 세 번 올라갔을 것이다.
프로토타입으로 정의하였기 때문에 intro() 함수는 메모리에 한 번만 올라가고, 다른 객체가 이미 메모리에 올라간 intro() 함수를 참조하는 것이다.
프로토타입으로 정의하는 건 보통 두 가지 방법으로 사용된다.
Member.prototype.xxx = function() {
...
}
Member.prototype.yyy = function() {
...
}
Member.prototype.zzz = function() {
...
}
위 코드로 하면 복잡해보일 수 있기 때문에 보통 아래처럼 정의한다.
var Member function() {
Member.prototype = {
xxx : function() {...},
yyy : function() {...},
zzz : function() {...}
}
}
동적으로 메소드 추가
var Member = function(firstName, lasName) {
this.firstName = firstName;
this.lastName = lastName;
}
var mem1 = new Member('김', '철수');
mem1.getName = function() { // 생성한 인스턴스에 대해서 메서드 추가
return this.lastName + ' ' + this.firstName;
}
console.log(mem1.getName());
var mem2 = new Member('홍', '길동');
console.log(mem2.getName()); // 지원하지 않음
Member 사용자 정의 객체를 만든 뒤, new 키워드를 사용해 mem1객체를 생성하였다.
mem1 객체에서 getName()이라는 함수를 생성하였고, mem1 객체에서 사용 시 김철수라는 이름은 잘 출력된다.
mem2 객체를 생성하고, mem1에서 정의된 getName() 함수를 호출하였는데 이렇게 하면 오류가 발생한다.
mem1 메모리에 있는 변수에 getName을 지정하였고, mem2는 mem1 메모리에 있는 걸 참조하지 못해서 getName() 함수를 지원하지 못하는 것이다.
프로토타입을 사용하여 Member.prototype으로 getName() 함수를 선언하던가, mem1처럼 함수 정의를 해야 한다.
동일한 클래스를 기초로 생성된 인스턴스라 할지라도 각각이 가지는 멤버가 동일하다고 한정할 수 없다.
내장객체
Date 내장객체 사용
today = new Date();
str = "현재 " + today.getYear() + "년 ";
str += (today.getMonth() + 1) + "월 ";
str += today.getDate() + "일. <br><br>";
document.write(str);
str = "현재 " + today.getHours() + "시간 ";
str += (today.getMinutes() + 1) + "분 ";
str += today.getSeconds() + "초";
document.write(str);
History 내장객체 사용
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="button" onclick="javascript:history.back(-1)" value="history.back()"/>
<input type="button" onclick="javascript:history.forward(-1)" value="history.forward()"/>
<input type="button" onclick="javascript:history.go(-1)" value="history.go(-1)"/>
</body>
</html>
DOM (Document Object Model)
태그들을 조작하기 위해 사용하는 자바스크립트 함수로, 웹 개발 시 필수적이다.
문서에 대한 구조적 정보를 제공하고 문서 구조나 외양 및 내용을 바꿀 수 있도록 프로그램에서 접근할 수 있는 방법을 제공한다.
속성(프로퍼티)과 메서드를 가지는 객체와 노드의 트리형 구조로 표현된다.