jQuery源码分析系列:Extend扩展方法

前言

  • JQuery是一个JS函数库,可以简单标记被添加到网页中。这个js库封装了各种选择器,可以捕获我们使用的html页面的节点。然后对html进行操作。

什么是封装?

  • 我们可以通过封装一些我们常用的方法或者模块,来提高我们自己的手法,提高我们自己的提高效果,所以我们就需要可以提高我们的效率,这样我们就是可以把更好的分析一下。

最简单的封装案例(toggle)

在js文件夹下我们下载一个真实的jquery以及一个我们自己写的jquery

在这里插入图片描述

  • 在html文件中在这里插入图片描述
  • 在js文件中
;(function(){
    
    
	// 匿名函数自执行
	// jQ的构造函数
	function jQuery(selector){
    
    
		// 返回new 一个初始化函数
		return new jQuery.fn.init(selector);
	}
	// 定义JQuery构造函数的显示原型
	jQuery.fn =jQuery.prototype = {
    
    
		constructor:jQuery,
		jquery:"9.0.0",
		length:0,
		get(index){
    
    
			return this[index];
		},

		each(callback){
    
    
			for(var i=0;i<this.length;i++){
    
    
				callback(this[i])
			}
			return this;
		},
		hide(){
    
    
			console.log("我执行了")
			this.each(function(item){
    
    
				if(item.style.visibility!="hidden"){
    
    
					item.style.visibility="hidden"
				}else{
    
    
					item.style.visibility="visible";
				}
			})

		},
		click(callback){
    
    
			// item指向的被遍历的每个元素
			this.each(function(item){
    
    
				// 让每个元素注册click事件 执行callback方法
				// 也就是click 括号里面的回调函数
				item.addEventListener("click",callback);
			})
			return this;
		},
		toggle(){
    
    
			this.each(function(item){
    
    
				if(item.style.display!="none"){
    
    
					item.style.display="none"
				}else{
    
    
					item.style.display="block";
				}
			})
		}
	}
	// jq初始化函数
	jQuery.fn.init =function(selector){
    
    
		// 获取到选择列表
		var list = document.querySelectorAll(selector);
		// 当前对象的长度
		this.length = list.length;
		for(var i=0;i<list.length;i++){
    
    
			//遍历类别对 this赋值
			this[i] = list[i];
		}
	}
	// 如何让new  init 产生对象拥有JQuery显示原型上的所有方法呢?
	jQuery.fn.init.prototype = jQuery.fn;
	// 全局对jQuery与$可以访问
	window.$=window.jQuery = jQuery;
	
})()

封装插件的要点:

  1. .jquery插件的命名为jquery.[插件名]js;
  2. 所有的对象方法即上面的(1) 附加到jQuery.fn对象. 上,而所有的全局函数附加到jQuery对象本身上;
  3. 插件内部,this指的是 选择器获取的jQuery对象,而非click () 方法内部指的是dom元素。
  4. 所有的方法和函数插件都应该以分号结尾,以方便压缩, 前面可以也加个分号,当然一般使用闭包来解决
  5. 插件应该返回一个Jquey对象,一遍链 式操作链式操作:$(element,.css().attr()
  6. 避免在插件内部使用$作为jQuery对象的别名,使用完整的jQuery来表示, 以避免冲突;
  7. 这两种封装方法传递进来的应该是纯正的object形式,即”函数或方法名/函数主体”;

Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型。

1,jQuery.extend({…})是给function jQuery添加静态属性或方法。
2,jQuery().extend({…})是给jQuery对象添加属性或方法。

一、Jquery的扩展方法原型是:

extend(dest,src1,src2,src3…);

  • 它的含义是将src1,src2,src3…合并到dest中,返回值为合并后的dest,由此可以看出该方法合并后,是修改了dest的结构的。如果想要得到合并的结果却又不想修改dest的结构,可以如下使用:
  • var newSrc=$.extend({},src1,src2,src3...)//也就是将"{}"作为dest参数。
  • 这样就可以将src1,src2,src3…进行合并,然后将合并结果返回给newSrc了。如下例:
  • var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})
  • 那么合并后的结果
  • result={name:"Jerry",age:21,sex:"Boy"}
也就是说后面的参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值。

二、省略dest参数

上述的extend方法原型中的dest参数是可以省略的,如果省略了,则该方法就只能有一个src参数,而且是将该src合并到调用extend方法的对象中去,如:

  • $.extend(src),该方法就是将src合并到jquery的全局对象中去,如:

$.extend({ hello:function(){alert('hello');} });
就是将hello方法合并到jquery的全局对象中。

  • $.fn.extend(src),该方法将src合并到jquery的实例对象中去,如:

$.fn.extend({ hello:function(){alert('hello');} });
就是将hello方法合并到jquery的实例对象中。

  • 下面例举几个常用的扩展实例:

$.extend({net:{}});
这是在jquery全局对象中扩展一个net命名空间。
$.extend($.net,{ hello:function(){alert('hello');} })
这是将hello方法扩展到之前扩展的Jquery的net命名空间中去。

三、Jquery的extend方法还有一个重载原型:

extend(boolean,dest,src1,src2,src3…)

  • 第一个参数boolean代表是否进行深度拷贝,其余参数和前面介绍的一致,什么叫深层拷贝,我们看一个例子:
var result=$.extend( true, {
    
    },
{
    
     name: "John", location: {
    
    city: "Boston",county:"USA"} },
{
    
     last: "Resig", location: {
    
    state: "MA",county:"China"} } );
  • 我们可以看出src1中嵌套子对象location:{city:“Boston”},src2中也嵌套子对象location:{state:“MA”},第一个深度拷贝参数为true,那么合并后的结果就是:
result={
    
    name:"John",last:"Resig",
location:{
    
    city:"Boston",state:"MA",county:"China"}}
  • 也就是说它会将src中的嵌套子对象也进行合并,而如果第一个参数boolean为false,我们看看合并的结果是什么,如下:
var result=$.extend( false, {
    
    },
{
    
     name: "John", location:{
    
    city: "Boston",county:"USA"} },
{
    
     last: "Resig", location: {
    
    state: "MA",county:"China"} }
);
  • 那么合并后的结果就是:location也会合并
result={
    
    name:"John",last:"Resig",location:{
    
    state:"MA",county:"China"}}
下面我们来看看jQuery中的extend方法的实现源代码:

jQuery.extend = function(){}时,函数体中的this对象指的是function jQuery,因此是在jQuery上添加方法和属性。

jQuery.fn.extend = function(){}时,函数体中的this指的是 jQuery.fn = jQuery.prototype,因此是在原型上添加属性和方法。

jQuery.extend = jQuery.fn.extend = function(){
    
    
     var target = arguments[0] || {
    
    },//第一个参数是目标对象
         i=1,
         length = arguments.length,//参数长度
         deep = false,//是否深度拷贝
         options,//用于在复制时记录参数对象
         name,//用于在复制时记录  对象属性名
         src,//用于复制时记录 目标对象的属性值
         copy,//用于复制时记录 添加对象的属性值
         copyIsArray,
         clone;
     if(typeof target === "boolean"){
    
    //第一个参数是布尔型,深度拷贝
         deep = target;//深度拷贝,target赋值给deep
         target = arguments[1] || {
    
    };//把第二个参数作为target
         //跳过boolean和target 从第三个开始
         i = 2;
     }
 
     //不是对象且不是函数  target置空  (string 或其他)
     if(typeof target != "object" && typeof target != "function"){
    
    
         target = {
    
    };
     }
     //如果传入一个参数,是对jquery的扩展
     if(length == i}{
    
    //参数长度等于传递进去的长度  只能在等于1的时候
         target = this;//this是jquery对象本身  在$.fn.extend()中表示jQuery函数所构造对象
         --i;
     }
 
     for(;i<length;i++){
    
    
         //只处理非空参数
         if((options = arguments[i])!=null)
             for (var name in options){
    
    
                 var src = target[name],//目标对象的属性值
                     copy = options[name];//待拷贝 对象或数组的属性值
 
                 if(target === copy){
    
    //存在目标对象本身的引用,构成死循环,结束此次遍历
                     continue;
                 }
                 //深度处理copy 最深为元素 值是纯对象或数组 拷贝原型链中的
                 if(deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))){
    
    
                     if(copyIsArray){
    
    //copy是数组
                         copyIsArray = false;
                         //clone是src的修正值   把当前的数组作为目标数组
                         clone = src && jQuery.isArray(src) ? src : [];
                     }else{
    
    //如果copy是对象     把当前的对象作为目标对象
                         clone = src && jQuery.isPlainObject(src) ? src :{
    
    };//src的修正值
                     }
                     //递归调用jQuery.extend  对copy迭代深度复制
                     target[name] = jQuery.extend(deep,clone,copy);
                 //如果不需要进行深度拷贝
                 }else if(copy! = undefined){
    
    
                     //直接将待增加的对象copy  复制给目标对象
                     target[name] = copy;
                 }
                 //原先的实现方式
                 /*if(deep && copy && typeof copy == "object" && !copy.nodeType)
                     target[name] = jQuery.extend(deep,src || (copy.length !=null ? [] : {}),copy);
                 else if(copy !== undefined)//不能拷贝空值
                     target[name] = copy;*/
             }
         }
     return target;
 };

猜你喜欢

转载自blog.csdn.net/m0_68907098/article/details/128008678