[javascript] innerHTML에 비해 createElement의 장점은 무엇입니까?

실제로 innerHTML보다 createElement를 사용하면 어떤 이점이 있습니까? innerHTML을 사용하는 것이 성능 및 코드 가독성 / 유지 보수 측면에서 더 효율적이라고 확신하기 때문에 질문하고 있지만 팀원들은 코딩 접근 방식으로 createElement를 사용하기로 결정했습니다. createElement가 어떻게 더 효율적일 수 있는지 이해하고 싶습니다.



답변

Pekka가 이미 언급했듯이 안전 외에도 createElement수정 innerHTML(이미있는 것을 버리고 교체하는 것과는 반대로) 대신 사용 하는 데는 몇 가지 이점이 있습니다 .

요소를 추가 할 때 DOM 요소에 대한 기존 참조를 유지합니다.

에 추가 (또는 수정) 할 때 innerHTML해당 요소 내의 모든 DOM 노드를 다시 구문 분석하고 다시 만들어야합니다. 노드에 대한 참조를 저장하면 더 이상 표시되지 않기 때문에 본질적으로 쓸모가 없습니다.

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>


답변

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


답변

사용자 bobince 는 jQuery에 대한 그의 비판 에서 여러 가지 단점을 매우 잘 설명 합니다.

… 또한 document.createElement ( ‘div’) 및 텍스트 노드를 사용하지 않고 $ ( “+ message + ”)라고 말하여 div를 만들 수 있습니다. 만세! 단지 … 잠시만 요. HTML에서 벗어나지 않았고 이번에는 클라이언트 측에서만 크로스 사이트 스크립팅 보안 허점을 만들었을 것입니다. 그리고 서버 측에서도 htmlspecialchars를 사용하기 위해 PHP를 너무 오랫동안 정리 한 후에. 부끄러운 일입니다. 아 글쎄, 아무도 정확성이나 보안에 대해 정말로 신경 쓰지 않습니까?

jQuery는 이것에 대해 전적으로 책임이 없습니다. 결국 innerHTML 속성은 몇 년 동안 사용되어 왔으며 이미 DOM보다 더 인기가 있음이 입증되었습니다. 그러나 라이브러리는 확실히 그러한 코딩 스타일을 장려합니다.

성능에 관해서 : InnerHTML은 파싱되고 내부적으로 DOM 요소로 변환되어야하기 때문에 (아마도createElement 메서드를 ) 입니다.

InnerHTML은 다음에 따라 모든 브라우저에서 더 빠릅니다. 제공 quirksmode 벤치 마크 .

가독성 과 사용 편의성에 관해서 는 대부분의 프로젝트에서 요일을 선택 innerHTML하는 것이 createElement좋습니다. 그러나 보시다시피 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;


답변