jQuery

jQuery原理

Nick · 1月27日 · 2020年本文6941字 · 阅读18分钟597

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人
隐藏