jQuery source code analysis series: Extend extension method

foreword

  • JQuery is a library of JS functions that can be added to web pages with simple markup. This js library encapsulates various selectors that can capture the nodes of the html pages we use. Then operate on the html.

What is encapsulation?

  • We can improve our own methods and improve our own improvement effect by encapsulating some of our commonly used methods or modules, so we need to improve our efficiency so that we can analyze it better.

The simplest encapsulation case (toggle)

In the js folder, we download a real jquery and a jquery written by ourselves

insert image description here

  • in the html fileinsert image description here
  • in the js file
;(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;
	
})()

Key points for encapsulating plugins:

  1. The name of the .jquery plugin is jquery.[plugin name]js;
  2. All object methods (1) above are attached to the jQuery.fn object. On, and all global functions are attached to the jQuery object itself;
  3. Inside the plugin, this refers to the jQuery object obtained by the selector, not the dom element inside the click () method.
  4. All methods and function plug-ins should end with a semicolon to facilitate compression. You can also add a semicolon in front of it. Of course, closures are generally used to solve the problem
  5. The plug-in should return a Jquey object, chain operation chain operation: $(element,.css().attr()
  6. Avoid using $ as an alias for the jQuery object inside the plugin, and use the full jQuery to express it to avoid conflicts;
  7. These two encapsulation methods should pass in the pure object form, that is, "function or method name/function body";

Jquery's extension method extend is a commonly used method in the process of writing plug-ins. This method has some overloaded prototypes.

1. jQuery.extend({...}) is to add static properties or methods to function jQuery.
2. jQuery().extend({...}) is to add properties or methods to the jQuery object.

1. The prototype of Jquery's extension method is:

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

  • Its meaning is to merge src1, src2, src3... into dest, and the return value is the merged dest. It can be seen that after the method is merged, the structure of dest is modified. If you want to get the merged result but don't want to modify the structure of dest, you can use it as follows:
  • var newSrc=$.extend({},src1,src2,src3...)//也就是将"{}"作为dest参数。
  • In this way, src1, src2, src3... can be merged, and then the merged result will be returned to newSrc. For example:
  • var result=$.extend({},{name:"Tom",age:21},{name:"Jerry",sex:"Boy"})
  • Then the merged result
  • result={name:"Jerry",age:21,sex:"Boy"}
That is to say, if the following parameter has the same name as the previous parameter, the latter will overwrite the previous parameter value.

2. Omit the dest parameter

The dest parameter in the prototype of the above extend method can be omitted. If it is omitted, the method can only have one src parameter, and the src is merged into the object calling the extend method, such as:

  • $.extend(src), this method is to merge src into the global object of jquery, such as:

$.extend({ hello:function(){alert('hello');} });
It is to merge the hello method into the global object of jquery.

  • $.fn.extend(src), this method merges src into the instance object of jquery, such as:

$.fn.extend({ hello:function(){alert('hello');} });
It is to merge the hello method into the instance object of jquery.

  • Here are a few examples of commonly used extensions:

$.extend({net:{}});
This is extending a net namespace in the jquery global object.
$.extend($.net,{ hello:function(){alert('hello');} })
This is to extend the hello method to the previously extended Jquery net namespace.

3. Jquery's extend method also has an overloaded prototype:

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

  • The first parameter boolean represents whether to perform deep copy, and the rest of the parameters are consistent with the previous introduction. What is deep copy, let's look at an example:
var result=$.extend( true, {
    
    },
{
    
     name: "John", location: {
    
    city: "Boston",county:"USA"} },
{
    
     last: "Resig", location: {
    
    state: "MA",county:"China"} } );
  • We can see that the nested sub-object location: {city: "Boston"} in src1, and the nested sub-object location: {state: "MA"} in src2, the first deep copy parameter is true, then the merged The result is:
result={
    
    name:"John",last:"Resig",
location:{
    
    city:"Boston",state:"MA",county:"China"}}
  • That is to say, it will also merge the nested sub-objects in src, and if the first parameter boolean is false, let's see what the merged result is, as follows:
var result=$.extend( false, {
    
    },
{
    
     name: "John", location:{
    
    city: "Boston",county:"USA"} },
{
    
     last: "Resig", location: {
    
    state: "MA",county:"China"} }
);
  • Then the result of the merger is: location will also be merged
result={
    
    name:"John",last:"Resig",location:{
    
    state:"MA",county:"China"}}
Let's take a look at the implementation source code of the extend method in jQuery:

When jQuery.extend = function(){}, the this object in the function body refers to function jQuery, so methods and properties are added to jQuery.

When jQuery.fn.extend = function(){}, this in the function body refers to jQuery.fn = jQuery.prototype, so attributes and methods are added to the 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