블로그 이미지
초딩입맛제주아재
하고 싶은 것만 하며 살고 싶다

calendar

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
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 가 삭제되고 주소록 정보를 담았던 배열에서도 해당 데이터를 담고 있는 원소가 삭제된 후 인덱스를


전개

배열의 원소를 삭제하고 인덱스를 정렬하는 알고리듬을 생각해보면 다음과 같은 절차를 거친다.

  1. 삭제할 원소의 인덱스 직전까지의 원소들과 이후의 원소들을 분리시킨다.
  2. 분리된 원소들을 하나의 배열로 합친다.
원리는 무척 간단해 보인다.
방법이 문제다.
어떻게 배열을 둘로 나눌지...

본인은 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;

주의해야 할점은 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;


어째 좀 이상하지 않은가??
자신이 소유하고 있는 메소드에서 자신을 바꾸려하다니....
익스플로러에서는 this에 할당 할 수 없다는 오류가 발생한다.
시도 자체가 말이 안되는 행위였다...-_-;;

그래서 다음과 같은 알고리듬을 생각했다.
  1. 위,아래 원소를 분리하고 합치는것까지는 동일
  2. 원본배열의 원소를 전부 제거
  3. 새로 만들어진 배열의 원소를 원본배열에 모두 추가
[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());
   }

이제 제대로 작동한다~

그런데 웬지 모르게 메소드가 지저분해 보인다.
for에 while이 두개씩이나...반복문이 세번이나 돌아간다...

그리하여 또 다시 머리를 쥐어짰다.
  1. 원본 배열에서 주어진 인덱스부터 마지막 원소까지 모두 추출한다.
  2. 추출된 배열에서 마지막 원소는 제거할 원소이므로 빼버린다.
  3. 남은 원소들을 원본 배열에 추가한다.
  
[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());
   }


결말

[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]);
   }

중간에 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>

posted by 초딩입맛제주아재