前言:本文只分析 jQuery 调用 append(‘<script>alert(“xxx”)’) 后,jQuery 对 <script> 的处理,关于 append()、domManip()、buildFragment() 等处理 待插入元素的函数,请看:当我调用了$().append()后,jQuery内部发生了什么?1、有这样一段代码:<body> <script src=“jQuery.js”></script> <div class=“inner”></div> <script> $(’.inner’).append("<script>alert(‘append执行script’)") </script></body>2、当调用 $().append("<script>alert(‘append执行script’)") 时,jQuery 内部的流程如下:3、domManip 对 script 的处理源码: function domManip(collection, args, callback, ignored) { args = concat.apply([], args); var fragment, first, scripts, hasScripts, node, doc, i = 0, l = collection.length, iNoClone = l - 1, value = args[0] fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored) first = fragment.firstChild if (fragment.childNodes.length === 1) { fragment = first; } scripts = jQuery.map(getAll(fragment, “script”), disableScript); //script 1 /判断是否包含<script>标签/ hasScripts = scripts.length //根据selector的个数循环 for (; i < l; i++) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone(node, true, true); //如果有script标签了,就将其复制到scripts中 if (hasScripts) { jQuery.merge(scripts, getAll(node, “script”)); } } //此时的node已经是文本节点了 callback.call(collection[i], node, i); } //如果有<script>标签,就解析script if (hasScripts) { console.log(scripts, ‘scripts5932’) //script doc = scripts[scripts.length - 1].ownerDocument; //document jQuery.map(scripts, restoreScript); for (i = 0; i < hasScripts; i++) { node = scripts[i]; if (rscriptType.test(node.type || “”) && //https://www.cnblogs.com/gongshunkai/p/5905917.html !dataPriv.access(node, “globalEval”) && jQuery.contains(doc, node)) { //这边是处理<script scr=’’>的情况的 if (node.src && (node.type || “”).toLowerCase() !== “module”) { // Optional AJAX dependency, but won’t run scripts if not present if (jQuery._evalUrl) { console.log(’_evalUrl’, ‘_evalUrl5950’) jQuery._evalUrl(node.src); } } //一般走的这边 else { console.log(doc, node.nodeType,node, ‘DOMEval5954’) //document 1 <script>alert(‘append执行script’)< /script> DOMEval(node.textContent.replace(rcleanScript, “”), doc, node); } } } } return collection; }解析:(1)domManip 的 buildFragment() 返回文档碎片 fragment 后,会调用 domManip 自定义的 callback() 回调函数,在 <div class=“inner”></div> 中插入 <script>alert(‘append执行script’) 的文本 (2)之后,根据定义的变量 scripts 的长度,判断是否有 <script> 标签scripts = jQuery.map(getAll(fragment, “script”), disableScript)(3)如果待插入元素有 <script> 标签的话,对该元素进行处理(restoreScript ) //去除type标签 function restoreScript( elem ) { if ( ( elem.type || "" ).slice( 0, 5 ) === “true/” ) { elem.type = elem.type.slice( 5 ); } else { elem.removeAttribute( “type” ); } return elem; }(4)如果 <script> 没有属性 src 的话,就执行 DOMEval() 方法:① jQuery 自个儿生成 <script> 标签② 添加 待插入元素的文本③ 执行 appendChild() 方法 //解析script标签 //code:alert(‘append执行script’) #document //doc:document //node:<script>alert(‘append执行script’)< /script> function DOMEval(code, doc, node) { doc = doc || document; let i //创建script标签 let script = doc.createElement(“script”) //添加文本 script.text = code; if (node) { //i:type/src/noModule for (i in preservedScriptAttributes) { if (node[i]) { script[i] = node[i]; } } } //解析script核心代码 doc.head.appendChild(script).parentNode.removeChild(script); }本质:可以看到 jQuery 解析 <script> 的本质即document.head.appendChild(script).parentNode.removeChild(script)4、domManip 的 callback 函数会分两种情况处理 待插入元素(1)$(’.inner’).append("<script>alert(‘append执行script’)")最后在 target.appendChild(elem) 中,插入的不是 <script> 元素,而是 文本"<script>alert(‘append执行script’)" //源码6113行左右 append: function() { return domManip( this, arguments, function( elem ) { … … 最后 console.log(elem.firstChild.nodeType,’target6016’) //3:文本节点 target.appendChild( elem ); }})},(2)$(’.inner’).append("<span>aaa</span>")最后在 target.appendChild(elem) 中,插入的是 <span>aaa</span> 元素 console.log(elem.firstChild.nodeType,’target6016’) //1:元素节点 target.appendChild( elem );5、最后的最后Github:https://github.com/AttackXiao…(完)