原生js实现 常见的jquery的功能

 

节点操作

 

var div2 = document.querySelector("#div2");
  div2.insertAdjacentHTML("beforebegin","<p>hello world</p>");//在调用元素外部前面添加一个元素
  div2.insertAdjacentHTML("afterbegin","<p>hello world</p>");//在调用元素的内部添加一个子元素并取代了第一个子元素
  div2.insertAdjacentHTML("beforeend","<p>hello world</p>");//在调用元素内部后面添加一个子元素 即取代了最后的子元素
  div2.insertAdjacentHTML("afterend","<p>hello world</p>");//在调用元素的外部后面添加一个元素

 

var  bes=document.getElementById("appends"),
 
 var  strs=  "<li>234</li>";
               
  bes.insertAdjacentHTML('beforebegin', strs);

  

extend 普通深拷贝

 

    
        function extend() {
               var length = arguments.length;
               var target = arguments[0] || {};
               if (typeof target!="object" && typeof target != "function") {
                   target = {};
               }
               if (length == 1) {
                   target = this;
                   i--;
               }
                var hasOwn=Object.prototype.hasOwnProperty;
               for (var i = 1; i < length; i++) {
                   var source = arguments[i];
                   for (var key in source) {
                       // 使用for in会遍历数组所有的可枚举属性,包括原型。
                       if (hasOwn.call(source, key)) {
                           target[key] = source[key];
                       }
                   }
               }
               return target;
           }

 

    var obj1 = {'a': 'obj2','b':'2'};
    var obj2 = {name: 'obj3'};
    console.log('extend',extend({},obj1,obj2),'obj1',obj1,'obj2',obj2);

 jquery 深拷贝

 

function isArray(value) {
				return Array.isArray(value) || Object.prototype.toString.call(value) === '[object Array]';
			}

			function isFunction(fn) {
				return Object.prototype.toString.call(fn) === "[object Function]";
			}

			function isPlainObject(value) {
				if (typeof value !== 'object' || value === null) {
					return false
				}
				if (Object.getPrototypeOf(value) === null) {
					return true
				}
				var proto = value
				while (Object.getPrototypeOf(proto) !== null) {
					proto = Object.getPrototypeOf(proto)
				}
				return Object.getPrototypeOf(value) === proto
			}


			function myExtend() {

				var src, copyIsArray, copy, name, options, clone,
					target = arguments[0] || {},
					i = 1,
					length = arguments.length,
					deep = false;

				// Handle a deep copy situation
				if (typeof target === "boolean") {
					deep = target;
					target = arguments[1] || {};
					// skip the boolean and the target
					i = 2;
				}

				// Handle case when target is a string or something (possible in deep copy)
				if (typeof target !== "object" && !isFunction(target)) {
					target = {};
				}

				// extend jQuery itself if only one argument is passed
				if (length === i) {
					target = this;
					--i;
				}

				for (; i < length; i++) {
					// Only deal with non-null/undefined values
					if ((options = arguments[i]) != null) {
						// Extend the base object
						for (name in options) {
							src = target[name];
							copy = options[name];

							// Prevent never-ending loop
							if (target === copy) {
								continue;
							}

							// Recurse if we're merging plain objects or arrays
							if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
								if (copyIsArray) {
									copyIsArray = false;
									clone = src && isArray(src) ? src : [];

								} else {
									clone = src && isPlainObject(src) ? src : {};
								}

								// Never move original objects, clone them
								target[name] = myExtend(deep, clone, copy);

								// Don't bring in undefined values
							} else if (copy !== undefined) {
								target[name] = copy;
							}
						}
					}
				}

				// Return the modified object
				return target;
			}

  

 




            var obj1 = {
                a: 1,
                name: "张珊",
                title: {
                    text: 'hello world',
                    subtext: 'It/s my world.'
                }
            };
            var obj2 = {
                a: 2,
                name: "李四",
                title: {
                    subtext: 'Yes, your world.'
                }
            }

            //var    obj3= {...{},...obj1,...obj2 }
            // Object.assign(目标对象,...源对象)可以有多个源对象
            //var obj3 =Object.assign({},obj1,obj2)
            //var    obj3= myExtend({},obj1,obj2)
        
            //console.log("$",$.version)
            //var    obj3= $.extend(true,{},obj1,obj2)
            //var    obj3= myExtend({},obj1,obj2)
            var obj3 = myExtend2({}, obj1, obj2)


            obj3.name = '王五'
            console.log("obj1", obj1);
            console.log("obj2", obj2);
            console.log("obj3", obj3, "title", obj3.title);

 

 

去掉JSON  中的  "undefined","null"  等字符串

    function deleteEmptyProp(opt,delArr,del) {
               var delArr=delArr||["undefined","null",undefined,null,NaN];
               for (var key in opt) {
                    var val=opt[key];
                    
                        if (delArr.includes(val)) {
                               if(del){
                                    delete opt[key]; 
                               }else{
                                   var isValueNaN= (typeof val === 'number')&&(val !== val)?1:0;//判断NaN ,替换成0
                                   if(isValueNaN){
                                       opt[key]=0;    
                                   }else{
                                       opt[key]="";   
                                   }
                                    
                               }
                        
                        }
               }
               return opt;
           }

var sas={a: 'duo', b: 0, c: null,d:"null",e:"undefined",f:NaN,g:undefined}
console.log((deleteEmptyProp(sas)))

var sas2={a: 'duo', b: 0, c: null,d:"null",e:"undefined",f:NaN,g:undefined,h:"NaN"}
console.log(deleteEmptyProp(sas2,["undefined","null",undefined,null,NaN]))

 

 合理化 字符串

 

 // "true"  => true
  // "false" => false
  // "null"  => null
  // "42"    => 42
  // "42.5"  => 42.5
  // "08"    => "08"
  // JSON    => parse if valid
  // String  => self
  function deserializeValue(value) {
    var num
    try {
      return value ?
        value == "true" ||
        ( value == "false" ? false :
          value == "null" ? null :
          !/^0/.test(value) && !isNaN(num = Number(value)) ? num :
          /^[\[\{]/.test(value) ? $.parseJSON(value) :
          value )
        : value
    } catch(e) {
      return value
    }
  }

 

 

原生选择器  $('#box')   利用 bind(this)绑定 

<div id="box">
      <ul>
        <li >111  </li>
        <li class="lione">2222</li>
        <li class="lione">3333</li>
     </ul>
     
   
</div>

<div id="box2">
  <p>我是AAAA</p>
     <p>我是BBBB</p>
     </div>

  

//选择器的实现
var element = document.querySelector('selectors');
var elementList = document.querySelectorAll('selectors');


var $=query = document.querySelector.bind(document);
var queryAll = document.querySelectorAll.bind(document);   //这个是最牛逼的  细细体会就会发现 
var fromId = document.getElementById.bind(document);
var fromClass = document.getElementsByClassName.bind(document);
var fromTag = document.getElementsByTagName.bind(document);


//调用
var box=$('#box');
var lioneall=queryAll('li');
var lione=$('.lione');
console.log(box.innerHTML);  //  
console.log(lioneall[2].innerHTML); //333

box.addEventListener('click',function(){	
	console.log('click lione'+lione.innerHTML);  //click lione 2222
}); 

 另一个不错的  https://github.com/snandy/zchain/blob/master/%24/selector.js

/**
 * JavaScript Selector
 * Copyright (c) 2010 snandy
 * Blog: http://snandy.cnglogs.com
 * QQ群: 34580561
 * 
 * $ 获取元素, 在DOM中使用频繁的,根据2/8原则只实现最常用的四种
 * 
 * @param {Object} selector
 * @param {Object} context
 * 
 * 1, 通过id获取,该元素是唯一的
 *    $('#id')
 * 
 * 2, 通过className获取
 *    $('.cls') 获取文档中所有className为cls的元素
 *    $('.cls', el)
 *    $('.cls', '#id')
 *    $('span.cls') 获取文档中所有className为cls的span元素
 *    $('span.cls', el) 获取指定元素中className为cls的元素, el为HTMLElement (不推荐)
 *    $('span.cls', '#id') 获取指定id的元素中className为cls的元素
 *    
 * 3, 通过tagName获取
 *    $('span') 获取文档中所有的span元素
 *    $('span', el) 获取指定元素中的span元素, el为HTMLElement (不推荐)
 *    $('span', '#id') 获取指定id的元素中的span元素
 * 
 * 4, 通过attribute获取
 *    $('[name]') 获取文档中具有属性name的元素
 *    $('[name]', el)
 *    $('[name]', '#id')
 *    $('[name=uname]') 获取文档中所有属性name=uname的元素
 *    $('[name=uname]', el)
 *    $('[name=uname]', '#id')
 *    $('input[name=uname]') 获取文档中所有属性name=uname的input元素
 *    $('input[name=uname]', el)
 *    $('input[name=uname]', '#id')
 */
~function(win, doc, undefined) {
    
// Save a reference to core methods
var slice = Array.prototype.slice

// selector regular expression
var rId = /^#[\w\-]+/
var rTag = /^([\w\*]+)$/
var rCls = /^([\w\-]+)?\.([\w\-]+)/
var rAttr = /^([\w]+)?\[([\w]+-?[\w]+?)(=(\w+))?\]/

// For IE9/Firefox/Safari/Chrome/Opera
var makeArray = function(obj) {
    return slice.call(obj, 0)
}
// For IE6/7/8
try{
    slice.call(doc.documentElement.childNodes, 0)[0].nodeType
} catch(e) {
    makeArray = function(obj) {
        var result = []
        for (var i = 0, len = obj.length; i < len; i++) {
            result[i] = obj[i]
        }
        return result
    }
}

function byId(id) {
    return doc.getElementById(id)
}
function check(attr, val, node) {
    var reg = RegExp('(?:^|\\s+)' + val + '(?:\\s+|$)')
    var attribute = attr === 'className' 
            ? node.className
            : node.getAttribute(attr)
    if (attribute) {
        if (val) {
            if (reg.test(attribute)) return true
        } else {
            return true
        }
    }
    return false
}    
function filter(all, attr, val) {
    var el, result = []
    var i = 0, r = 0
    while ( (el = all[i++]) ) {
        if ( check(attr, val, el) ) {
            result[r++] = el
        }
    }
    return result
}
    
function query(selector, context) {
    var s = selector, arr = []
    var context = context === undefined 
            ? doc 
            : typeof context === 'string' ? query(context)[0] : context
            
    if (!selector) return arr
    
    // id和tagName 直接使用 getElementById 和 getElementsByTagName

    // id 
    if ( rId.test(s) ) {
        arr[0] = byId( s.substr(1, s.length) )
        return arr
    }
    
    // Tag name
    if ( rTag.test(s) ) {
        return makeArray(context.getElementsByTagName(s))
    }

    // 优先使用querySelector,现代浏览器都实现它了
    if (context.querySelectorAll) {
        if (context.nodeType === 1) {
            var old = context.id, id = context.id = '__ZZ__'
            try {
                return context.querySelectorAll('#' + id + ' ' + s)
            } catch(e) {
                throw new Error('querySelectorAll: ' + e)
            } finally {
                old ? context.id = old : context.removeAttribute('id')
            }
        }
        return makeArray(context.querySelectorAll(s))
    }
    
    // ClassName
    if ( rCls.test(s) ) {
        var ary = s.split('.')
        var tag = ary[0] 
        var cls = ary[1]
        if (context.getElementsByClassName) {
            var elems = context.getElementsByClassName(cls)
            if (tag) {
                for (var i = 0, len = elems.length; i < len; i++) {
                    var el = elems[i]
                    el.tagName.toLowerCase() === tag && arr.push(el)
                }
                return arr
            } else {
                return makeArray(elems)
            }
        } else {
            var all = context.getElementsByTagName(tag || '*')
            return filter(all, 'className', cls)
        }
    }

    // Attribute
    if ( rAttr.test(s) ) {
        var result = rAttr.exec(s)
        var all = context.getElementsByTagName(result[1] || '*')
        return filter(all, result[2], result[4])
    }
}

win.query = win.$ = query
}(this, document);

  

offset 函数

var myOffest=function (obj){
var top=0,left=0;
if(obj){
 while(obj.offsetParent){
      top += obj.offsetTop;
      left += obj.offsetLeft;
      obj = obj.offsetParent;
   }
 }

  return{
  top : top,
  left : left
  }
}

  

var jqtop=jQuery('#box2').offset().top;
console.log('jQuery offsetTop  值'+jqtop);  // jQuery offsetTop  值274


var jstop=document.getElementById("box2");
console.log('js offsetTop  值'+myOffest(jstop).top); // js offsetTop  值274

 

	getOffset2(node){
			

		var offest = {
		        top: 0,
		        left: 0
		    };
		    // 当前为IE11以下, 直接返回{top: 0, left: 0}
		    if (!node.getClientRects().length) {
		        return offest;
		    }
		    // 当前DOM节点的 display === 'node' 时, 直接返回{top: 0, left: 0}
		    if (window.getComputedStyle(node)['display'] === 'none') {
		        return offest;
		    }
		    // Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
		    // 返回值包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。
		    // 返回如{top: 8, right: 1432, bottom: 548, left: 8, width: 1424…}
		    offest = node.getBoundingClientRect();
		    var docElement = node.ownerDocument.documentElement;
		    return {
		        top: offest.top + window.pageYOffset - docElement.clientTop,
		        left: offest.left + window.pageXOffset - docElement.clientLeft
		    };
			
		}

  

 

offset限定父类范围

function myOffest(obj,parentObj){
                  var top=0,left=0;
                  
                  if(obj){
                   while(obj.offsetParent){
                      if(parentObj&&obj&&obj.className.indexOf(parentObj)!=-1){
                       break; 
                      }
                        left += obj.offsetLeft;
                        obj = obj.offsetParent;
                     }
                   }
                  //console.log("222  55 最后obj---",obj) 
                    return{
                    left : left
                    }
                  } 

 

getOffsetParent 

function getOffsetParent(element) {
			  // NOTE: 1 DOM access here
			  var offsetParent = element && element.offsetParent;
			  var nodeName = offsetParent && offsetParent.nodeName;
			
			  if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
			    if (element) {
			      return element.ownerDocument.documentElement;
			    }
			
			    return window.document.documentElement;
			  }
			
			  // .offsetParent will return the closest TD or TABLE in case
			  // no offsetParent is present, I hate this job...
			  //console.log("window.getComputedStyle(offsetParent, null).position",window.getComputedStyle(offsetParent, null).position)
			  if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 &&window.getComputedStyle(offsetParent, null).position=== 'static') {
			    return getOffsetParent(offsetParent);
			  }
			
			  return offsetParent;
			}
			
			

			
		   	

 

function getOffsetParent(elem) {
    
      var doc = elem.ownerDocument||document;
    
      var offsetParent = elem.offsetParent ;
      //console.log(elem,"offsetParent",offsetParent)
      var position= offsetParent&&window.getComputedStyle(offsetParent)[ "position"]
      while (offsetParent &&(offsetParent.nodeName !== 'HTML' ) &&position=== "static") {
        offsetParent = offsetParent.offsetParent;
      }
      
      var last=offsetParent|| doc.documentElement;
      
      return offsetParent|| doc.documentElement;
    
    }

  

 

//https://github.com/jquery/jquery/blob/main/src/offset.js  

 

get_position

	function get_position(elem) {
		
	
			var offsetParent, offset,
				elem = elem,
				parentOffset = { top: 0, left: 0 };
	
			// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
			// because it is its only offset parent
			if (window.getComputedStyle(elem)['position'] === "fixed" ) {
	
				// Assume getBoundingClientRect is there when computed position is fixed
				offset = elem.getBoundingClientRect();
	
			} else {
	
	
		       // Get *real* offsetParent
		       offsetParent =getOffsetParent(elem);
		      
			   // console.log("offsetParent nodeName",offsetParent.nodeName)
				//console.log("eaas",eaas)
			   // console.log("offsetParent2",offsetParent2)
		       // Get correct offsets
		       offset = getOffest(elem);
			   
			    
				
		       if ( offsetParent.nodeName !="html" ) {
		       	parentOffset =getOffest(offsetParent);;
		       }
		       
			  
		     
			   var borderTopWidth=window.getComputedStyle(offsetParent)['borderTopWidth']||0;
			   var borderLeftWidth=window.getComputedStyle(offsetParent)['borderLeftWidth']||0;
			   
			
			   
			 // Add offsetParent borders
				parentOffset.top += parseFloat(borderTopWidth);
				parentOffset.left += parseFloat(borderLeftWidth) ;
		
	
	      // Subtract parent offsets and element margins
	      // 可以看出,$().position()的本质是目标元素的offset()减去父元素的offset(),同时还要算上目标元素的margin,因为盒子模型(关键)。
	      //(注意:offset()的本质是getBoundingClientRect()的top、left + pageYOffset、pageXOffset)
	
		
			}
	        
			// Subtract parent offsets and element margins
			var marginTop=window.getComputedStyle(elem)['marginTop']||0;
			var marginLeft=window.getComputedStyle(elem)['marginLeft']||0;
                  console.log(marginTop,"marginLeft",marginLeft)
				  
			var  top2=parseFloat(offset.top||0) - parseFloat(parentOffset.top||0) - parseFloat(marginTop) ;
			var  left2=parseFloat(offset.left||0) - parseFloat(parentOffset.left||0) - parseFloat(marginLeft)
			return {
				top: top2 ,
				left: left2
			};
		}

  

 

setOffset 

function setOffset(elem,props,pixel){
                var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition;
                
                //console.log("setOffset---",elem)
                 //获取元素的position属性的值
                var   position =window.getComputedStyle(elem)['position'];
                 if ( position === "static" ) {
                      elem.style.position = "relative";
                 }
                 
        
                    //{left:8,top:16}
                     curOffset = getOffest(elem);;
                  //0px
                  curCSSTop = window.getComputedStyle(elem)['top']||0;;
                  //0px
                  curCSSLeft = window.getComputedStyle(elem)['left']||0; 
                 
                   calculatePosition = ( position === "absolute" || position === "fixed" ) &&( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
                 
                         if (calculatePosition ) {
                         // curPosition = elem.position();
                            curPosition = get_position(position);
                            curTop = parseFloat(curPosition.top)|| 0;
                            curLeft= parseFloat(curPosition.left)|| 0;
    
                        } else {
                          //0 0
                          curTop = parseFloat( curCSSTop ) || 0;
                          curLeft = parseFloat( curCSSLeft ) || 0;
                        }
                 
                   //解析:
                   //(1)先判断当前元素的 position 的值,没有设置 position 属性的话,默认为 relative,并获取元素的 top、left 属性的值
                   //(2)返回一个对象 obj,obj 的 top 是参数的 top - 默认偏移(offset)的 top + position 设置的 top(没有设置,默认为0),obj 的 left 同理。
                   
                  // 也就是说 offset({top:15,;eft:15}) 的本质为:
                  // 参数的属性减去对应的默认offset属性加上position上的对应属性。    
                 
                  //如果传的参数的有top值
                
                       //参数 top - offset().top + element.top
                      var top = ( props.top - parseFloat(curOffset.top) ) + curTop;
                      //参数 left - offset().left + element.left
                      var left = ( props.left - parseFloat(curOffset.left) ) + curLeft;
                      
                      var pixel=pixel||"px" 
                      //console.log("top",top,'left',left)
                      elem.style.top= top+pixel;
                      elem.style.left= left+pixel;
                
            }

 

 

 setOffset(p2,{top:200,left:position.left})

$(".p1").offset({top:200,left:position.left});

getOffsetRect 获取大小

 

			function getOffsetRect(element) {
			    var elementRect = {
			        width: element.offsetWidth,
			        height: element.offsetHeight,
			        left: element.offsetLeft,
			        top: element.offsetTop
			    };
			
			    elementRect.right = elementRect.left + elementRect.width;
			    elementRect.bottom = elementRect.top + elementRect.height;
			
			    // 位置
			    return elementRect;
			}

  

 找到指定父类元素

			function getParent(element, className, limitClasss) {
							var nowName = element.getAttribute("class") || "";
							var isFind = nowName && nowName.indexOf(className) !== -1 || limitClasss && nowName && nowName
								.indexOf(limitClasss) !== -1;
							if (isFind || !element.parentNode) {
								return element; // 已达到文档根元素,未找到指定父元素
							}
							return getParent(element.parentNode, className); // 继续向上查找
						}

 找到子元素在父元素的索引值 

		function getChildIndex(child) {
							var parent = child.parentNode;
							for (var i = 0; i < parent.children.length; i++) {
								if (parent.children[i] === child) {
									return i;
								}
							}
							return -1; // 如果找不到子元素,返回-1
						}

var liEle = getParent(target, 'li-item', 'ul-item');
var liIndex = 0;
if (liEle) {
liIndex = getChildIndex(liEle);
console.log("liIndex", liIndex)
}

  

数组 forEach的实现

var unboundForEach = Array.prototype.forEach,forEach = Function.prototype.call.bind(unboundForEach);
<div id="box3">
   <p class="klasses">one</p>
   <p class="klasses">two</p>
   <p class="klasses">three</p>
</div>

<script>
var unboundForEach = Array.prototype.forEach,forEach = Function.prototype.call.bind(unboundForEach);
 
var box3=document.getElementById("box3");
var klasses=document.querySelectorAll('.klasses')
forEach(klasses, function (el) {
    el.addEventListener('click', function(){
		alert('点击我的序号'+this.innerHTML);   //点击我的序号 one
		});
});

</script>

jquery的静态方法 $.each

 

function jQueryEach(object, callback, args) {
    var name,
    i = 0,
    length = object.length;
    if (args) {
        if (length == undefined) {
            for (name in object) {
                if (callback.apply(object[name], args) === false) {
                    break
                }
            }
        } else {
            for (; i < length;) {
                if (callback.apply(object[i++], args) === false) {
                    break
                }
            }
        }
    } else {
        if (length == undefined) {
            for (name in object) {
                if (callback.call(object[name], name, object[name]) === false) {
                    break
                }
            }
        } else {
            for (var value = object[0]; i < length && callback.call(value, i, value) !== false; value = object[++i]) {}
        }
    }
    return object
};

 

var arr1 = [ "one", "two", "three", "four", "five" ];
jQueryEach(arr1, function(index){
   console.log(arr1[index]);
  // alert(this)
});


var obj = { one:'张珊', two:'李四', three:3, four:4, five:'王五' };
jQueryEach(obj, function(key, val) {
    console.log('val'+obj[key]);      
});

  

 

	Array.prototype.forEach2=function(fun,context){
            var len=this.length;
            var context=arguments[1];     //即使为undefined,call函数也正常运行。
            if(typeof fun !=="function"){
                throw "输入正确函数!";
            }
            for(var i=0;i<len;i++){
            	fun.apply(context,[i,this[i],this]);
                //fun.call(context,i,this[i],this);
            }
 };
var arr2=[5,6,7];
//arr.forEach2(function(item,index,arr){
//console.log(item,index,arr);
//});

 

hover 方法

 

function hover(myElement,fnOver,fnOut,offEventFlag){
				
				var startX=0;
				var startY=0;
				var startT=null;
				var isEnter=false;
				// 防止多次触发鼠标移入移出事件
				function checkHover(e, target) {
					 var e=e || window.event;
					 var type=e.type.toLowerCase();
					 var related;
					// if (!related || (related !== this && !$.contains(this, related))
				    if (type == "mouseover") {
						related=e.relatedTarget||e.fromElement;
						
				        return (!related || (related !== target && !contains(target, related)));
				    } else {
						related=e.relatedTarget||e.toElement;
				        return (!related || (related !== target && !contains(target, related)));
				    }
				}
				function contains(a,b){
				return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);
				}
				
				myElement.addEventListener("mouseover",enterHandle,false)
				myElement.addEventListener("mouseout",leaveHandle,false)
				myElement.addEventListener("touchstart",enterHandle,false)

				function enterHandle(e){
					        var e=e || window.event;
							var type=e.type.toLowerCase()
				            var touch ;
						
				            if(e.touches){
				                touch = e.touches[0];
				            }else {
				                touch = e;
				            }
							//console.log("11touch",e.touch)
							startX = touch.clientX||touch.pageX ;
						    startY = touch.clientY ||touch.pageY;
							startT=+new Date;
							isEnter=true;
					     		
                    //console.log("1enterHandle",checkHover(e,this))
					if(type==="mouseover"&&checkHover(e,this)||type==="touchstart"){
						 //console.log("2enterHandle",checkHover(e,this))
						fnOver.call(this,e,type)
						 //do someting...
					}
					 if(type==="touchstart"){
						 document.addEventListener("touchend",leaveHandle,false)
						 document.addEventListener("touchcancel",leaveHandle,false)
					 }
						
				}
				function leaveHandle(e){
					//console.log("leaveHandle")
					var e=e || window.event;
					var type=e.type.toLowerCase()
					var touch ;
					if(e.touches||e.changedTouches){
					    touch = e.touches[0]||e.changedTouches[0];
					}else {
					    touch = e;
					}
					
				
				    var	endX = touch.clientX||touch.pageX ;
				    var	endY = touch.clientY ||touch.pageY;
					
					var endT=+new Date;
				    var canEnd=(endT - startT) < 300&&Math.abs(endX - startX) <25&&Math.abs(endY - startY) < 25;
					//var canEnd=Math.abs(endX - startX) <25&&Math.abs(endY - startY) < 25;
					
					  
					 if (isEnter&&type==='touchend') {
					   
						 fnOut.call(this,e,type)          
					    // e.preventDefault&&e.preventDefault();
						  document.removeEventListener("touchend",leaveHandle,false)
						  document.removeEventListener("touchcancel",leaveHandle,false)
						//return false;
					
				    }
					
					//type==='mouseout'&&checkHover(e,this)
					else if(type==='mouseout'&&checkHover(e,this)){
						  //console.log("mouseout",checkHover(e,this))
						fnOut.call(this,e,type)
						 //do someting...
					}
					startX=0;
					startY=0;
					isEnter=false;
				}
				
				var  unbild=function(){
					myElement.removeEventListener("mouseover",enterHandle,false)
					myElement.removeEventListener("mouseout",leaveHandle,false)
					myElement.removeEventListener("touchstart",enterHandle,false)
					//console.log("以销毁")
				}
				
				return unbild;
			
			}
			
			//---------------------

  

  

 

 

	<style>
			*{
				margin:0; padding:0;list-style: none;
			}
			body{height:4000px;}
			.div0{
				width:200px; height:60px; margin:20px;border:1px solid #eee;
				user-select: none;
				}
				.div0:active{
					background-color: rgba(0, 0, 0, .2);
				}
			.divtip{width:100px; height:60px; background-color: #999; color:#fff;
			margin:10px auto;display:none;text-align: center;}
			.div1{
				width:200px; height:200px; border:1px solid red;
			}
			.div2 {
				width:100px; height:80px; border:1px solid #eee;background-color: #999;
				margin-left:100px ;
			}
		</style>
		<div style="width:300px;margin:10px auto;">
		<div  class="div0"> 
		     <div  id="jtip" class="divtip">tip</div>
		</div>
		
		<div id="myElement" class="div1">鼠标悬停我
              <div class="div2" id="childElement">子元素</div>
         </div>
		 
		 <button id="myElement2"  style="margin-top:20px;height:30px;line-height:30px;background-color: #999;border: 0;">
			 点击销毁   hover事件    
		  </button>
	</div>

  

 

 

var element = document.getElementById('myElement');
			var childElement = document.getElementById('childElement');
			var myElement2=document.getElementById('myElement2');
			var jtip = document.getElementById('jtip');
			var timer2=null;
			
		       var aaaEvent=hover(element,function(e,type){
				   if(timer2){
					   clearTimeout(timer2)
				   }
				   jtip.style.display="block"
				   //console.log('进入',e,type);
			   },function(e,type){
				   console.log('离开',e,type);
				   timer2=setTimeout(function(){
					    jtip.style.display="none"
				   },100)
				   
			   })	
			  // console.log("aaaEvent",aaaEvent)
			   
			  
			 myElement2.addEventListener('click', function(event) {
				 console.log("销毁点击")
			     aaaEvent();
				
			 });
			

  

  

 

 --------

 

jQuery.fn.extend( {
	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	}
} );

  

 

 

获取文档高度

//获取文档完整的高度 
var getScrollHeight=function () { 
    return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); 
} 

console.log('jquery文档高度'+jQuery(document).height());  //jquery文档高度1739
console.log('js文档高度'+getScrollHeight()); // js文档高度1739g滚动条

滚动条高度

 

document.getElementById("element").addEventListener("click",function(){
    var scrollTop1 = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
    var scrollTop2 = window.scrollY||document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
    console.log('scrollTop1'+scrollTop1)
     console.log('scrollTop2'+scrollTop2)
 
});

 

  

 

样式操作 

// jQuery  
$('.el').addClass('class');  
$('.el').removeClass('class');  
$('.el').toggleClass('class');  
  
// 原生方法  
document.querySelector('.el').classList.add('class');  
document.querySelector('.el').classList.remove('class');  
document.querySelector('.el').classList.toggle('class');

// 原生方法 扩展添加多个 
DOMTokenList.prototype.adds = function(tokens) {
   tokens.split(" ").forEach(function(token) {
       this.add(token);
   }.bind(this));
   return this;
};

// adds 添加多个
document.querySelector(".el").classList.adds("child1 child2 child3");

 

function hasClass(ele, cls) {
    return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(ele, cls) {
    if (!this.hasClass(ele, cls)) ele.className += " " + cls;
}
function removeClass(ele, cls) {
    if (hasClass(ele, cls)) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
        ele.className = ele.className.replace(reg, ' ');
    }
}

 

获取jsonp

 

 

function getJSONP2(url,success,jsonpCallback,jsonp){
            var jsonp=jsonp||"callback",
             cn=jsonpCallback||"jsonpCallback",
             url=url.toString(),
             dataString = url.indexOf('?') == -1? '?': '&',
            s=document.createElement("script"),
            head=document.head||document.getElementsByTagName("head")[0];
            s.type="text/javascript";
            s.charset="UTF-8";s.src=url+dataString+"_="+(+new Date)+"&"+jsonp+"="+cn;

            head.insertBefore(s,head.firstChild);
            console.log("src",s.src);
            setTimeout(function(){
                window[cn]=function(data){
                    
                    
                    try{s.onload=s.onreadystatechange=function(){
                        var that=this;
                        if((!that.readyState||that.readyState==="loaded"||that.readyState==="complete")){
                            success&&success(data);
                            s.onload=s.onreadystatechange=null;if(head&&s.parentNode){
                                head.removeChild(s)}}}}catch(e){}finally{window[cn]=null}}
                },0)};

 

 

   var url44="http://api.map.baidu.com/geocoder/v2/?sa=1&location=30.290466116991468,120.00192773949404&output=json&pois=1&latest_admin=1&ak=ABq5yEuwLp5Z4yWlRDGX3vEhxxjGDu8L";
        getJSONP2(url44,function(data){
            var data=data;
               data.regeocode=data.result;
        //var  address = data.regeocode.formatted_address;


            console.log(data,"结果" ,  data.regeocode.formatted_address);
            
        })

 

 

//document.addEventListener('click',function(){
getJSONP("https://api.github.com/repos/HubSpot/pace?callback=",function(json){
   alert('success!'+ json.data.id+'获取到的'+json.data.name);
   document.getElementById("testText").innerHTML='回调函数获取到了'+json.data.name;
   document.getElementById("testText").style.cssText='color:red;font-size:22px; border:1px solid #666'
});

清楚字符串空格

function trimStr(str){return str.replace(/(^\s*)|(\s*$)/g,"");}


function TrimAll(str,is_global){ //删除全部空格
      var result;
      result = str.replace(/(^\s+)|(\s+$)/g,"");
      if(is_global.toLowerCase()=="g")
      {
         result = result.replace(/\s/g,"");
       }
      return result;
}

 

tring.prototype.trim = function() {
	return this.replace(/(^\s*)|(\s*$)/g, "");
};
String.prototype.ltrim = function() {
	return this.replace(/(^\s*)/g, "");
};
String.prototype.rtrim = function() {
	return this.replace(/(\s*$)/g, "");
};
 String.prototype.trimAll = function () {  
    return this.replace(/\s+/g, "");  
}    
 

  

 cookie的操作

function addCookie(objName,objValue,objHours){
var str = objName + "=" + escape(objValue);
if(objHours > 0){
var date = new Date();
var ms = objHours*3600*1000;
date.setTime(date.getTime() + ms);
str += "; expires=" + date.toGMTString();
}
str += "; path=/";
document.cookie = str;

};   

function getCookie (objName){
var arrStr = document.cookie.split("; ");
for(var i = 0;i < arrStr.length;i ++){
var temp = arrStr[i].split("=");
if(temp[0] == objName) return unescape(temp[1]);
}
};

原生ajax的操作

 

/**
 * ajax封装
 *  var xmlhttp = new YAjax();
 *    xmlhttp.request({
 *         url : "./demo.php",  // get请求时 可以这样写 "./demo.php?name=zhangsan"
 *        method : "POST",
 *        data : "name=李四",  // 支持json传值 {"name":"zhangsan"}  get时不用该参数
 *        receiveType : "html",  // json html or xml
 *        timeout : 3000,  // 3秒
          async : true,            //默认true  可省略
 *        beforeSend:function(){},   //请求之前回调函数  就得 这边beforesent  s小写  beforesend
 *        success : function(d) {alert(d);},
 *        error : function(xmlhttp){alert('timeout');}
 *    });
 */

 

  

function YAjax() {
    this._self = this;
    this.xmlhttp = this.init()
}
YAjax.prototype = {
    constructor: YAjax,
    init: function() {
        var xmlhttp = null;
        if (window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
            if (xmlhttp.overrideMimeType) {
                xmlhttp.overrideMimeType("text/xml")
            }
        } else {
            if (window.ActiveXObject) {
                var activexName = ["MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
                for (var i = 0; i < activexName.length; i++) {
                    try {
                        xmlhttp = new ActiveXObject(activexName[i]);
                        break
                    } catch(e) {}
                }
            }
        }
        return xmlhttp
    },
    extend: function(destination, source, override) {
        if (undefined == override) {
            override = true
        }
        if (typeof destination != "object" && typeof destination != "function") {
            if (!override) {
                return destination
            } else {
                destination = {}
            }
        }
        var property = "";
        for (property in source) {
            if (override || !(property in destination)) {
                destination[property] = source[property]
            }
        }
        return destination
    },
    json2String: function(jsonData) {
        var strArr = [];
        for (var k in jsonData) {
            strArr.push(k + "=" + jsonData[k])
        }
        return strArr.join("&")
    },
    request: function(opt) {
        var _self = this,
        isTimeout = false,
        timeFlag = 0,
        options = {
            url: "",
            data: "",
            method: "POST",
            receiveType: "html",
            timeout: 7000,
            async: opt.async || true,
            beforeSend: function() {},
            success: function() {
                alert("define your success function")
            },
            error: function(xmlhttp) {}
        };
        if ("data" in opt) {
            if (typeof opt.data == "string") {} else {
                opt.data = this.json2String(opt.data)
            }
        }
        options = this.extend(options, opt);
        this.xmlhttp.onreadystatechange = function() {
            if (_self.xmlhttp.readyState == 2) {
                options.beforeSend && options.beforeSend.apply(_self.xmlhttp, arguments)
            }
            if (_self.xmlhttp.readyState == 4) {
                if (!isTimeout && _self.xmlhttp.status == 200) {
                    clearTimeout(timeFlag);
                    var t = options.receiveType.toLowerCase();
                    if (t == "html") {
                        options.success(_self.xmlhttp.responseText)
                    } else {
                        if (t == "xml") {
                            options.success(_self.xmlhttp.responseXML)
                        } else {
                            if (t == "json") {
                                try {
                                    var obj = JSON.parse(_self.xmlhttp.responseText);
                                    options.success(obj)
                                } catch(e) {
                                    var str = "(" + _self.xmlhttp.responseText + ")";
                                    options.success(JSON.parse(str))
                                }
                            } else {}
                        }
                    }
                } else {
                    clearTimeout(timeFlag);
                    options.error(_self.xmlhttp)
                }
            }
        };
        clearTimeout(timeFlag);
        timeFlag = setTimeout(function() {
            if (_self.xmlhttp.readyState != 4) {
                isTimeout = true;
                _self.xmlhttp.abort();
                clearTimeout(timeFlag)
            }
        },
        options.timeout);
        this.xmlhttp.open(options.method.toUpperCase(), options.url, options.async);
        if (options.method.toUpperCase() == "POST") {
            this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            this.xmlhttp.send(options.data)
        } else {
            this.xmlhttp.send(null)
        }
    }
};

 

 

原生延迟加载插件

/*! echo.js v1.7.0 | (c) 2015 @toddmotto | https://github.com/toddmotto/echo */
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(function() {
      return factory(root);
    });
  } else if (typeof exports === 'object') {
    module.exports = factory;
  } else {
    root.echo = factory(root);
  }
})(this, function (root) {

  'use strict';

  var echo = {};

  var callback = function () {};

  var offset, poll, delay, useDebounce, unload,effectClass;
  var classList= 'classList' in document.documentElement ?1:0;
  var isHidden = function (element) {
    return (element.offsetParent === null);
  };
  
  var inView = function (element, view) {
    if (isHidden(element)) {
      return false;
    }

    var box = element.getBoundingClientRect();
    return (box.right >= view.l && box.bottom >= view.t && box.left <= view.r && box.top <= view.b);
  };

  var debounceOrThrottle = function () {
    if(!useDebounce && !!poll) {
      return;
    }
    clearTimeout(poll);
    poll = setTimeout(function(){
      echo.render();
      poll = null;
    }, delay);
  };

  echo.init = function (opts) {
    opts = opts || {};
    var offsetAll = opts.offset || 0;
    
    var offsetVertical = opts.offsetVertical || offsetAll;
    var offsetHorizontal = opts.offsetHorizontal || offsetAll;
    var optionToInt = function (opt, fallback) {
      return parseInt(opt || fallback, 10);
    };
    offset = {
      t: optionToInt(opts.offsetTop, offsetVertical),
      b: optionToInt(opts.offsetBottom, offsetVertical),
      l: optionToInt(opts.offsetLeft, offsetHorizontal),
      r: optionToInt(opts.offsetRight, offsetHorizontal)
    };
    delay = optionToInt(opts.throttle, 80);
    useDebounce = opts.debounce !== false;
    effectClass=opts.effectClass;
    unload = !!opts.unload;
    callback = opts.callback || callback;
    echo.render();
    if (document.addEventListener) {
      root.addEventListener('scroll', debounceOrThrottle, false);
      root.addEventListener('load', debounceOrThrottle, false);
    } else {
      root.attachEvent('onscroll', debounceOrThrottle);
      root.attachEvent('onload', debounceOrThrottle);
    }
  };

  echo.render = function () {
    var nodes = document.querySelectorAll('img[data-echo], [data-echo-background]');
    var length = nodes.length;
    var src, elem;
    var view = {
      l: 0 - offset.l,
      t: 0 - offset.t,
      b: (root.innerHeight || document.documentElement.clientHeight) + offset.b,
      r: (root.innerWidth || document.documentElement.clientWidth) + offset.r
    };
    for (var i = 0; i < length; i++) {
      elem = nodes[i];
      if (inView(elem, view)) {

        if (unload) {
          elem.setAttribute('data-echo-placeholder', elem.src);
        }

        if (elem.getAttribute('data-echo-background') !== null) {
          elem.style.backgroundImage = "url(" + elem.getAttribute('data-echo-background') + ")";
            
        }
        else {
          elem.src = elem.getAttribute('data-echo');
                 
        }
        
        
        
        if (!unload) {
         if(effectClass){
                      if (classList){    
                      elem.classList.add(effectClass);
                      }else{
                      elem.className += " " + effectClass;      
                       }
                 }    
          elem.removeAttribute('data-echo');
          elem.removeAttribute('data-echo-background');
        }

        callback(elem, 'load');
      }
      else if (unload && !!(src = elem.getAttribute('data-echo-placeholder'))) {

        if (elem.getAttribute('data-echo-background') !== null) {
          elem.style.backgroundImage = "url(" + src + ")";
        }
        else {
          elem.src = src;
        }

        elem.removeAttribute('data-echo-placeholder');
        callback(elem, 'unload');
      }
    }
    if (!length) {
      echo.detach();
    }
  };

  echo.detach = function () {
    if (document.removeEventListener) {
      root.removeEventListener('scroll', debounceOrThrottle);
    } else {
      root.detachEvent('onscroll', debounceOrThrottle);
    }
    clearTimeout(poll);
  };

  return echo;

});
View Code

使用方法

  <img src="img/blank.gif" alt="Photo" data-echo="img/photo.jpg">

  <script src="../echo.js"></script>
  <script>
  echo.init({
    offset: 100,
    throttle: 250,
    unload: false,
    callback: function (element, op) {
      console.log(element, 'has been', op + 'ed')
    }
  });

 

domready(fn)

function Domready(readyFn) {
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", function() {
            readyFn && readyFn()
        }, false)
    } else {
        var bReady = false;
        document.attachEvent("onreadystatechange", function() {
            if (bReady) {
                return
            }
            if (document.readyState == "complete" || document.readyState == "interactive") {
                bReady = true;
                readyFn && readyFn()
            }
        });
        setTimeout(checkDoScroll, 1)
    }
    function checkDoScroll() {
        try {
            document.documentElement.doScroll("left");
            if (bReady) {
                return
            }
            bReady = true;
            readyFn && readyFn()
        } catch (e) {
            setTimeout(checkDoScroll, 1)
        }
    }
};
View Code

 

为元素添加on方法

Element.prototype.on = Element.prototype.addEventListener;

 

为元素添加trigger方法

HTMLElement.prototype.trigger = function (type, data) {
    var event = document.createEvent('HTMLEvents');
    event.initEvent(type, true, true);
    event.data = data || {};
    event.eventName = type;
    event.target = this;
    this.dispatchEvent(event);
    return this;
};

  

 获取文档完整的高度 

//获取文档完整的高度 
var getScrollHeight=function () { 
    return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); 
} 

 

获取当前可是范围的高度

//获取当前可是范围的高度 
var getClientHeight=function () { 
	  var clientHeight = 0; 
	  if (document.body.clientHeight && document.documentElement.clientHeight) { 
	  clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight); 
	  } 
	  else { 
	  clientHeight = Math.max(document.body.clientHeight, document.documentElement.clientHeight); 
	  } 
	  return clientHeight; 
} 

  

 getScrollParent

 function getScrollParent(element, includeHidden, documentObj) {
			           let style = getComputedStyle(element);
			           const excludeStaticParent = style.position === 'absolute';
			           const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
			       
			           if (style.position === 'fixed') {
			               return documentObj.body;
			           }
			           let parent = element.parentElement;
			           while (parent) {
			               style = getComputedStyle(parent);
			               if (excludeStaticParent && style.position === 'static') {
			                   continue;
			               }
			               if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) {
			                   return parent;
			               }
			               parent = parent.parentElement;
			           }
			       
			           return documentObj.body;
			       }

  

其他

 

'use strict';

module.exports = (object, onChange) => {
  const handler = {
    get(target, property, receiver) {
      try {
        return new Proxy(target[property], handler);
      } catch (err) {
        return Reflect.get(target, property, receiver);
      }
    },
    defineProperty(target, property, descriptor) {
      onChange();
      return Reflect.defineProperty(target, property, descriptor);
    },
    deleteProperty(target, property) {
      onChange();
      return Reflect.deleteProperty(target, property);
    }
  };

  return new Proxy(object, handler);
};

  

数组

 

Object.assign

/**
     * The Object.assign() method is used to copy the values of all enumerable own properties from one or more source
     * objects to a target object. It will return the target object.
     * This polyfill doesn't support symbol properties, since ES5 doesn't have symbols anyway
     * Source: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
     * @function
     * @ignore
     */
    if (!Object.assign) {
        Object.defineProperty(Object, 'assign', {
            enumerable: false,
            configurable: true,
            writable: true,
            value: function(target) {
                if (target === undefined || target === null) {
                    throw new TypeError('Cannot convert first argument to object');
                }

                var to = Object(target);
                for (var i = 1; i < arguments.length; i++) {
                    var nextSource = arguments[i];
                    if (nextSource === undefined || nextSource === null) {
                        continue;
                    }
                    nextSource = Object(nextSource);

                    var keysArray = Object.keys(nextSource);
                    for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
                        var nextKey = keysArray[nextIndex];
                        var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
                        if (desc !== undefined && desc.enumerable) {
                            to[nextKey] = nextSource[nextKey];
                        }
                    }
                }
                return to;
            }
        });
    }

 

 

   /**
     * Get bounding client rect of given element
     * @function
     * @ignore
     * @param {HTMLElement} element
     * @return {Object} client rect
     */
    function getBoundingClientRect(element) {
        var rect = element.getBoundingClientRect();

        // whether the IE version is lower than 11
        var isIE = navigator.userAgent.indexOf("MSIE") != -1;

        // fix ie document bounding top always 0 bug
        var rectTop = isIE && element.tagName === 'HTML'
            ? -element.scrollTop
            : rect.top;

        return {
            left: rect.left,
            top: rectTop,
            right: rect.right,
            bottom: rect.bottom,
            width: rect.right - rect.left,
            height: rect.bottom - rectTop
        };
    }

 

 

-----jquery 源码阅读分析-------- start-------------

目标:根据jQuery的思路实现不用new实例化对象

首先用函数实现类,常规的方法:

var aQuery = function(age) {
}
aQuery.prototype = {
  name: function(){},
  age: 18
}
var a = new aQuery();
a.age; // 返回18

 

但jQuery未在外面用new就可以实例化对象,也就是让函数直接返回实例:

var aQuery = function(age) {
  return new aQuery(); // ←把new放进函数了!
}
aQuery.prototype = {
  name: function(){},
  age: 18
}
aQuery().age; // 但是,死循环了!

 为了返回正确的实例,把aQuery类当作一个工厂方法,放到aQuery.prototype中来创建实例:

var aQuery = function(age) {
  return aQuery.prototype.init(); // ←专门搞个init来返回了!
}
aQuery.prototype = {
  init: function() {
    return this;
  },
  name: function(){},
  age: 18
}
aQuery().age; // 返回18了!

  

但是,此时init中的this指向aQuery类,若把init函数也当作一个构造器,aQuery的prototype会被改变:

var aQuery = function(age) {
  return aQuery.prototype.init(age);
};
aQuery.prototype = {
  init: function(s) {
      if (s) this.age = s; // ←age被改了!
      return this;
  },
  name: function(){},
  age: 18
};
var a = aQuery().age; // 未传值,根据原型对象的值,age是18
var b = aQuery(16).age; // 原型对象的age变为16
var c = aQuery(17).age; // 原型对象的age变为17
var d = aQuery().age; // 未传值,age仍为17不变
// “this指向aQuery的原型prototype,aQuery()得到的始终就是aQuery.prototype”,执行后aQuery()的age变为17

  

因此,要通过实例化init函数,让每个this指向各自的实例化对象:

var aQuery = function(age) {
  return new aQuery.prototype.init(age); // ←又把new放进来了!
};
aQuery.prototype = {
  init:function(s){
      if (s) this.age = s;
      return this;
  },
  name:function(){},
  age:18
};
var a = aQuery().age; // 未传值,返回undefined
var b = aQuery(16).age; // 传入16,返回16
var c = aQuery(17).age; // 传入17,返回17
var d = aQuery().age; // 未传值,返回undefined
// “this指向aQuery.prototype.init的实例, aQuery()得到的结果是aQuery.prototype.init的实例”,执行后aQuery()的age为undefined

  

但这样就访问不到aQuery的原型对象了;
为了让this各回各家的同时能够使用aQuery原型对象上的属性和方法,jQuery的骚操作出现了!

  

var aQuery = function(age) {
  return new aQuery.prototype.init(age);
};
aQuery.prototype = {
  init:function(s){
      if (s) this.age = s;
      return this;
  },
  name:function(){},
  age:18
};
aQuery.prototype.init.prototype = aQuery.prototype; // ←把aQuery的prototype赋给init的prototype!
var a = aQuery().age; // 未传值,新生成的实例上没有age,访问原型对象的值,得到18
var b = aQuery(16).age; // 传入16,返回16
var c = aQuery(17).age; // 传入17,返回17
var d = aQuery().age; // 未传值,新生成的实例上没有age,访问原型对象的值,得到18
// “将init的原型和aQuery的原型关联起来,从而通过aQuery()能够访问到aQuery.prototype的属性”,执行后aQuery()的age本身应为undefined,访问原型对象得到18

 

extend的实现

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不赘述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷贝,且被拷贝的属性值本身是个对象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷贝的属性值是个数组
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

                    // Never move original objects, clone them
                    target[ name ] = jQuery.extend( deep, clone, copy );  // 递归~

                // Don't bring in undefined values
                } else if ( copy !== undefined ) {  // 浅拷贝,且属性值不为undefined
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;

 

 

-----jquery 源码阅读分析-------- end-------------

 

 。。。。剩下的慢慢添加...

 http://www.cnblogs.com/surfaces/

posted @ 2016-01-14 18:07  surfaces  阅读(3286)  评论(0)    收藏  举报