Как jQuery data() нарушает циклическую ссылку
Я прочитал, почему это лучше и как это реализовано. Но что я на самом деле не понимаю, как это нарушает круговую ссылку?,
как это разрывает контрольный круг?
$(div1).data('item', div2);
$(div2).data('item', div1);
Например, приведенные выше элементы указывают друг на друга, как это предотвратить? У меня есть догадка, но я просто хочу убедиться, что моя догадка верна.
1 ответ
Проблема циклической ссылки возникает в некоторых браузерах, когда вы помещаете ссылку на объект DOM на объект DOM как свойство этого объекта DOM. Затем у вас есть два объекта DOM, указывающих друг на друга. Удаление объекта DOM с пользовательским свойством не очищает это пользовательское свойство. Сборщик мусора, который не настолько умен, не понимает, что эта ссылка на DOM не считается, поэтому он застревает, и есть несколько способов, которые могут привести к утечкам.
.data()
решает эту проблему, потому что .data()
данные НЕ находятся на объекте DOM. Это просто структура данных javascript, которая может быть связана с объектом DOM через уникальный идентификатор строки.
Единственная запутанная часть этого заключается в том, что когда вы читаете .data("key")
и key
не найден в JavaScript .data()
структура данных, тогда и только тогда, jQuery будет искать атрибут в объекте DOM, называемый "data-key"
, Но всякий раз, когда вы пишете с .data("key", "myData")
, он никогда не пишет в объект DOM, только в структуру данных javascript.
Таким образом, так как .data()
никогда не записывает данные в объект DOM, не может быть таких циклических ссылок, с которыми у некоторых браузеров возникают проблемы.
Есть несколько других полезных вещей, которые нужно знать о .data()
структура данных. Когда вы используете JQuery's .remove()
удалить элементы из DOM или когда вы звоните $(elem).html("new html")
jQuery очищает .data()
данные о любых удаленных предметах. Это один из случаев, когда хорошо не смешивать jQuery с простым javascript. Если вы используете .data()
, то вы всегда должны удалять элементы из DOM, используя функции jQuery, так .data()
очищен соответствующим образом. В противном случае, вы можете получить утечки памяти таким образом (оба .data()
данные могут утечь, и любые удаленные объекты DOM, на которые есть ссылки в .data()
может протечь. Но, если вы используете только методы jQuery для удаления элементов из DOM (включая замену innerHTML), то jQuery очистит все соответствующим образом и не будет утечек.
Так, например, это создаст утечку памяти:
// suppose elem is a DOM element reference
// store some data in jQuery's data storage on behalf of a DOM element
$(elem).data("someKey", "someValue");
// remove DOM element with plain Javascript
elem.parentNode.removeChild(elem);
Поскольку вы удалили элемент DOM с простым Javascript, у jQuery не было возможности очистить ранее сохраненные данные. Сам элемент DOM будет собираться мусором, но .data()
ранее сохраненное вами значение теперь потеряно в хранилище jQuery и, по сути, является "утечкой", так как оно, вероятно, никогда не будет очищено. С другой стороны, если вы сделаете это:
$(elem).data("someKey", "someValue");
$(elem).remove();
Затем jQuery увидит, что вы удаляете элемент DOM, а также очистит данные, которые вы сохранили с .data()
,
Довольно простой способ понять, как это работает, - создать сценарий из нескольких строк с не минимизированной версией jQuery, а затем просто выполнить вызов $(elem).data("key", "whatever")
в отладчике и смотри как он работает.