실제로 innerHTML보다 createElement를 사용하면 어떤 이점이 있습니까? innerHTML을 사용하는 것이 성능 및 코드 가독성 / 유지 보수 측면에서 더 효율적이라고 확신하기 때문에 질문하고 있지만 팀원들은 코딩 접근 방식으로 createElement를 사용하기로 결정했습니다. createElement가 어떻게 더 효율적일 수 있는지 이해하고 싶습니다.
답변:
Pekka가 이미 언급했듯이 안전 외에도 createElement수정 innerHTML(이미있는 것을 버리고 교체하는 것과는 반대로) 대신 사용 하는 데는 몇 가지 이점이 있습니다 .
에 추가 (또는 수정) 할 때 innerHTML해당 요소 내의 모든 DOM 노드를 다시 구문 분석하고 다시 만들어야합니다. 노드에 대한 참조를 저장하면 더 이상 표시되지 않기 때문에 본질적으로 쓸모가 없습니다.
이것은 마지막 경우의 특별한 경우 (일반적이지만)입니다. 설정 innerHTML은 생성 된 새 요소에 이벤트 핸들러를 자동으로 다시 연결하지 않으므로 직접 추적하고 수동으로 추가해야합니다. 이벤트 위임은 경우에 따라이 문제를 해결할 수 있습니다.
많은 추가 작업을 수행하는 경우, innerHTML단순한 변경의 경우 더 빠르지 만 반복적으로 다시 구문 분석하고 요소를 만드는 속도가 더 느리기 때문에 재설정을 계속하고 싶지는 않습니다 . 이 문제를 해결하는 방법은 HTML을 문자열로 작성하고 innerHTML완료되면 한 번 설정 하는 것입니다. 상황에 따라 문자열 조작은 단순히 요소를 만들고 추가하는 것보다 느릴 수 있습니다.
또한 문자열 조작 코드가 더 복잡 할 수 있습니다 (특히 안전을 원하는 경우).
다음은 사용하기 더 편리하도록 가끔 사용하는 기능 createElement입니다.
function isArray(a) {
return Object.prototype.toString.call(a) === "[object Array]";
}
function make(desc) {
if (!isArray(desc)) {
return make.call(this, Array.prototype.slice.call(arguments));
}
var name = desc[0];
var attributes = desc[1];
var el = document.createElement(name);
var start = 1;
if (typeof attributes === "object" && attributes !== null && !isArray(attributes)) {
for (var attr in attributes) {
el[attr] = attributes[attr];
}
start = 2;
}
for (var i = start; i < desc.length; i++) {
if (isArray(desc[i])) {
el.appendChild(make(desc[i]));
}
else {
el.appendChild(document.createTextNode(desc[i]));
}
}
return el;
}
다음과 같이 부르면 :
make(["p", "Here is a ", ["a", { href:"http://www.google.com/" }, "link"], "."]);
다음과 같은 HTML을 얻을 수 있습니다.
<p>Here is a <a href="http://www.google.com/">link</a>.</p>
make함수가 조금 더 쉽게 만들 수있는 또 다른 것 ).
innerHTML단점 때문에 피 합니다. 복잡한 마크 업 (예 : 테이블 작성)의 경우 일반적으로 마크 업의 각 부분을 생성하는 함수를 작성합니다. 예를 들어, tr각 행의 데이터에서 를 생성하는 함수가 있습니다 . 그런 다음 행을 테이블로 결합하는 다른 기능이있을 수 있습니다. 각 함수 make는 적절한 인수 로 호출 하는 것처럼 간단 할 수 있습니다 . 성능이 문제가되면 HTML 문자열을 반환하도록 함수를 변경할 수 있습니다.
innerHTML더 빠를 수 있지만 가독성이나 유지 관리 측면에서 더 좋다는 데 동의하지 않습니다. 모든 것을 하나의 문자열에 넣는 것이 더 짧을 수 있지만 코드가 짧다고 항상 유지 관리가 더 쉬운 것은 아닙니다.
문자열 연결은 더하기 '와 따옴표 열기 및 닫기를 추적하기 어려워 지므로 동적 DOM 요소를 만들어야하는 경우에만 확장되지 않습니다. 다음 예를 고려하십시오.
결과 요소는 콘텐츠가 동적 인 두 개의 내부 범위가있는 div입니다. 첫 번째 범위 내의 클래스 이름 (전사) 중 하나도 동적입니다.
<div>
<span class="person warrior">John Doe</span>
<span class="time">30th May, 2010</span>
</div>
다음 변수가 이미 정의되어 있다고 가정합니다.
var personClass = 'warrior';
var personName = 'John Doe';
var date = '30th May, 2010';
innerHTML 만 사용하고 모든 것을 단일 문자열로 매싱하면 다음을 얻을 수 있습니다.
someElement.innerHTML = "<div><span class='person " + personClass + "'>" + personName + "</span><span class='time'>" + date + "</span></div>";
위의 혼란은 매번 문자열을 열고 닫지 않도록 문자열 교체를 사용하여 정리할 수 있습니다. 간단한 텍스트 교체의 경우에도 replace문자열 연결 대신 사용 하는 것을 선호합니다 .
이것은 키와 대체 값의 객체를 가져와 문자열에서 대체하는 간단한 함수입니다. 키가 $특수 값임을 나타 내기 위해 접두사가 붙은 것으로 가정합니다 . $대체 값 등에 나타나는 이스케이프 또는 가장자리 케이스를 처리하지 않습니다 .
function replaceAll(string, map) {
for(key in map) {
string = string.replace("$" + key, map[key]);
}
return string;
}
var string = '<div><span class="person $type">$name</span><span class="time">$date</span></div>';
var html = replaceAll(string, {
type: personClass,
name: personName,
date: date
});
someElement.innerHTML = html;
객체를 구성하는 동안 속성, 텍스트 등을 분리하여 요소 구성을보다 프로그래밍 방식으로 제어함으로써 개선 할 수 있습니다. 예를 들어 MooTools를 사용하면 객체 속성을 맵으로 전달할 수 있습니다. 이것은 확실히 더 유지 관리가 가능하며 더 읽기 쉽다고 주장합니다. jQuery 1.4는 유사한 구문을 사용하여 DOM 객체를 초기화하기위한 맵을 전달합니다.
var div = new Element('div');
var person = new Element('span', {
'class': 'person ' + personClass,
'text': personName
});
var when = new Element('span', {
'class': 'time',
'text': date
});
div.adopt([person, when]);
아래의 순수한 DOM 접근 방식을 위의 것보다 더 읽기 쉽게 부르지는 않겠지 만 여는 / 닫는 따옴표와 수많은 더하기 기호를 추적 할 필요가 없기 때문에 확실히 유지 관리가 더 쉽습니다.
var div = document.createElement('div');
var person = document.createElement('span');
person.className = 'person ' + personClass;
person.appendChild(document.createTextNode(personName));
var when = document.createElement('span');
when.className = 'date';
when.appendChild(document.createTextNode(date));
div.appendChild(person);
div.appendChild(when);
가장 읽기 쉬운 버전은 일종의 자바 스크립트 템플릿 을 사용한 결과 일 가능성이 큽니다 .
<div id="personTemplate">
<span class="person <%= type %>"><%= name %></span>
<span class="time"><%= date %></span>
</div>
var div = $("#personTemplate").create({
name: personName,
type: personClass,
date: date
});
var a = hello.하지만 귀하의 코드를 알아낼 수 있습니다. 하나의 연결된 문자열보다 더 읽기 쉬워 보입니다.
innerHTML더 빨리? jsperf.com/innerhtml-vs-createelement-and-appendchild
사용자 bobince 는 jQuery에 대한 그의 비판 에서 여러 가지 단점을 매우 잘 설명 합니다.
... 또한 document.createElement ( 'div') 및 텍스트 노드를 사용하지 않고 $ ( "+ message + '')라고 말하여 div를 만들 수 있습니다. 만세! 단지 ... 잠시만 요. HTML에서 벗어나지 않았고 이번에는 클라이언트 측에서만 크로스 사이트 스크립팅 보안 허점을 만들었을 것입니다. 그리고 서버 측에서도 htmlspecialchars를 사용하기 위해 PHP를 너무 오랫동안 정리 한 후에. 부끄러운 일입니다. 아 글쎄, 아무도 정확성이나 보안에 대해 정말로 신경 쓰지 않습니까?
jQuery는 이것에 대해 전적으로 책임이 없습니다. 결국 innerHTML 속성은 몇 년 동안 사용되어 왔으며 이미 DOM보다 더 인기가 있음이 입증되었습니다. 그러나 라이브러리는 확실히 그러한 코딩 스타일을 장려합니다.
성능에 관해서 : InnerHTML은 파싱되고 내부적으로 DOM 요소로 변환되어야하기 때문에 (아마도createElement 메서드를 ) 입니다.
InnerHTML은 다음에 따라 모든 브라우저에서 더 빠릅니다. 제공 quirksmode 벤치 마크 .
가독성 과 사용 편의성에 관해서 는 대부분의 프로젝트에서 요일을 선택 innerHTML하는 것이 createElement좋습니다. 그러나 보시다시피 createElement.
innerHTML? 나는 그것이 확실히 거짓이라는 것을 오랫동안 알고 있습니다. innerHTML실제로 사용 하는 것은 일부 브라우저 (추측)의 극적인 성능 이점 때문에 프레임 워크 내부에서 인기를 얻었습니다.
createElement. 이것은 첫 단계에서하는 일이다. 그렇지 않다고 말하는 벤치 마크를 알고 있다면 기꺼이 바로 잡을 것입니다.
코드에서 참조를 유지하려면 createElement를 사용해야합니다. InnerHTML은 때때로 발견하기 어려운 버그를 생성 할 수 있습니다.
HTML 코드 :
<p id="parent">sample <span id='test'>text</span> about anything</p>
JS 코드 :
var test = document.getElementById("test");
test.style.color = "red"; //1 - it works
document.getElementById("parent").innerHTML += "whatever";
test.style.color = "green"; //2 - oooops
1) 색상을 변경할 수 있습니다.
2) 위의 줄에서 innerHTML에 무언가를 추가하고 모든 것이 다시 생성되고 더 이상 존재하지 않는 것에 액세스 할 수 있기 때문에 더 이상 색상이나 다른 것을 변경할 수 없습니다. 변경하려면 다시 getElementById 해야합니다 .
모든 이벤트에도 영향을 미친다는 점을 기억해야합니다. 이벤트를 다시 신청해야합니다.
InnerHTML은 더 빠르고 읽기가 더 쉬우므로 훌륭하지만주의해서 사용해야합니다. 당신이 무엇을하고 있는지 안다면 당신은 괜찮을 것입니다.
템플릿 리터럴 (템플릿 문자열)은 또 다른 옵션입니다.
const container = document.getElementById("container");
const item_value = "some Value";
const item = `<div>${item_value}</div>`
container.innerHTML = item;