jQuery源碼學習(一)

有很長一段時間沒有更新博客了,近一段時間開始重新梳理知識點和寫博客了。重要的事情說三遍,新的博客地址:歡迎訪問,新的博客地址:歡迎訪問,新的博客地址:歡迎訪問

jQuery的核心理念

  • 簡潔的API
  • 優雅的鏈式
  • 強大的選擇器
  • 便捷的操作

jQuery框架的核心就是從HTML文檔中匹配元素並對其執行操作

jQuery源碼整體放在一個匿名函數執行中

(function(window,undefined){//這裏是形參
})(window,undefined);//傳入實參

**這樣寫的好處是:**在匿名函數中定義的變量和函數在匿名函數外部都是訪問不到的,在匿名函數中提供對外訪問的接口
這裏把window當做參數傳進來是因爲window處於作用域的最頂端,它的查找速度是最慢的。
**好處1:**將window作爲實參傳遞給匿名函數的形參,在匿名函數中可以加快window的查找速度
**好處2:**在壓縮版本中window作爲實參傳遞給匿名函數的形參e,通過這樣傳遞,我們知道在壓縮代碼中e就代表了window
傳入undefined,是因爲在匿名函數外部undefined可能被修改爲其他值,將undefined作爲參數傳進來,在匿名函數中用到undefined了就是用的傳進來的值而不會向外查找了。

方法和屬性

####jquery##
用來輸出相應的版本號:

<script type="text/javascript">
alert($().jquery);//彈出版本號
</script>

####constructor##

<script type="text/javascript">
function Person(){
}
Person.prototype.name = "lisi";
Person.prototype.age = 20;
var person1 = new Person();
alert(person1.constructor);//輸出相應的構造函數
/*
function Person(){
}
 */
</script>
<script type="text/javascript">
function Person(){
}
Person.prototype = {//這裏是重寫了原型,這樣構造函數指向就出現了問題,需要手動去修正
	constructor:Person,
	name:"lisi",
	age:20
}
var person1 = new Person();
alert(person1.constructor);
/*
function Object(){
	[native code]
}
 */
</script>

####jQuery對象轉爲dom對象##

<script type="text/javascript">
console.log($("li"));//jQuery.fn.init[3],每個li都有對應的下標
$("li")[1].style.background = "#f00";//$("li")[1]這樣可以把jQuery轉化爲dom對象
</script>

####parseHTML##
jQuery.parseHTML用來將字符串轉化爲數組,返回一個數組

<script type="text/javascript">
$(function(){
	var str = '<li>1</li><li>2</li><li>3</li>';
	var arr = jQuery.parseHTML(str);
	console.log(arr);//[li, li, li]
	$.each(arr,function(i){
		$("ul").append(arr[i]);
	});
});
</script>

####merge##

script type="text/javascript">
$(function(){
	var arr1 = ['a','b'];
	var arr2 = ['c','d'];
	var arr3 = {
		0:'a',
		1:'b',
		length:2
	};
	//$.merge用來合併數組
	console.log($.merge(arr1,arr2));//["a", "b", "c", "d"]
	//$.merge也可以用來合併json
	//merge在jQuery中可以用來合併json
	console.log($.merge(arr3,arr2));//Object {0: "a", 1: "b", 2: "c", 3: "d", length: 4}
});
</script>

####正則匹配##

<script type="text/javascript">
	var rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;
	var str1 = '#div1';
	var str2 = '<li>hello';
	console.log(rquickExpr.exec(str1));//["#div1",undefined,'div1'];
	console.log(rquickExpr.exec(str2));//["<li>hello", "<li>", undefined]
	</script>

####makeArray###

<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
        var oDiv=document.getElementsByTagName("div");
        /*
        oDiv只是一個類數組,並不是真正的數組,類數組不能調用數組的方法
        在jQuery中可以通過makeArray方法將類數組轉爲真正數組
         */
        console.log(oDiv);//HTMLCollection[div, div, div]
        console.log($.makeArray(oDiv));//[div, div, div]  變爲數組
         console.log($.makeArray(oDiv,{length:0}));// Object { 0=div,  1=div,  2=div,  更多...}   變爲json形式
    </script>
</body>

####pushStack###

    pushStack():JQ對象的入棧
    棧是後進先出,所以這裏span的背景顏色變紅
    隊列是先進先出
    end() 進行出棧操作,來返回棧中的前一個狀態
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>pushStack</title>
</head>
<body>
    <div>1111111</div>
    <span>222222</span>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
$(function(){     $('div').pushStack($('span')).css('background','red');
//end() 進行出棧操作,來返回棧中的前一個狀態,所以div背景變黃了 
          $('div').pushStack($('span')).css('background','red').end().css('background','yellow');
        });
    </script>
</body>
</html>
<body>
    <div>1111111</div>
    <div>1111111</div>
    <div>1111111</div>
    <div>1111111</div>
    <span>222222</span>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
        $(function(){
            //$('div').slice(1,3).css('background','red');
//$('div')選擇了所有的div
//slice(1,3)選擇了中間兩個div
//棧中$('div')在下,slice(1,3)在上
//所以css('background','red')使得中間兩個div背景變紅
//end() 進行出棧操作,返回棧中的前一個狀態
//css('color','blue')使得四個div的字體顏色都爲藍色
            $('div').slice(1,3).css('background','red').end().css('color','blue');
        });
    </script>
</body>

####map###
返回新集合

<body>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
        var arr=['a','b','c'];
        //將原始數組中的每個值加上自己索引後,映射到新的數組中。
        arr=$.map(arr,function(elem,i){
            //i是數組元素的下標
            //elem表示數組元素
            return elem+i;
        });
        console.log(arr);// ["a0", "b1", "c2"]
    </script>
</body>

####eq###
first(就是eq(0))和last(就是eq(-1))方法都是基於eq方法來實現的

<body>
    <div>1111111</div>
    <div>1111111</div>
    <div>1111111</div>
    <div>1111111</div>
    <span>222222</span>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
        /*
        eq是獲取指定下標的元素
        下標可以爲負值
         */
        $(function(){
            //$('div')選擇了所有的div
            //eq(2)選擇了第三個div
            //棧中$('div')在下,eq(2)在上
            //所以css('color','red')使得第三個div字體顏色變紅
            $('div').eq(2).css('color','red');
            $('div').eq(-1).css('color','red');//其實是-1+length
        });
    </script>
</body>

####toArray()###
toArray()方法用來轉數組

<body>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <script type="text/javascript" src="../jquery-2.1.4.js"></script>
    <script type="text/javascript">
        $(function(){
            console.log($('div'));//Object[div, div, div]  返回的是對象
            console.log($('div').toArray());//[div, div, div]  返回數組
        });
    </script>
</body>

extend–JQ的繼承方法##

###jQuery.extend和jQuery.fn.extend###

  • jQuery.extend 對jQuery本身的屬性和方法進行了擴展
  • jQuery.fn.extend 對jQuery.fn的屬性和方法進行了擴展

jQuery.extend 調用的時候,this是指向jQuery對象的(jQuery是函數,也是對象!),所以這裏擴展在jQuery上。
而jQuery.fn.extend 調用的時候,this指向fn對象,jQuery.fn 和jQuery.prototype指向同一對象,擴展fn就是擴展jQuery.prototype原型對象。這裏增加的是原型方法,也就是對象方法了。

<body>
<script type="text/javascript" src="../jquery-2.1.4.js"></script>
<script type="text/javascript">
    //當只寫一個對象字面量的時候,JQ中擴展插件的形式
    $.extend({//擴展工具方法
        aaa:function(){
            alert(1);
        },
        bbb:function(){
            alert(2);
        }
    });
    $.fn.extend({//擴展JQ實例方法
        aaa:function(){
            alert(3);
        },
        bbb:function(){
            alert(4);
        }
    });
//$代表函數
$.aaa();
$.bbb();
//$()代表對象
$().aaa();
$().bbb();
//$.extend();   this指向$    this.aaa->$.aaa()
//$.fn.extend();   this指向$.fn     this.aaa->$().aaa()
//$.fn是原型,在原型下擴展的方法,需要通過對象實例來調用
</script>
</body>
<body>
<script type="text/javascript" src="../jquery-2.1.4.js"></script>
<script type="text/javascript">
    //當寫多個對象字面量的時候,後面的對象都是擴展到第一個對象身上
    var a={};
    $.extend(a,{name:'hello'},{age:30});
    console.log(a);// Object { name="hello",  age=30}
</script>
</body>
<body>
<script type="text/javascript" src="../jquery-2.1.4.js"></script>
<script type="text/javascript">
    //當寫多個對象字面量的時候,後面的對象都是擴展到第一個對象身上

    //還可以做深拷貝和淺拷貝
    //默認是淺拷貝
    var a={};
    var b={name:"hello"};
    $.extend(a,b);//淺拷貝
    a.name='hi';
    console.log(b.name);//hello

    //當進行淺拷貝的時候b.name.age會受影響,這時就需要深拷貝
    var a={};
    var b={name:{age:30}};
    $.extend(a,b);//淺拷貝
    a.name.age=20;
    console.log(b.name.age);//20

    var a={};
    var b={name:{age:30}};
    $.extend(true,a,b);//深拷貝
    a.name.age=20;
    console.log(b.name.age);//30
    /*
    JQ:拷貝繼承
     */
</script>
</body>

###jQuery.extend()用法###
**Demo1:**這個例子只給jQuery.extend()方法傳遞了一個對象參數,這樣會將該對象的所有屬性和方法添加到jQuery對象上。

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
	var obj1 = {apple:0,banana:{weight:52,price:100},cherry:97};
	$.extend(obj1);//這樣寫是將obj1對象的屬性添加給jQuery對象
	console.log(jQuery.apple);//0
	console.log(jQuery.banana);//Object {weight: 52, price: 100}
	console.log(jQuery.cherry);//97
});
</script>

Demo2:

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
	var obj1 = {apple:0,banana:{weight:52,price:100},cherry:97};
	var obj2 = {banana:{price:200},durian:100};
	var obj = $.extend(obj1,obj2);
	console.log(JSON.stringify(obj));//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
	//從輸出的結果可以看出,banana這個key值被替換掉了
});
</script>

**Demo3:**深拷貝

<script type="text/javascript" src="jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
	var obj1 = {apple:0,banana:{weight:52,price:100},cherry:97};
	var obj2 = {banana:{price:200},durian:100};
	var obj = $.extend(true,obj1,obj2);//第一個參數true表示深拷貝
	console.log(JSON.stringify(obj));
	//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
	//深拷貝是進行遞歸合併,對已有屬性值進行覆蓋替換,沒有的屬性進行增加
	//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
});
</script>

一篇不錯的博文:jQuery.extend 函數詳解

jQuery.extend()–擴展一些工具方法

###noConflict()###
jQuery與其他庫的防衝突解決

<body>
<div>1111111</div>
<script type="text/javascript" src="../jquery-2.1.4.js"></script>
<script type="text/javascript">
    var aa = $.noConflict();
    //這裏在引入jQuery庫之後使用了$
    //這樣就會導致$成爲123,而不是原先的jQuery函數,所以要在這之前調用處理衝突函數,將$對jQuery的引用解除,並將jQuery對象賦值給aa變量
    console.log(window.$);//undefined
    var $ = 123;
    aa(function(){
        alert($);//123
    });
</script>
</body>

在jQuery庫之前引用$和jQuery

<body>
<script type="text/javascript">
/*
源碼中:
_jQuery = window.jQuery
_$ = window.$
 */
//這裏在引入jQuery之前將$賦值爲123
//相當於將jQuery源碼中的_$ = window.$ = 123
    var $ = 123;
//相當於將jQuery源碼中的_jQuery = window.jQuery = 456
    var jQuery = 456;
    //console.log("window:"+window.$);//window:123
</script>
<script type="text/javascript" src="../jquery-2.1.4.js"></script>
<script type="text/javascript">
    var aa = $.noConflict(true);//這裏aa就等於$.noConflict()函數返回的jQuery對象
    aa(function(){
        alert($);//123
        alert(jQuery);//456
    });
</script>
</body>

上面代碼中在引入jQuery庫之前,先將$和jQuery分別賦值。並在jQuery源碼中分別將其值保存在私有變量_$和_jQuery中。
當我們引入jQuery庫之後:

window.jQuery = window.$ = jQuery;

這樣一來,之前$和jQuery的值將被覆蓋爲jQuery對象。如果不進行衝突處理,將無法訪問之前定義的$和jQuery。當使用jQuery防衝突方法後,用我們之前保存在私有變量_$和_jQuery中的值重新給$和jQuery賦值,並將jQuery對象賦值給其他變量。這樣一來我們就能夠正常訪問$和jQuery了。
jQuery在其他庫之後引入

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>jQuery與其他庫的衝突解決</title>
</head>
<body>
	<div id="box1">Test-prototype(將被隱藏)</div>
	<div id="box2">Test-jQuery(將被綁定單擊事件)</div>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/prototype/1.7.1.0/prototype.js"></script>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript">
		jQuery.noConflict();//將變量$的控制權移交給prototype.js
		jQuery(function(){//使用jQuery
			jQuery("#box2").click(function(){
				alert(jQuery(this).text())
			});
		});
		$("box1").style.display = 'none';//使用prototype.js隱藏元素
		//這樣就可以將jQuery函數作爲jQuery對象的製造工廠
	</script>
</body>
</html>

由於prototype和jQuery中都存在$引用,而jQuery在prototype之後引入,這樣一來會導致prototype中的$無法使用。所以,這裏我們jQuery的防衝突方法,使得jQuery放棄了$。這樣一來,就可以在prototype中正常使用$了。
注意:

window.jQuery = window.$ = jQuery;

這裏雖然jQuery放棄了$,但是可以使用window.jQuery來使用jQuery對象。
自定義快捷方式

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>jQuery與其他庫的衝突解決</title>
</head>
<body>
	<div id="box1">Test-prototype(將被隱藏)</div>
	<div id="box2">Test-jQuery(將被綁定單擊事件)</div>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/prototype/1.7.1.0/prototype.js"></script>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript">
		$j = jQuery.noConflict();//將變量$的控制權移交給prototype.js
		$j(function(){//使用jQuery
			$j("#box2").click(function(){
				alert($j(this).text())
			});
		});
		$("box1").style.display = 'none';//使用prototype.js隱藏元素
		//這樣就可以將jQuery函數作爲jQuery對象的製造工廠
	</script>
</body>
</html>

如果不想給jQuery自定義備用名稱,還想使用而不管其他庫的()方法,同時又不想與其他庫相沖突,我們可以這樣來解決

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>jQuery與其他庫的衝突解決</title>
</head>
<body>
	<div id="box1">Test-prototype(將被隱藏)</div>
	<div id="box2">Test-jQuery(將被綁定單擊事件)</div>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/prototype/1.7.1.0/prototype.js"></script>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript">
		jQuery.noConflict();//將變量$的控制權移交給prototype.js
		(function($){//定義匿名函數並設置形參$
			$(function(){//匿名函數內部的$均爲jQuery
				$("#box2").click(function(){//繼續使用$()方法
				alert($(this).text())
			});
			});
		})(jQuery);//執行匿名函數且傳遞實參jQuery
		$("box1").style.display = 'none';//使用prototype.js隱藏元素
	</script>
</body>
</html>

jQuery在其他庫之前引入

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>jQuery與其他庫的衝突解決</title>
</head>
<body>
	<div id="box1">Test-prototype(將被隱藏)</div>
	<div id="box2">Test-jQuery(將被綁定單擊事件)</div>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
	<script type="text/javascript" src="http://apps.bdimg.com/libs/prototype/1.7.1.0/prototype.js"></script>
	<script type="text/javascript">
	//jQuery庫在其他庫之前引入了,可以直接使用jQuery,無需調用jQuery.noConflict(),可以使用$()方法作爲其他庫的快捷方式
		jQuery(function(){//直接使用jQuery,無需調用jQuery.noConflict()
			jQuery("#box2").click(function(){
				alert(jQuery(this).text())
			});
		});
		$("box1").style.display = 'none';//使用prototype.js隱藏元素
		//這樣就可以將jQuery函數作爲jQuery對象的製造工廠
	</script>
</body>
</html>

相應的源碼:

	//防止衝突
	noConflict: function( deep ) {
		if ( window.$ === jQuery ) {
			window.$ = _$;//將私有變量_$賦值給對外接口window.$,這裏jQuery就放棄了$
		}
		//當傳遞參數的時候
		if ( deep && window.jQuery === jQuery ) {
			window.jQuery = _jQuery;//將私有變量_jQuery賦值給對外接口window.jQuery,這裏jQuery就放棄了jQuery
		}
		return jQuery;
	}

###expando###
expando用來生成一個隨機字符串
在數據緩存、事件操作、aJax都用到這個來生成隨機字符串

<body>
<script type="text/javascript" src="../../jquery-2.1.4.js"></script>
<script type="text/javascript">
//生成一個隨機字符串
console.log($.expando);//jQuery214073688220245906
</script>
</body>

待續。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章