2007. 3. 28. 13:22
Programing/HTML/JavaScript/CSS
개요
이번에 AJAX 실전 테스트용 주소록 코드를 만들면서 배열의 remove 기능이 필요해서 Javascript API를 보니 Array 객체에 remove 메소드가 없다.(혹시 필자가 못찾은 거라면 낭패 -_-.... 찾은분은 알려주시길..)
코어에서 지원이 안되니 직접 만들수 밖에 없었다.
본인이 손수만든 Array.remove() 메소드를 공개한다.
누누히 당부드리지만 본인은 신이 아니고 프로그래밍 도사도 아니기에 실수도 할 수 있고 효율이 떨어지는 코드를 남발할수도 있다. 조언과 지적은 감사히 수용하겠으나 막가파식 테클은 반사다...:)
발단
주소록의 정보를 배열에 담았다가 삭제할때 인덱스를 테이블 ROW(tr)과 일치시켜 주어야 하기때문에
인덱스의 재정렬이 필요했다.
* tableSection.deleteRow() 메서드는 자동으로 ROW의 인덱스가 재정렬한다.
* http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-67417573 참고.
주소록 리스트 - 여기서 데이터를 삭제하면...
테이블 ROW 가 삭제되고 주소록 정보를 담았던 배열에서도 해당 데이터를 담고 있는 원소가 삭제된 후 인덱스를
전개
배열의 원소를 삭제하고 인덱스를 정렬하는 알고리듬을 생각해보면 다음과 같은 절차를 거친다.
- 삭제할 원소의 인덱스 직전까지의 원소들과 이후의 원소들을 분리시킨다.
- 분리된 원소들을 하나의 배열로 합친다.
방법이 문제다.
어떻게 배열을 둘로 나눌지...
본인은 API를 보던중 slice 라는 메소드를 찾았다.
출처 : http://www.w3schools.com/jsref/jsref_slice_array.asp
Definition and Usage
The slice() method returns selected elements from an existing array.
Syntax
arrayObject.slice(start,end) |
Parameter | Description |
---|---|
start | Required. Specify where to start the selection. Must be a number |
end | Optional. Specify where to end the selection. Must be a number |
Tips and Notes
Tip: You can use negative numbers to select from the end of the array.
Note: If end is not specified, slice() selects all elements from the specified start position and to the end of the array.
이 메소드를 사용하면 간단하게 해결될것 같지 않은가?
그리하여 다음과 같은 코드를 만들었다.
//addressbook 는 주소록 정보를 가지고 있는 배열이다.
var temp_head = addressbook.slice(0,rowIndex);
var temp_body = addressbook.slice(rowIndex + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
addressbook = temp_head;
var temp_head = addressbook.slice(0,rowIndex);
var temp_body = addressbook.slice(rowIndex + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
addressbook = temp_head;
주의해야 할점은 slice메소드의 첫번째 인자와 두번째 인자의 시작 위치가 다르다는 것이다.
start값은 0부터 시작하는 배열의 첨자값을, end값은 1부터 시작하는 배열의 length 값을 의미한다.
절정
위 코드를 만들고 나니 아무래도 remove 기능을 모든 배열에서 쓰게 하는게 낫겠다는 생각이 들었다.
Array객체에 prototype으로 remove 메서드를 추가하기로 했다.
Array.prototype.remove = function(index){}
처음엔 위의 코드를 그대로 복사해서 가져다 붙였다. Ctrl + c, Ctrl + v 신공...
[code 1]
var temp_head = this.slice(0,index);
var temp_body = this.slice(index + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
this = temp_head;
var temp_head = this.slice(0,index);
var temp_body = this.slice(index + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
this = temp_head;
어째 좀 이상하지 않은가??
자신이 소유하고 있는 메소드에서 자신을 바꾸려하다니....
익스플로러에서는 this에 할당 할 수 없다는 오류가 발생한다.
시도 자체가 말이 안되는 행위였다...-_-;;
그래서 다음과 같은 알고리듬을 생각했다.
- 위,아래 원소를 분리하고 합치는것까지는 동일
- 원본배열의 원소를 전부 제거
- 새로 만들어진 배열의 원소를 원본배열에 모두 추가
[code 2]
var temp_head = this.slice(0,idx);
var temp_body = this.slice(idx + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
while(this.length > 0){
this.pop(); //shift 를 사용해도 된다.
}
while(temp_head.length > 0){
this.push(temp_head.shift());
}
var temp_head = this.slice(0,idx);
var temp_body = this.slice(idx + 1);
for(var i=0; i<temp_body.length; i++){
temp_head.push(temp_body[i]);
}
while(this.length > 0){
this.pop(); //shift 를 사용해도 된다.
}
while(temp_head.length > 0){
this.push(temp_head.shift());
}
이제 제대로 작동한다~
그런데 웬지 모르게 메소드가 지저분해 보인다.
for에 while이 두개씩이나...반복문이 세번이나 돌아간다...
그리하여 또 다시 머리를 쥐어짰다.
- 원본 배열에서 주어진 인덱스부터 마지막 원소까지 모두 추출한다.
- 추출된 배열에서 마지막 원소는 제거할 원소이므로 빼버린다.
- 남은 원소들을 원본 배열에 추가한다.
[code 3]
var temp = new Array();
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
temp.pop();
while(temp.length > 0){
this.push(temp.pop());
}
var temp = new Array();
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
temp.pop();
while(temp.length > 0){
this.push(temp.pop());
}
결말
[code 2]와 [code 3] 의 효율성의 차이는 정확히 파악하지 못했다.
단지 보기에 깔끔하고 반복문을 한번 덜 쓴다는 이유로 [code 3]을 주소록에 적용을 했다.
[code 3]의 경우 아직 리팩토링의 소지가 있는데 바로 두번째 while 블럭 이다.
조건절에서는 함수나 메소드의 호출을 지양해야 하기 때문인데
다음과 같이 수정 할 수 있다.
var temp = new Array();
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
for(var i=temp.length - 2; i>=0; i--){
this.push(temp[i]);
}
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
for(var i=temp.length - 2; i>=0; i--){
this.push(temp[i]);
}
중간에 temp.pop()이 필요가 없어졌고 for문을 사용한다.
조건절에서는 i가 0이상인지만 비교하면 된다.
사용예)
<script type="text/javascript">
Array.prototype.remove = function(idx){
var temp = new Array();
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
for(var i=temp.length - 2; i>=0; i--){
this.push(temp[i]);
}
}
var arr = new Array(6)
arr[0] = "Jani"
arr[1] = "Hege"
arr[2] = "Stale"
arr[3] = "Kai Jim"
arr[4] = "Borge"
arr[5] = "Tove"
document.write(arr + "<br />")
arr.remove(1);
document.write(arr + "<br />")
</script>
Array.prototype.remove = function(idx){
var temp = new Array();
var i = this.length;
while(i > idx){
var kk = this.pop();
temp.push(kk);
i--;
}
for(var i=temp.length - 2; i>=0; i--){
this.push(temp[i]);
}
}
var arr = new Array(6)
arr[0] = "Jani"
arr[1] = "Hege"
arr[2] = "Stale"
arr[3] = "Kai Jim"
arr[4] = "Borge"
arr[5] = "Tove"
document.write(arr + "<br />")
arr.remove(1);
document.write(arr + "<br />")
</script>
'Programing > HTML/JavaScript/CSS' 카테고리의 다른 글
Javascript 의 Object : new Object() ?===? {} (0) | 2007.04.06 |
---|---|
AJAX 실전 #2 - 주소록 구현 준비 (1) | 2007.03.30 |
AJAX 실전 #1 - XMLHttpRequest (0) | 2007.03.14 |
가로 세로 정중앙에 위치하는 레이어 만들기 (0) | 2007.02.15 |
[HTML] LABEL과 사용자 중심의 프로그래밍-UI (3) | 2007.01.05 |