Ashley’s Blog

A blogging framework for Ashley.

JQuery API

JQuery API

jQuery( “prev + next” )

同一个父元素下紧接在 “prev” 元素后的 “next” 元素

jQuery( “prev ~ siblings” )

匹配 “prev” 元素之后的所有 兄弟元素。具有相同的父元素,并匹配过滤“siblings”选择器。

jQuery( “:eq(index)” )

注意 因为 :eq() 是一个 jQuery 延伸出来的选择器,并不是的CSS规范的一部分, 使用:eq()查询不能充分利用原生DOM提供的querySelectorAll() 方法来提高性能。为了在现代浏览器上获得更佳的性能,请使用$(“your-pure-css-selector”).eq(index)代替。

jQuery( “:has(selector)” )

如果表达式 $(‘div:has(p)’) 匹配一个<div>,那么应有一个<p>存在于<div>后代元素中的任何地方,不是直接的子元素也可以。它匹配的是 <div> 而不是 <p>, 对比 $(“div p”)

jQuery( “[attribute|=‘value’]” )

选择指定属性值等于给定字符串或以该字符串为前缀(该字符串后跟一个连字符“-” )的元素。

jQuery( “[attribute~=‘value’]” )

选择指定属性用空格分隔的值中包含一个给定值的元素。

jQuery( “:nth-child(index/even/odd/equation)” )

选择他们所有父元素的第n个子元素。 用:nth-child(n)时 ,所有子元素都计算在内,不管它们是什么,并且指定的元素被选中仅匹配连接到伪类选择器。而用:eq(n)时,只有与这个伪类前面的选择相匹配的元素才会被计数(即,成为候选元素),不限于任何其他元素的孩子,而且第(n +1)个一(n是基于0)被选中。

.height()

返回的是数值, 只是纯粹的 height 数值,与此相对应的是 css(‘height’) 返回带 px 的字符串,innerHeight() 返回height+padding的数值

.outerHeight( [includeMargin ] )

height+padding+border or height+padding+border+margin

.offset() and .position()

.offset()是获得该元素相对于documet的当前坐标,而.position()方法可以取得元素相对于父元素的偏移位置

选择器

基本 * .class element #id selector1, selectorN, … 层级 parent > child ancestor descendant prev + next prev ~ siblings 基本筛选 :animated :eq() :even :first :gt() :header :lang() :last :lt() :not() :odd :root :target 内容筛选 :contains() :empty :has() :parent

可见性筛选 :hidden :visible 属性 [name|=“value”] [name*=“value”] [name~=“value”] [name$=“value”] [name=“value”] [name!=“value” [name^=“value”] [name] [name=“value”][name2=“value2”] 子元素筛选 :first-child :first-of-type :last-child :last-of-type :nth-child() :nth-last-child() :nth-last-of-type() :nth-of-type() :only-child :only-of-type()

表单 :button :checkbox :checked :disabled :enabled :focus :file :image :input :password :radio :reset :selected :submit :text 属性 / CSS

属性 .attr() .prop() .removeAttr() .removeProp() .val() CSS .addClass() .css() jQuery.cssHooks .hasClass() .removeClass() .toggleClass() 尺寸 .height() .innerHeight() .innerWidth() .outerHeight() .outerWidth() .width() 位置 .offset() .offsetParent() .position() .scrollLeft() .scrollTop() 数据 jQuery.data() .data() jQuery.hasData() jQuery.removeData() .removeData() 操作

拷贝 .clone() DOM 插入, 包裹 .wrap() .wrapAll() .wrapInner() DOM 插入, 内部插入 .append() .appendTo() .html() .prepend() .prependTo() .text() DOM 插入, 外部插入 .after() .before() .insertAfter() .insertBefore() DOM 移除 .detach() .empty() .remove() .unwrap() DOM 替换 .replaceAll() .replaceWith() 遍历

筛选 .eq() .filter() .first() .has() .is() .last() .map() .not() .slice() 各种遍历 .add() .andSelf() .contents() .each() .end() 树遍历 .addBack() .children() .closest() .find() .next() .nextAll() .nextUntil() .parent() .parents() .parentsUntil() .prev() .prevAll() .prevUntil() .siblings()

重大更新!这么写实在太慢了 还是直接贴网址比较好 JQUery API

JQuery Merge

merge: function( first, second ) {
    var len = +second.length,
        j = 0,
        i = first.length;

    for ( ; j < len; j++ ) {
        first[ i++ ] = second[ j ];
    }

    first.length = i;

    return first;
}

first 和 second 都是数组的话非常好理解,如果是 JQuery 对象其实也是可以的,因为 JQeury 对象本身也具有类似数组的特性

var ret = jQuery.merge( this.constructor(), elems );

所以昨天代码pushStack中解析的这一句,实际上是构造了一个全新的 JQuery 元素然后把 elems 赋给了他的 dom 属性。 再举一个 get 和 eq 区别的例子,我们都知道 get 返回的是 dom,eq 返回的是包装过后的 jquery 元素,这个其实也是通过 pushStack 来实现的

eq: function( i ) {
    var len = this.length,
        j = +i + ( i < 0 ? len : 0 );
    //this[i] 为 dom 元素,通过 pushStack->merge包装成为了 JQuery 元素
    return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );

}

JQuery.slice

slice: function() {
    return this.pushStack( slice.apply( this, arguments ) );
}

arguments传进去后内部调用Array.slice对 JQuery 数组做分割,将结果(一个 dom 数组)传入 pushStack 做进一步处理。最终返回分割后的 JQuery 对象。

JQuery Find and prevObject

jQuery内部维护着一个jQuery对象栈。每个遍历方法都会找到一组新元素(一个jQuery对象),然后jQuery会把这组元素推入到栈中。 每个jQuery对象都有三个属性:context、selector和prevObject,其中的prevObject属性就指向这个对象栈中的前一个对象,而通过这个属性可以回溯到最初的DOM元素集中。 一般通过end()以及addBack()方法实现内部栈的调用 例如$(‘aaa’).find(‘div’).css(…).end() //从子 div 那里回来了

find: function( selector ) {
    var i,
        len = this.length,
        ret = [],
        self = this;
    /*
     *如果不是 string,那就应该是一个 Jquery 对象
     *过滤或者说寻找到该对象的同时通过 pushStack 把该对象压入jQuery对象栈的顶端
     */
    if ( typeof selector !== "string" ) {
        return this.pushStack( jQuery( selector ).filter(function() {
            for ( i = 0; i < len; i++ ) {
                if ( jQuery.contains( self[ i ], this ) ) {
                    return true;
                }
            }
        }) );
    }

    for ( i = 0; i < len; i++ ) {
    //jQuery.find 等于 sizzle,sizzle 的内容以后再分析。结果在 ret 中呢
        jQuery.find( selector, self[ i ], ret );
    }

    // Needed because $( selector, context ) becomes $( context ).find( selector )
    // 没看懂,为什么会有重复?
    // 但是pushStack的执行是毋庸置疑的
    ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
    ret.selector = this.selector ? this.selector + " " + selector : selector;
    return ret;
}

然后就是 pushStack 和 end 方法

    pushStack: function( elems ) {

    // Build a new jQuery matched element set
    //太犀利了,没看懂这数组的合并
    var ret = jQuery.merge( this.constructor(), elems );

    // Add the old object onto the stack (as a reference)
    //做了一次关键的链接,把执行 find 的 JQuery 对象赋给了返回结果的prevObject
    //通俗点说就是我知道了我的上家是谁
    ret.prevObject = this;
    ret.context = this.context;

    // Return the newly-formed element set
    return ret;
},
    end: function() {
    //返回我的上家
    return this.prevObject || this.constructor(null);
}

还是有不明白的地方以后再回过来看吧 这些 Jquery 的解读大部分都是从 imooc 上 Aaron 的课程中学来的

JQuery Object

JQuery Object
    init = jQuery.fn.init = function( selector, context ) {
    var match, elem;

    // HANDLE: $(""), $(null), $(undefined), $(false)
    if ( !selector ) {
        return this;
    }

    // Handle HTML strings
    if ( typeof selector === "string" ) {
        if ( selector[0] === "<" && selector[ 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 ]; //如果是 html 标签, 直接赋值 match

        } else {
            match = rquickExpr.exec( selector ); //其他情况走正则处理,正则只找有没有<tag>或者 #id
        }

        // Match html or make sure no context is specified for #id
        //match代表是否匹配上了,匹配上<tag>放match[1]里 匹配上#id 放match[2]里
        if ( match && (match[1] || !context) ) {

            // HANDLE: $(html) -> $(array)
            //匹配上 tag 标签了
            if ( match[1] ) {
                context = context instanceof jQuery ? context[0] : context;

                // scripts is true for back-compat
                // Intentionally let the error be thrown if parseHTML is not present
                jQuery.merge( this, jQuery.parseHTML(
                    match[1],
                    context && context.nodeType ? context.ownerDocument || context : document,
                    true
                ) );

                // HANDLE: $(html, props)
                if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
                    for ( match in context ) {
                        // Properties of context are called as methods if possible
                        if ( jQuery.isFunction( this[ match ] ) ) {
                            this[ match ]( context[ match ] );

                        // ...and otherwise set as attributes
                        } else {
                            this.attr( match, context[ match ] );
                        }
                    }
                }

                return this;

            // HANDLE: $(#id)
            //匹配上 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;
            }

        // HANDLE: $(expr, $(...))
        //如果没匹配上 分别看看其他的情况 例如非 id 的其他选择器.css tag
        } else if ( !context || context.jquery ) {
            return ( context || rootjQuery ).find( selector );

        // HANDLE: $(expr, context)
        // (which is just equivalent to: $(context).find(expr)
        } else {
            return this.constructor( context ).find( selector );
        }

    // HANDLE: $(DOMElement)
    //或者就是个 dom 元素
    } else if ( selector.nodeType ) {
        this.context = this[0] = selector;
        this.length = 1;
        return this;

    // HANDLE: $(function)
    // Shortcut for document ready
    //Jquery Ready 传参是函数啊
    } else if ( jQuery.isFunction( selector ) ) {
        return typeof rootjQuery.ready !== "undefined" ?
            rootjQuery.ready( selector ) :
            // Execute immediately if ready is not present
            selector( jQuery );
    }
    //这两句是对后面 makeArray传参的预处理,不明觉厉
    if ( selector.selector !== undefined ) {
        this.selector = selector.selector;
        this.context = selector.context;
    }
    其他一些情况 比如就传了个对象类似{a:1,b:2}
    return jQuery.makeArray( selector, this );//其实还是把传进去的对象 挂在了 JQuery 对象的0位置上
};

匹配上 HTML Tag String 之后详细的处理没看,下次再说吧。

Regex Review

复习 regexp

/hello world/

/hello world\b/ 其实还有\B

/^hello world$/

\w [A-Za-z0-9_]


/g global

/i ignore

/m multiple


exec 通过( )分组匹配

var osVersion = 'Ubuntu 8';//其中的8表示系统主版本号  
re=/^[a-z]+\s+(\d+)$/i;//用()来创建子匹配  
arr =re.exec(osVersion);  
console.log(arr[0]);//整个osVersion,也就是正则表达式的完整匹配
console.log(arr[1]);//分组 第一个括号所匹配的  8

反向引用 先挖个大坑 To be continued……..

非贪婪匹配

  • ??
  • +?
  • *?
  • {1,4}?

分组相关()

  • /([‘“])[^’”]*\1/

  • (?:…) 只组合不记忆

  • (?=…) 先行断言 指定一个位置 零宽 并非真正匹配 /Java([Ss]cript)(?=:)/ 可以匹配”Javascript: The Definitive Guide”中的Javascript 不包含冒号 但是必须要有!

  • (?!…) 负向先行断言

String方法

  • search
  • replace
  • match
  • split

RexExp方法

  • exec
  • test

通过上面的学习我尝试去分析一下Jquery源码中一个正则表达式

rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/

最外面包裹的的恰好是代表完全匹配的/^…$/

次外层只组合不记忆(?:…)

  • \s* 一些空格
  • (<[\w\W]+>) Tag标签
  • [^>]* 任意非>字符
  • | 或者
  • #([\w-]*)) #+任意字符或者-

所以该正则匹配的是 Tag标签 或者 #开头的字符串(获取id用吗?)。 分析的是否正确等下一篇继续介绍jQuery源码的blog再分析吧

JQuery Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;(function(global, factory) {
    factory(global);
}(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
    var jQuery = function( selector, context ) {
      return new jQuery.fn.init( selector, context ); //确保构造函数的执行
  };
  jQuery.fn = jQuery.prototype = {...};
  init = jQuery.fn.init = function( selector, context ) {};
  init.prototype = jQuery.fn//把挂在fn上的方法都传给init prototype,这样Jquery对象就能拥有并使用了
  // 核心方法
  // 回调系统
  // 异步队列
  // 数据缓存
  // 队列操作
  // 选择器引
  // 属性操作
  // 节点遍历
  // 文档处理
  // 样式操作
  // 属性操作
  // 事件体系
  // AJAX交互
  // 动画引擎
  return jQuery;
}));

小技巧 ctrl+m 快速跳转到匹配的括号

----------------------

noconflict

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var
  // Map over jQuery in case of overwrite
  _jQuery = window.jQuery, //把原jQuery对象保存到_jQuery

  // Map over the $ in case of overwrite
  _$ = window.$; //把原$对象保存到_$

jQuery.noConflict = function( deep ) {
  if ( window.$ === jQuery ) {
      window.$ = _$; //如果咱们代码中的JQuery已经鸠占鹊巢占有了window.$,就把他还原回去
  }

  if ( deep && window.jQuery === jQuery ) {
      window.jQuery = _jQuery;//如果他要求的更多(指deep),咱们把window.jQuery也还原回去
  }

  return jQuery;
};

珍藏了2个月的刘明湘漂洋过海来看你

How Browser Parse Html

研究了几个小时,用chrome和dynatrace都试了试,看了看。

结论就一句话:js执行的时候会阻塞浏览器的其他行为,现代浏览器都支持并行下载的功能了,但是js的执行还是按从上倒下的顺序依次进行,只是下载由于并行能提前一会。

如果你在js文件的某处打断点,并且在控制台查看document.body你只能看到该js文件位置之前的dom元素。 parseHTML 和paint 貌似都有这种打断的功能(浏览器单线程的原因?)

Markdown Review

一级标题

2

3

4

5
6

_ First

  • Second
  • Third
  • fourth
    1. 4.1
    2. 4.2
    3. 4.3
  • fivth
  • sixth
  • seventh

another list

  1. 111
  2. 222
  3. 333
  4. 444
  5. 555

baidu cnblog 加粗 变斜了