JQuery模拟二------添加extend函数和简单选择器
在原来的基础上添加extend函数和#id选择器
//自调函数把window这个全局变量传入 (function(){ //把jQuery和$另存一份 var _jQuery = window.jQuery,_$ = window.$; //在上次的代码上添加选择器机制 var jQuery = window.jQuery = window.$ = function(selector,context){ return new jQuery.fn.init(selector,context); } //对 HTML strings or ID strings进行判定 /*可以把它看作是两个正则表达式串: 第一个:^[^<]*(<(.|\s)+>)[^>]*$ 第二个:^#(\w+)$ /^ 字符串开始 [^<]* 匹配不包含<号的任意长度字符,长度可以为0 (<(.|\s)+ 匹配任意字符或空白符,长度必须大于等于1 >)[^>]* 匹配不包含>号的任意字符,长度可以为0 $ 字符串结束 | 或 ^ 字符串开始 # 匹配符号# (\w+) 匹配a-zA-z0-9,也就是所有英文字母及数字,长度大于等于1 $/; 结束*/ var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; jQuery.fn = jQuery.prototype = { init:function(selector,context){ selector=selector||document; context=context||document; //如果传入的是DOM 节点对象 if ( selector.nodeType ) { this[0] = selector; this.length = 1; return this; } //对于选择器是字符串有可能是#id if ( typeof selector == "string" ) { // Are we dealing with HTML string or an ID? var match = quickExpr.exec(selector); console.log(match); // Verify a match, and that no context was specified for #id if ( match && (match[0] || !context)) { var elem = document.getElementById( match[3] ); this.length=1; return jQuery(elem); } selector = []; } //console.log("this is:"+Object.prototype.toString.call(this)); return this; }, //新增加一个方法用来取得或设置jQuery对象的html内容 html:function(val){ //遍历通过回调函数来设置innerHTML为val参数 return jQuery.each(this,function(val){ this.innerHTML=val; },val); }, length: 0, jquery:"1.0.0", author:"BaiQiang", size:function(){ return this.length; } }; //简单的遍历函数 jQuery.each=function(obj,callback,args){ for(var i=0;i<obj.length;i++){ callback.call(obj[i],args); } return obj; }; //需要深入理解一下jQuery的复制函数写法 jQuery.extend = jQuery.fn.extend = function() { /// <summary> /// 用一个或多个其他对象来扩展一个对象,返回被扩展的对象。 /// 用于简化继承。 /// jQuery.extend(settings, options); /// var settings = jQuery.extend({}, defaults, options); /// </summary> //target是被扩展的对象,默认是第一个参数(下标为0)或者是一个空对象{} var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; /*如果传进来的首个参数是一个boolean类型的变量,那就证明要进行深度拷贝。 而这时传进来的argumens[1]就是要拷贝的对象.如果是这种情况,那就要做一些"矫正"工作, 因为这个时候,target变量指向的是一个布尔变量而不是我们要拷贝的对象.*/ if ( target.constructor == Boolean ) { deep = target; target = arguments[1] || {}; //这样的话使得i=2直接跳过前两个参数 i = 2; } // 如果target不是objet 并且也不是function 就默认设置它为{}; if ( typeof target != "object" && typeof target != "function" ) target = {}; //一个参数的就是扩展jQuery对象本身 if ( length == i ) { target = this; --i; } for ( ; i < length; i++ ) //非null的扩展对象才把它扩展到被扩展对象上来. if ( (options = arguments[ i ]) != null ) // Extend the base object for ( var name in options ) { //target是被扩展对象 options是扩展对象, 它的方法或属性将会被扩展到target上 var src = target[ name ], copy = options[ name ]; // target和copy如果相等还深拷贝的话就出问题了 if ( target === copy ) continue; // Recurse if we're merging object values //递归src和copy深度拷贝即对每一个属性递归 //要是没有nodeType, 就是非Dom对象引用, 可以对它进行深度拷贝 if ( deep && copy && typeof copy == "object" && !copy.nodeType ) target[ name ] = jQuery.extend( deep, // Never move original objects, clone them src || ( copy.length != null ? [ ] : { } ) , copy ); // Don't bring in undefined values //如果要加进来的引用不是对象的引用(只要不是undefined ) 那就把引用加进来 //可能是覆盖也可能是新建name这个属性或方法 else if ( copy !== undefined ) target[ name ] = copy; } //返回扩展后的被扩展对象 return target; }; //使用jQuery的原型覆盖init的原型 这样就自动把jQuery.prototype的方法可以在init里面使用 jQuery.fn.init.prototype=jQuery.fn; })(window);
再来测试一下,给它添加一个getName()方法 然后我们调用一下它
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script type="text/javascript" src="jquery.js"></script> </head> <body> <script type="text/javascript"> jQuery.extend({ getName: function(){ return "bq's jQuery" } }); console.log(jQuery().jquery); console.log(jQuery.getName()); </script> </body> </html>
结果如下