defineProperty()는 객체에 새로운 속성을 직접 정의하거나 이미 존재하는 속성을 수정한 후, 해당 객체를 반환하는 메서드이다. 그런데 나의 경우에는 이런 메서드를 사용하지 않고 직접 객체에 접근하여 새로운 속성을 할당했는데 그동안 몰랐던 차이점이 있었다.
사실, 객체의 프로퍼티에는 플래그라 불리는 특별한 속성 세가지가 있으며 기존방식으로 직접 객체에 접근하여 할당한 프로퍼티는 다음 플래그의 값들을 true값으로 세팅하게 된다.
true이면 값을 수정할 수 있다. 그렇지 않다면 읽기만 가능하다.
true이면 반복문을 사용해 나열할 수 있다. 그렇지 않다면 반복문을 사용해 나열할 수 없다.
true이면 프로퍼티 삭제나 플래그 수정이 가능하다. 그렇지 않다면 프로퍼티 삭제와 플래그 수정이 불가능하다.
반면에 defineProperty()를 사용하여 생성한 속성값은 위의 플래그의 값들을 false값으로 세팅한다. 그래서 다음과 같이 접근하여 기존값을 수정한다고해도 변하지 않는 것을 볼 수 있다.
그리고 이미 정의되어 있는 속성의 경우에도 해당 메서드를 사용하여 플래그 수정을 할 수가 있다.
문자열의 일부분을 하이라이트하고 싶어 jsx내부에서 replace() 메서드를 사용하여 치환하였지만 다음과 같이 생각했던대로 동작하지 않았다.
<p>하이라이트전 [object Object] 하이라이트 후</p>
원인은 repalce() 메서드를 사용하게 되면 반환되는 값이 새로운 문자열로 중간에 치환해버리기 때문이었다.
예시상황
const test = <div>hell</div>; console.log(test.toString()); // [object Object]
해결방법은 간단하다. 중간에 문자열로 바꿔버리는 replace()메서드 대신 태그를 그대로 살릴 수 있도록 커스텀 함수를 구현해주면 된다.
const title = '노란색 단지';
// 반환되는 값
[<span>노란색 </span>, <mark class="hl">단지</mark>]
예를 들면 특정키워드만 하이트라이트하는 예시라면 해당 키워드로 문자열로 쪼갠 뒤, 태그 그대로를 반환해주는 함수를 만들면 되는데 중복적으로 들어가는 배열의 마지막 요소만 제거하는 것만 주의해주면 된다.
function flatMap(array: string[], fn: (part: string) => IDom[]) {
const result = [];
for (let i = 0; i < array.length; i += 1) {
const mapping = fn(array[i]);
result.push(mapping);
}
return result.flat();
}
const keyword = '단지';
const markedTitle = flatMap(title.split(keyword), (part: string) => {
if (part === '') return [<mark class="hl">{keyword}</mark>];
return [<span>{part}</span>, <mark class="hl">{keyword}</mark>];
});
markedTitle.pop();
return markedTitle;