ECMAScript 객체 수정
- 이전 페이지 클래스나 객체 정의
- 다음 페이지 thừa kế 메커니즘 예제
ECMAScript를 사용하면 객체를 생성할 뿐만 아니라 기존 객체의 행동을 수정할 수 있습니다.
prototype 속성은 생성자 함수의 속성과 메서드를 정의할 뿐만 아니라 로컬 객체에 속성과 메서드를 추가할 수 있습니다.
새 메서드 생성
기존 메서드를 통해 새 메서드 생성
prototype 속성을 사용하여 어떤 기존 클래스에도 새 메서드를 정의할 수 있습니다. 예를 들어, Number 클래스의 toString() 메서드를 기억하십니까? 16을 전달하면 16진수 문자열을 출력하며, 2를 전달하면 2진수 문자열을 출력합니다. 숫자 객체를 직접 16진수 문자열로 변환할 수 있는 메서드를 생성할 수 있습니다. 이 메서드를 생성하는 것은 매우 간단합니다:
Number.prototype.toHexString = function() { return this.toString(16); };
이 환경에서 키워드 this는 Number 인스턴스를 가리키며, 따라서 Number의 모든 메서드에 완전히 접근할 수 있습니다. 이 코드를 통해 다음과 같은 작업을 수행할 수 있습니다:
var iNum = 15; alert(iNum.toHexString()); // "F"
숫자 15는 16진수에서 'F'와 일치합니다. 따라서 경고는 'F'를 표시합니다.
기존 메서드 이름 변경
기존 메서드의 이름을 더 이해하기 쉬운 이름으로 변경할 수도 있습니다. 예를 들어, Array 클래스에 enqueue()와 dequeue() 메서드를 추가할 수 있습니다. 이 메서드는 push()와 shift() 메서드를 반복적으로 호출하는 것만으로도 됩니다:
Array.prototype.enqueue = function(vItem) { this.push(vItem); }; Array.prototype.dequeue = function() { return this.shift(); };
기존 메서드와 관련이 없는 메서드 추가
물론, 기존 메서드와 관련이 없는 메서드를 추가할 수도 있습니다. 예를 들어, 배열에서 특정 항목의 위치를 판단해야 하는 경우에 기존 메서드가 없다면, 아래와 같은 메서드를 쉽게 생성할 수 있습니다:
Array.prototype.indexOf = function (vItem) { for (var i=0; i<this.length; i++) { if (vItem == this[i]) { return i; } } return -1; }
이 메서드 indexOf()는 String 클래스의同名 메서드와 일치하며, 배열에서 각 항목을 검색하여传入된 항목과 일치하는 항목을 찾을 때까지 검색합니다. 같은 항목을 찾으면 해당 항목의 위치를 반환하고, 찾지 못하면 -1을 반환합니다. 이 정의를 가지고 있기 때문에 다음과 같은 코드를 작성할 수 있습니다:
var aColors = new Array("red","green","blue"); alert(aColors.indexOf("green")); // "1" 출력
로컬 객체에 새 메서드 추가
마지막으로, ECMAScript의 모든 로컬 객체에 새 메서드를 추가하려면, Object 객체의 prototype 속성에 정의해야 합니다. 이전 장에서 설명한 것처럼, 모든 로컬 객체는 Object 객체를 상속받기 때문에, Object 객체에 어떤 변경을 가하더라도 모든 로컬 객체에 반영됩니다. 예를 들어, 객체의 현재 값을 경고 메시지로 출력하는 메서드를 추가하려면 다음과 같은 코드를 사용할 수 있습니다:
Object.prototype.showValue = function () { alert(this.valueOf()); }; var str = "hello"; var iNum = 25; str.showValue(); // "hello" 출력 iNum.showValue(); // "25" 출력
여기서 String과 Number 객체는 Object 객체에서 showValue() 메서드를 상속받았으며, 각 객체에서 이 메서드를 호출하면 "hello"와 "25"를 출력합니다.
기존 메서드 재정의
기존 클래스에 새 메서드를 정의할 수 있듯이, 기존 메서드를 재정의할 수도 있습니다. 이전 장에서 설명한 것처럼, 함수 이름은 함수를 가리키는 포인터이므로 다른 함수로 쉽게 지정할 수 있습니다. 지역 메서드를 수정했을 때 어떤 일이 일어날까요? toString()와 같은 메서드를 수정했습니다.
Function.prototype.toString = function() { return "Function code hidden"; }
이전 코드는 완전히 유효하며, 실행 결과는 예상과 일치합니다:
function sayHi() { alert("hi"); } alert(sayHi.toString()); // "Function code hidden" 출력
아마도 기억할 수 있을 것입니다. Function 객체 이론에서 Function toString() 메서드는 일반적으로 함수의 소스 코드를 출력합니다. 이 메서드를 오버라이드하면 다른 문자열을 반환할 수 있습니다. 이 예제에서는 "Function code hidden"를 반환할 수 있습니다. 그러나 toString() 메서드가 가리키는 원래 함수는 어떻게 되었을까요? 완전히 버려진 상태로 무용한 저장 공간 회수 프로그램에 회수됩니다. 원래 함수를 복구할 수 있는 방법이 없기 때문에, 원래 메서드를 오버라이드하기 전에 그 포인터를 저장하는 것이 더 안전합니다. 때로는 새 메서드에서 원래 메서드를 호출할 수도 있습니다:
Function.prototype.originalToString = Function.prototype.toString; Function.prototype.toString = function() { if (this.originalToString().length > 100) { return "함수가 표시할 수 없이 길다."; } else { return this.originalToString(); } };
이 코드에서 첫 번째 줄은 현재 toString() 메서드에 대한 참조를 원본 toString() 속성에 저장합니다. 그런 다음 맞춤형 메서드를 사용하여 toString() 메서드를 대체합니다. 새 메서드는 함수 소스 코드의 길이가 100보다 크면 오류 메시지를 반환하고, 그렇지 않으면 원본 toString() 메서드를 호출하여 함수 소스 코드를 반환합니다.
최종 바인딩(Very Late Binding)
기술적으로, 최종 바인딩은 존재하지 않습니다. 이 책은 ECMAScript에서 객체가 인스턴스화된 후에 메서드를 정의할 수 있는 현상을 이 표현으로 사용합니다. 예를 들어:
var o = new Object(); Object.prototype.sayHi = function () { alert("hi"); }; o.sayHi();
대부분의 프로그래밍 언어에서는 객체를 인스턴스화하기 전에 객체의 메서드를 정의해야 합니다. 여기서는 메서드 sayHi()가 Object 클래스의 인스턴스를 생성한 후에 추가되었습니다. 전통적인 언어에서 이러한 작업을 들어보지도 않았고, 이 메서드가 Object 객체의 인스턴스에 자동으로 할당되고 즉시 사용할 수 있다는 것도 들어보지도 않았습니다.
주의:최종 바인딩 메서드를 사용하지 않는 것이 좋습니다. 이 메서드를 추적하고 기록하는 것이 어렵기 때문입니다. 그러나 이러한 가능성을 이해해야 합니다.
- 이전 페이지 클래스나 객체 정의
- 다음 페이지 thừa kế 메커니즘 예제