优美编程读过源码才知道-JQuery(v3.3.1)

JQuery源码阅读1=>detach同级上

2018-04-22  本文已影响2人  小遁哥

$element.remove(selector)

JQuery中大部分DOM操作API,都支持传递选择器对原集合进行过滤,不传则意味着全部

很多方法作为公共函数,会应用到不同的场景,其中还结合了构建JQuery的核心对象。在阅读源码的过程中可以针对指定场景简单的了解下,不要过分尝试解读,比如access、clearData、buildFragment、domManip等

1 detach和remove

两者都用于移除,detach不会移除元素上的事件和数据。通过JQuery绑定、存储的。

detach: function( selector ) {
    return remove( this, selector, true );
},

remove: function( selector ) {
    return remove( this, selector );
},

1.1 remove

function remove( elem, selector, keepData ) {
var node,
            //根据selector对elem集合进行过滤,不建议将需要逻辑处理的赋值写在一个;号里,调试器在调试代码时,一步会走一个;号
    nodes = selector ? jQuery.filter( selector, elem ) : elem,
    i = 0;

for ( ; ( node = nodes[ i ] ) != null; i++ ) {
    if ( !keepData && node.nodeType === 1 ) {
            //getAll( node ) 获取node节点下的全部元素包括自身。
           //jQuery.cleanData清除事件和数据 
        jQuery.cleanData( getAll( node ) );
    }
        
    if ( node.parentNode ) {
          // jQuery.contains  当前document是否包含node
        if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
                            //标记脚本已经执行过一次
            setGlobalEval( getAll( node, "script" ) );
        }
                    //移除元素
        node.parentNode.removeChild( node );
    }
}

return elem;

}

1.2 getAll函数的源码

function getAll( context, tag ) {
//content 是DOM元素  tag是标签的名字
// Support: IE <=9 - 11 only
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
var ret;

if ( typeof context.getElementsByTagName !== "undefined" ) {
    ret = context.getElementsByTagName( tag || "*" );

} else if ( typeof context.querySelectorAll !== "undefined" ) {
    ret = context.querySelectorAll( tag || "*" );

} else {
    ret = [];
}
    //nodeName( context, tag )  context的节点名是否与tag相等,这个名字取得...
if ( tag === undefined || tag && nodeName( context, tag ) ) {
            //将ret数组的内容放到[context]中
    return jQuery.merge( [ context ], ret );
}

return ret;
}

tag || "*" 的执行逻辑是 从左到右执行,一个表达式可以转化为true时(Bollean(tag))时,返回这个表达式的结果,不再继续执行。

2 empty

empty: function() {
    var elem,
        i = 0;

    for ( ; ( elem = this[ i ] ) != null; i++ ) {
        if ( elem.nodeType === 1 ) {
                                  
                            //防止内存泄漏  清除绑定事件和数据
            // Prevent memory leaks
            jQuery.cleanData( getAll( elem, false ) );
                            //清除子节点
            // Remove any remaining nodes
            elem.textContent = "";
        }
    }

    return this;
},

3 clone

  clone: function( dataAndEvents, deepDataAndEvents ) {
            //这里是非常值得提倡的地方,deepDataAndEvents默认是和dataAndEvents值一致,这符合大部分人对一个元素克隆行为的认知,而没有采取deepDataAndEvents不传默认就是false的写法!
    dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
    deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
            //jQuery.fn.map(this.map) => JQuery.map  map可以理解为"映射",将数据逐一处理后,返回结果的集合。 jQuery.fn.map  将返回的结果传给了pushStack,用于记录框架操作过的DOM元素
    return this.map( function() {
                    //在这里完成克隆
        return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
    } );
},

4 html

access作为"预处理"函数用在很多地方,比如对传进来的函数求值,以及处理多个dom元素的情况等。
在调试的过程中,如果我们不想进入这个函数中,可以在回调函数内部打一个断点,在按下F8,便可直接跳到新的断点处,再次调试时直接按F10就可以走到断点处

html: function( value ) {
    return access( this, function( value ) {
        var elem = this[ 0 ] || {},
            i = 0,
            l = this.length;

        if ( value === undefined && elem.nodeType === 1 ) {
                            //获取值
            return elem.innerHTML;
        }

        // See if we can take a shortcut and just use innerHTML
                   //rnoInnerhtml = <script|<style|<link/i  
                  //rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i  获取标签名
                  /*wrapMap 是对一些特殊元素进行包裹
                          比如td、option,td包裹上<table><tbody><tr></tr></tbody>
</table>
                          这里是可以防止的情况有,a.不生效  比如执行下列语句$(p)[0].innerHTML= "<td></td>" 不会报错也不会有效果,b.自动生成一些标签,
$("table"),innerHTML = "<td></td>"  会自动生成<tbody><tr></tr></tbody>
                   */
        if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
            !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
                            //对标html字符串进行一些预处理 比如<span/> 会成为<span></span>
            value = jQuery.htmlPrefilter( value );

            try {
                for ( ; i < l; i++ ) {
                    elem = this[ i ] || {};

                    // Remove element nodes and prevent memory leaks
                    if ( elem.nodeType === 1 ) {
                                                   //清除绑定的事件和数据
                        jQuery.cleanData( getAll( elem, false ) );
                                                    //elem.innerHTML = ”div“是可以的
                        elem.innerHTML = value;
                    }
                }

                elem = 0;

            // If using innerHTML throws an exception, use the fallback method
            } catch ( e ) {}
        }

        if ( elem ) {
                            //不能通过innerHTML直接添加的通过一下方式添加 比如
                            //$("div.shadow").html($("<div>"))
            this.empty().append( value );
        }
    }, null, value, arguments.length );
},

给大家推荐一款正则表达式的可视化工具
https://regexper.com/

上一篇下一篇

猜你喜欢

热点阅读