路漫漫其修远兮:js的成长经历(十五)—— jQuery原理

jQuery基本结构

<script type="text/javascript">			
			(function (window,undefind){
				var jQuery =function(){
					return new jQuery.prototype.init();
				}
				jQuery.prototype={
					constructor:jQuery
				}
				jQuery.prototype.init.prototype = jQuery.prototype;
				window.jQuery=window.$=jQuery;
			})(window);
			
			
			//写完马上被调用
			(function test(){
				console.log("我要立即执行");
			})();
			
		</script>

1.jQuery的本质是一个闭包
2.jQuery为什么要使用闭包来实现?
可以避免多个框架的冲突
3.jQuery如何让外部访问内部定义的局部变量通过
widow.xxx=xxx;
4.jQuery为什么要个自己传入一个实参window
为了后期压缩代码
为了提升查找的效率
5.jQuery为什么要个自己接收一个实参undefind
ie9以下的浏览器undefined可以被修改,为了保证内部使用undefined不被修改,
所以需要接受一个正确的undefined

jQuery中的extend方法

jQuery中有众多的方法,但这么多的方法不可能都是一一用每一个函数来封装,因此应用到了extend继承的方法来对这些方法进行管理,不仅起到了封装的效果,并且让代码更好的管理,提高代码的阅读性和维护性。
下面的示例中应用了三种extend方法:
1.通过类调用或添加静态方法
2.通过对象调用或添加实例方法
2.将两种方法合二为一

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			function kjQuery(){
				
			}
			kjQuery.extend=function(obj){
				//此时此刻this就是jQuery这个类
				//console.log(this);
				for(var key in obj){
					this[key]=obj[key];
				}
			}
			kjQuery.extend({
				isTest:function(){
					console.log("我是Test");
				}
			});
			
			/*自己理解的原理:kjQuery相当于父类,extend相当于子类,父类调用了子类中的方法			
		   isTest相当于obj,在kjQuery这个类中找到extend方法中key为isTest的值,
		   而在extend方法中,key为isTest的值为一个函数,返回给this对象
		   ,而this就是kjQuery,就相当于用kjQuery调用了isTest()这个方法		   
		   */
			kjQuery.isTest();
			
			
			
			//用构造函数prototype来解释,对象添加实例方法
			kjQuery.prototype.extend=function(obj){
				//此时此刻this就是jQuery这个类
				//console.log(this);
				for(var key in obj){
					this[key]=obj[key];
				}
			}
			var q=new kjQuery();
			q.extend({
				isDemo:function(){
					console.log("我是Demo");
				}
			}); 
			//此时的extend是kjQuery对象q的方法,不能直接用kjQuery来调用
			q.isDemo();

			
			//3.两个方法合二为一
			kjQuery.extend = kjQuery.prototype.extend = function(obj) {
				for (var key in obj) {
					this[key] = obj[key];
				}
			}
			//通过类调用可以添加静态方法
			kjQuery.extend({
				isDemo0:function(){
					console.log("我是类调用的Demo");
				}
			}); 
			//通过对象调用可以添加实例方法
			var q=new kjQuery();
			q.extend({
				isDemo:function(){
					console.log("我是对象调用的Demo");
				}
			}); 
			q.isDemo()//我是对象调用的Demo
			kjQuery.isDemo0();//我是类调用的Demo
		</script>
	</body>
</html>

jQuery中真伪数组的转换

为了避免浏览器的兼容性,写出了两种完美兼容的互转换方法

<script type="text/javascript">
			$(function() {
				var res=document.querySelectorAll("div");
				var obj={};
				var arr=[1,2,3,4,5,6,7];//真数组
				//真数组转伪数组
				[].push.apply(obj,arr);
				//如果oobj的后面bj里面有值,则会将arr数组里的添加在obj的后面
				console.log(obj);
				//伪数组转真数组:
				//slice是截取字符串的方法
				//apply和call方法是往第一个参数对象里添加元素
				var arr=[].slice.call(res);
				console.log(arr);

			});	
		</script>

jQuery的原生方法和属性的实现(部分)

主要实现了
1.传入 ‘’ null undefind NaN 0 false.返回空的jQuery对象
2.字符串
代码片段:会将创建好的DOM元素储存到jQuery对象中返回
选择器:会将所有找的元素存储到jQuery对象中返回
3.数组
会将数组中的元素依次存入到jQuery对象中返回
4.除上述以外的
会将传入的数据储存到jQuery对象中返回
5.内置静态方法
(1)isString
(2)isHTML
(3)isObject
(4)isWindow
(5)isArray
(6)isFuncton
(7)ready
(8)each
6.内置属性方法
(1)push
(2)sort
(3)splice
(4)toArray
(5)get
(6)eq
(7)first
(8)last
(9)each
7.去除两端空格的方法(兼容浏览器)

原生jQuery代码实现

/*
1.传入 '' null undefind NaN 0 false.返回空的jQuery对象
2.字符串
	代码片段:会将创建好的DOM元素储存到jQuery对象中返回
	选择器:会将所有找的元素存储到jQuery对象中返回
3.数组
	会将数组中的元素依次存入到jQuery对象中返回
4.除上述以外的
	会将传入的数据储存到jQuery对象中返回
*/
(function(window, undefind) {
	var kjQuery = function(selector) {
		return new kjQuery.prototype.init(selector);
	}
	kjQuery.prototype = {
		constructor: kjQuery,
		init: function(selector) {
			//去除开头和结尾的空格
			selector = kjQuery.trim(selector);
			// 1.传入 '' null undefind NaN 0 false.返回空的jQuery对象
			if (!selector) {
				return this;
			}
			//2.传入方法:需要先将DOM元素加载完毕
			else if (kjQuery.isFuncton(selector)) {
				kjQuery.ready(selector);
			}
			// 2.字符串
			// 	代码片段:会将创建好的DOM元素储存到jQuery对象中返回			
			else if (kjQuery.isString(selector)) {
				// 	代码片段:会将创建好的DOM元素储存到jQuery对象中返回
				if (kjQuery.isHTML(selector)) {
					// 1.根据代码片段创建所有的元素
					var temp = document.createElement("div");
					temp.innerHTML = selector;
					//优化第二和第三步
					[].push.apply(this, temp.children);

				} else {
					// 	选择器:会将所有找的元素存储到jQuery对象中返回
					// 1.根据传入的选择器找到对应的元素
					var res = document.querySelectorAll(selector);
					// 2.将找到的元素添加到kjQuery中
					[].push.apply(this, res);
				}
			}
			// 3.数组
			// 	会将数组中的元素依次存入到jQuery对象中返回
			else if (kjQuery.isArray(selector)) {
				//不管真伪都将传进来的转化为真数组
				var arr = [].slice.call(selector);
				// 真数组转化为伪数组
				[].push.apply(this, arr);
			}
			// 4.除上述以外的
			// 	会将传入的数据储存到jQuery对象中返回
			else {
				this[0] = selector;
				this.length = 1;

			}
			//把加工以后的返回
			return this;

		},
		//内置属性
		jquery: "1.1.0",
		selector: "",
		length: 0,
		//[]找到数组的push方法
		//冒号前面的push由jQuery调用
		//相当于 [].push.apply(this);
		push: [].push,
		sort: [].sort,
		splice: [].splice,
		toArray: function() {
			return [].slice.call(this); //将伪数组转化为数组
		},
		get: function(num) {
			// 没有传递参数
			if (arguments.length === 0) {
				return this.toArray();
			}
			// 传递不是负数
			else if (num >= 0) {
				return this[num];
			}
			// 传递负数
			else {
				return this[this.length + num];
			}
		},
		eq: function(num) {
			// 没有传递参数
			if (arguments.length === 0) {
				return new kjQuery();
			} else {
				return kjQuery(this.get(num));
			}
		},
		first: function() {
			return this.eq(0);
		},
		last: function() {
			return this.eq(-1);
		},
		each: function(fn) {
			return njQuery.each(this, fn);
		}
	}
	kjQuery.extend = kjQuery.prototype.extend = function(obj) {
		for (var key in obj) {
			this[key] = obj[key];
		}
	}
	//内置方法
	kjQuery.extend({
		isString: function(str) {
			return typeof str == "string";
		},
		isHTML: function(str) {
			return str.charAt(0) == "<" && str.charAt(str.length - 1) == ">" && str.length >= 3;
		},
		isObject: function(sele) {
			return typeof sele == "object";
		},
		isWindow: function(sele) {
			return sele == window;
		},
		isArray: function(sele) {
			if (typeof sele == "object" && "length" in sele && sele != "window") {
				return true;
			} else {
				return false;
			}
		},
		isFuncton: function(sele) {
			return typeof sele == "function";
		},
		ready: function(fn) {
			//判断DOM元素是否加载完毕
			if (document.readyState == "complete") {
				fn();
			} else if (document.addEventListener) {
				//监听一个事件DOMContentLoaded:这个事件只会等到DOM元素加载完毕后执行回调
				document.addEventListener("DOMContentLoaded", function() {
					fn();
				});
			} else {
				document.attachEvent("onreadystatechange", function() {
					if (document.readyState == "complete") {
						fn();
					}
				});
			}
		},
		each: function(obj, fn) {
			// 1.判断是否是数组
			if (kjQuery.isArray(obj)) {
				for (var i = 0; i < obj.length; i++) {
					// var res = fn(i, obj[i]);
					var res = fn.call(obj[i], i, obj[i]);
					if (res === true) {
						continue;
					} else if (res === false) {
						break;
					}
				}
			}
			// 2.判断是否是对象
			else if (kjQuery.isObject(obj)) {
				for (var key in obj) {
					// var res = fn(key, obj[key]);
					var res = fn.call(obj[key], key, obj[key]);
					if (res === true) {
						continue;
					} else if (res === false) {
						break;
					}
				}
			}
			return obj;
		}
	});


	//去除两端空格的方法
	kjQuery.trim = function(str) {
		if (!kjQuery.isString(str)) {
			return str;
		}
		//判断浏览器是否支持trim方法
		if (str.trim) {
			return str.trim();
		} else {
			//匹配开头和结尾的多个空格
			return str.replace(/^\s+|\s+$/g, "")
		}

	}

	kjQuery.prototype.init.prototype = kjQuery.prototype;
	window.kjQuery = window.$ = kjQuery;
})(window);

测试代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="kjQuery.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<ul>
			<li class="item1"></li>
			<li class="item2"></li>
			<li class="item3"></li>
			<li class="item4"></li>
			<li class="item5"></li>
		</ul>
		<script type="text/javascript">
			console.log($(""));
			console.log($(0));
			console.log($("<p>asdas</p><p>asd</p>"));
			console.log($(" <div><p>asd</p>  </div><p>asd</p>  "));
			console.log($(".item"));
			var arr=[0,2,3,5,6];
			var obj={0:"dsas",1:"sad",2:"sad",length:3};
			console.log($(arr));
			console.log($(obj));
			console.log($(123));
			console.log($(true));
			console.log($().jquery);
			$(function(){
				var res=$("li");
				console.log(res.toArray());
				console.log(res.get(1));
				// console.log(res.get(-1));
				console.log(res.eq(1));
				console.log(res.first());
				console.log(res.last());
			});
			var arr = [1, 3, 5, 7, 9];
			var obj1 = {0:"lnj",1:"333",2:"male",length:3};
			var obj2 = {"name":"lnj","age":"33"};
			kjQuery.each(arr, function (key, value) {
			    console.log(key, value);
			    console.log(this);
			});
		</script>
	</body>
</html>

感受

jQuery原生代码学起来真的很犯困,学起来也很困难,很多逻辑不理解,但是还是选择了坚持,慢慢的也还好,毕竟是有jQuery的参考源码,虽然现在看的懂的不多,我会相信,有一天我可以完全看懂jQuery源码,并且自己封装出更实用的,适合自己的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不愿意做鱼的小鲸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值