目录
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个对象,falseconsole.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.prototypejQuery.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个对象,falseconsole.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)