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源码,并且自己封装出更实用的,适合自己的方法。