目录
1 模块化的基本结构
2 编写封装里的jQuery函数
2.1 对象本身上添加css方法
2.2 对象原型上添加css方法
2.3 自定义构造函数
2.4 优化1-伪数组
2.5 优化2-原型链
2.6 简化代码
需求:给页面中所有的div设置字体颜色为红色
jQuery封装:$("div").css("color","red")
如果没有引入jQuery,该如何编写?
1 模块化的基本结构
要封装的这个库应该是一个独立的单元:模块化
独立:
- 不依赖任何其他第三方库
- 里面的东西大部分也是与世隔绝的,只有:$、jQuery
模块化的基本结构
(function (global) { function jQuery() { } //global.$ = global.jQuery = jQuery; //相当于: global.jQuery = jQuery; global.$ = jQuery; })(window)
1) 传入window,global接收window,即global保存了window对象的引用
2)在global(相当于window)里添加一个方法jQuery,并将模块化里的jQuery函数将其赋值
3)在global(相当于window)里添加一个方法$,并将模块化里的jQuery函数将其赋值
2 编写封装里的jQuery函数
2.1 对象本身上添加css方法
步骤:
1、获取页面中所有的元素
2、把这个元素放在一个特定的对象中观察$("div").css("color","red")所得:
直接在jQuery函数里elementsc添上css方法
(function(global){ function jQuery(selector){ const elements = document.getElementsByTagName(selector); elements.css=()=>{ } return elements; } window.$ = window.jQuery = jQuery; })(window) $("div").css() $("p") $("span") $("img") $("input")
问题:随着$()操作频次的增加,会产生无数个相同的css方法,造成内存浪费
2.2 对象原型上添加css方法
放在对象本身上会造成浪费,则我们优化成:放在对象的原型上
(function(global){ function jQuery(selector){ const elements = document.getElementsByTagName(selector); return elements; } HTMLCollection.prototype.css=()=>{ console.log('css方法'); } window.$ = window.jQuery = jQuery; })(window) $("div").css()
这种解决方案,把DOM操作的方法都放在了原型中,这样看似可以正常访问,但是依然存在问题:破坏了原生的对象结构
2.3 自定义构造函数
自定义构造函数 F,在F的原型上添加css方法
<body> <div>aaa</div> <div>bbb</div> <div>ccc</div> <span class="header">123</span> <input type="text" id="inputId"> </body> <script> //给页面中所有的div设置字体颜色为红色 //$("div").css("color","red") (function(global){ function jQuery(selector){ return new F(selector); } //jquery对象的构造函数 function F(selector){ //jquery内部封装了一个Sizzle引擎来获取DOM元素 const elements = document.querySelectorAll(selector) //把DOM元素放到这个对象中 this.elements = elements; //为了让这些元素可以在css方法中进行访问,所以需要把这些元素放在对象上面进行传递 } F.prototype.css=function(name,value){ for(let i = 0;i<this.elements.length;i++){ let element = this.elements[i]; element.style[name]=value; } } window.$ = window.jQuery = jQuery; })(window) $("div").css("color","red") $(".header").css("backgroundColor","pink") $("#inputId").css("backgroundColor","black") </script>
2.4 优化1-伪数组
jquery为了后续的DOM操作的方便,将这些获取到的DOM元素全部放在了对象自己身上,让自己变成了一个就像数组一样,可以使用for循环进行遍历,我们把这种对象特性称之为【伪数组】
(function(global){ function jQuery(selector){ return new F(selector); } function F(selector){ //把DOM元素放到这个对象中 const elements = document.querySelectorAll(selector) //实现把这些所有DOM元素都添加到对象自己身上 for(let i = 0;i<elements.length;i++){ //ele:DOM元素 this[i] = elements[i]; } this.length=elements.length; } F.prototype = { constructor:F, //此时的css方法还是雏形,后续完善 css(name,value){ for(let i = 0;i<this.length;i++){ let element = this[i]; element.style[name]=value; } } } window.$ = window.jQuery = jQuery; })(window) $("div").css("color","red") $(".header").css("backgroundColor","pink") $("#inputId").css("backgroundColor","black") //实现的结果:没次需要new一个对象,但是对象的方法是共用的 var $1=$("div"); var $2=$("div"); console.log($1 == $2); //2个对象,false console.log($1.css == $2.css); //同一个方法,true
优化前
优化后
jquery对象不可能相同,后续,内存优化介绍如何适当地解决这种jquery对象消耗的内存
2.5 优化2-原型链
1、jQuery函数里返回的是构造函数(jQuery原型里的init函数)
2、jQuery原型里有的css函数
3、jQuery.prototype.init(selector)只能访问本身及其原型里的内容(原型:构造函数.prototype)
4、所以 jQuery.prototype.init.prototype = jQuery.prototype;
<script> (function(global){ function jQuery(selector){ var _init=jQuery.prototype.init; return new _init(selector); //等价于: //return new jQuery.prototype.init(selector); } jQuery.prototype = { constructor:jQuery, init:function(selector){ const elements = document.querySelectorAll(selector) for(let i = 0;i<elements.length;i++){ this[i] = elements[i]; } this.length=elements.length; }, css(name,value){ for(let i = 0;i<this.length;i++){ let element = this[i]; element.style[name]=value; } } } //此时创建的jquery是init构造函数的实例 //css方法在jquery.prototype对象中 //-->为了让jquery对象可以访问到css方法 // -->让init的原型继承自jQuery.prototype jQuery.prototype.init.prototype = jQuery.prototype; //-->1、创建了一个init的对象 //-->2、执行css方法 // -->找对象本身有没有css方法,并没有 // -->找对象的原型:init.prototype -->jquery.prototype // -->发现jquery.prototype中有一个css方法 window.$ = window.jQuery = jQuery; })(window) $("div").css("color","red") $(".header").css("backgroundColor","pink") $("#inputId").css("backgroundColor","black") var $1=$("div"); var $2=$("div"); console.log($1 == $2); //2个对象,false console.log($1.css == $2.css); //同一个方法,true </script>
2.6 简化代码
1、考虑到需要经常访问jQuery.prototype
2、给jQuery添加了一个fn属性,fn属性等价于prototype属性
3、访问jQuery.fn相当于访问jQuery.prototype
(function(global){ function jQuery(selector){ return new jQuery.fn.init(selector); } //给jquery添加了一个fn属性,fn属性等价于prototype属性 jQuery.fn = jQuery.prototype = { constructor:jQuery, init:function(selector){ const elements = document.querySelectorAll(selector) for(let i = 0;i<elements.length;i++){ this[i] = elements[i]; } this.length=elements.length; }, css(name,value){ for(let i = 0;i<this.length;i++){ let element = this[i]; element.style[name]=value; } } } jQuery.fn.init.prototype = jQuery.fn; window.$ = window.jQuery = jQuery; })(window)