jq 96-280 方法属性(原型链上,实例方法属性)

jQuery.fn = jQuery.prototype = {
    // The current version of jQuery being used
    jquery: core_version,

    constructor: jQuery,
        *重定向,否则constructor 指向Object
        *在下面有用到 jQuery 时, 将用this.constructor 代替.
        *这么做的好处是,可维护性强?
      
    init: function( selector, context, rootjQuery ) {
                *selector : 我们要选择的dom,或者我们要创建的dom?
                *context : dom的父容器节点?筛选范围?
                *rootjQuery = $(document) 跟节点的jq包装对象 在外面调用时,实际上传不了这个参数.
        var match, elem;
                //这个是核心的构造函数,最后的实例长什么样由这个函数决定.
        // HANDLE: $(""), $(null), $(undefined), $(false)
        if ( !selector ) {*返回原来jq对象
            return this;
        }

        // Handle HTML strings
        *匹配字符串
        if ( typeof selector === "string" ) {
            if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {*用来匹配''的情况
                // Assume that strings that start and end with <> are HTML and skip the regex check
                match = [ null, selector, null ];
                  * 此处用match 来储存selector是因为与下面的情况保持统一
                                
            } else {
                                
                match = rquickExpr.exec( selector );
                          *上面75行定义了,rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
                          *匹配的情况:$('
'),$(#id) * 其实这里我不太懂,为什么selector 一定会在 match[1] 这个位置上. } // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { *context 不为空时? // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; *如果context传的是jQuery对象,改成原生dom // scripts is true for back-compat jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); *$.merge函数是用来合并数组的.返回第一个参数.(更改第一个参数) *最终返回的格式取决于第一个参数 *这里把第二个参数添加到实例对象中. *merge源码在636行,用来合并数组或者类数组, *无法合并两个对象(非类数组). *并且不会出现覆盖. * * *$.parseHTML()实际上是创建dom元素,返回数组. *第一个参数是字符串 *第二个参数是在哪个document *第三个参数是能不能创建script,true表示可以. * * // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { *78行定义了 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, *匹配的情况 $('
')? *jQuery.isPlainObject() 判断是否为对象,但不能是node元素,也不能是window *所以此处的意思是,context如果不是dom节点? *匹配的情况 $('
',{title:'123',name:'kakgj'}) 很少用,用来给创建的节点增加属性. for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); *匹配的情况 $('
',{html:'
123
'});这你就很牛逼了. *这个我服,尽管我可能永远都不会这么用,但开启各种接口,我是真的服! *在一个原型上定义了方法,我传一个对象,对象名用来调用原型上的方法 *对象值用来当做参数传给该方法. // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); *匹配的情况 $('
',{title:'123',name:'kakgj'}) } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; *一个标准的jq对象中,通常有context,selector,length,prevObject,以及一堆dom元素 *此时我们发现,这里是不配备prevObject属性的.也容易理解, } // HANDLE: $(expr, $(...)) *以下是dom的查找,上面是主要是dom的创建. *匹配的是 $(('div'),$('father')), 也就是context 传的是jq对象时,context就是这个对象. *或者是$('div') 也就是没传 context时,默认context 是 rootjQurey } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) *匹配的是$('div',father); // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) *这个地方不懂,指的是document?还是html的情况? * 明白了,,当不是字符串而是dom元素时, *匹配的情况是 $(div); *此时返回的对象没有selector,也没有preObject属性 } else if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) *匹配的是$(function(){}); // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); *关于jQuery.ready还是另起一篇比较好. } *匹配的是$($('div')) if ( selector.selector !== undefined ) {*可用来判断是否是jq对象 this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); *jQuery.makeArray 定义在615行,内部调用的是merge,或者push, *返回的是第二个参数,如果第二个参数不填入,则第二个参数默认是[];(只传一个参数时,类数组转换成数组) *所以这句最终是返回this的. }, *以上就是init构造函数.实际上虽然勉强能看懂,但很明显还有很多含金量没被发掘. // Start with an empty selector *selector 默认值 selector: "", // The default length of a jQuery object is 0 *length 默认值 length: 0, *这个就是把类数组转变成数组啦 *跟makeArray 相比,这个无法传入两个参数,并且返回的不可能是jq对象. toArray: function() { return core_slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array *还没这么用过, 匹配情况,$('div').get() 相当于 $('div').toArray(); this.toArray() : // Return just the object *$('div').get(num) 注意,此时返回的就不是jq对象而是 原生dom元素. ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { *个人觉得这是原型上定义的方法中,除了init之外最有含金量的了. *主要是解决prevObject 属性,有这个属性才能配合使用end()方法; *elems 通常应该是一个dom数组. // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); *merge就是返回第一个类数组,添加后面类数组的内容.(都是浅克隆) // Add the old object onto the stack (as a reference) ret.prevObject = this;*这样就正式设置了prevObject了. ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); *jQuery.each 方法定义在 源码561行,可以看出整个jq内部调用这个each的频率可是非常高的. *整个jq最大的亮点就是隐式迭代,用的就是这个each *返回的是this,假设this就是jq对象的情况,会遍历this当中的所有节点, *每个节点都会调用一次这个函数,可以传参. *如果$('div').each(function(index,ele){}),那么callback传的参数是index和ele *如果$('div').each(function(){a,b,c},[a,b,c]),那么我后面传什么参数就是什么, *此时this指向的是每个dom元素.我反正是一次都没这么用过. *如果传参,必须传一个数组.或者类数组.. }, ready: function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); *这一部分我大概知道干什么用的,具体怎么实现似乎挺复杂的.还是另起一篇比较好. return this; }, slice: function() { return this.pushStack( core_slice.apply( this, arguments ) ); *这就很巧妙,用了数组的slice方法,以及pushStack方法, *实现了jq的slice,关键是返回的依然是jq对象. * 也就是说 pushStack最大的用处实际上是: 把一个dom数组转换成jq对象. *或者说把一个jq对象转换成另一个jq对象. *尽管里面用的是merge,但一封装一下,就很方便. *由此更感觉,merge方法很重要. }, first: function() { return this.eq( 0 ); *直接看eq }, last: function() { return this.eq( -1 ); *直接看eq }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); *这里有个细节,+i ,当i是字符串'1'时 可以转换成number类型 1,相当于调用Number()? * 当然跟parseInt 和parseFloat 还是有区别.遇到字类似'1.1a'类型会变成NaN * 但很简洁! return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); *map源码在676行,结构上和each 似乎差不多,不过返回dom数组. *map和each 应该是jq隐式迭代专用函数了. }, end: function() {*兼容,如果没有prevObject时返回自身. return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: core_push, sort: [].sort, splice: [].splice *这三个是把数组上的方法移植过来了. };

你可能感兴趣的:(jq 96-280 方法属性(原型链上,实例方法属性))