jQuery方法原生实现---each遍历
来源:互联网 发布:淘宝网网页版 编辑:程序博客网 时间:2024/06/01 07:46
最近有点浮躁,总想着快速前端进阶,成为高手。奈何现实残酷,故此用原生js实现下jQuery一些函数,用于练手。
each遍历类数组,数组挺好用的。网上也有很多教程,原理无非是利用call,apply改变this指针指向,指向谁呢?嗯,js数组!
原生数组有着很多方法能够读取数组元素,例如新增加every()方法遍历数组,IE9以上支持该方法
function each(object,callback){[].every.call(object, function(v, i){ return callback.call(v, i, v) === false ? false : true; }); }each(ages,function(v,i){console.log(i);});
使用扩展方式,对js原生函数进行改造,也就是利用call改变this指针,让其指向传进来的object,后方的function则是参数。合起来就是带有两个参数的匿名function连同数组array同时指向object,此时object便具有原生数组的every特性和带有两个参数方法。
那为何function方法返回布尔值?原因就是every方法遍历返回的便是布尔值。
到此,简单的each遍历就实现了。不过问题来了,此时的each只能是数组和类数组,因为调用的是数组原生方法every,对象格式就不行了。
所以我们还要对象进行遍历,就得再写一个函数,返回对象键和值(key value),我们需要for循环遍历
function each1(obj,fn){ for(var i in obj){ if(fn.call(obj,i,obj[i])===false){ break; } }}var obj = {name:"张三",age:"15"}each1(obj,function(i,v){ console.log(i+" "+v);});
call能够改变this内部指针的指向,从而改变某个对象的执行上下文环境,也就是改变了fn回掉函数的指向,指向了obj对象,从而达到遍历对象目的。所以call也能够用来实现js式的继承,不过es6的出现,弥补好多js缺陷,有兴趣的自己去百度下es6继承。
类数组验证:
<p>1</p> <p>2</p> <p>3</p> <p>4</p>
var p = document.querySelectorAll('p');each1(p,function(i,v){ console.log(i+" "+v.innerHTML);})
结果会输出下标0123和值1234
回过头来看下,我们发现其实这个实现有缺陷,我们并没有对传入的第一个参数做类型判断。如果将对象类型和类数组类型传给第一个函数each,就会报错,它只能处理数组对象。
所以我们要给它添加类型判断,用于区分处理。这里我们要用到一个数组对象属性constructor,constructor 属性返回对创建此对象的数组函数的引用,我们用它来区分各个类型数据。
var test=new Array();if (test.constructor==Array){document.write("This is an Array");}if (test.constructor==Boolean){document.write("This is a Boolean");}if (test.constructor==Date){document.write("This is a Date");}if (test.constructor==String){document.write("This is a String");}
以上是引用w3c网站的例子,我们each遍历函数主要是数组,类数组,对象格式三种格式,所以我们在参数传进来时候做一个判断即可。
var type = (function(){ switch (object.constructor){ case Object: return 'Object'; break; case Array: return 'Array'; break; case NodeList: return 'NodeList'; break; default: return 'null'; break; } })();
到了这里我们就可以保证each函数不出错,数组和类数组调用each,对象格式调用each1,怎么?两个函数,自己开个if--else控制语句就可以合并了。到了这里基本可以算是完事了,但貌似every不支持ie9以下浏览器,那怎么办呢?你完全可以使用第二种方法嘛!数组也是对象啊!!!!!
each1([45,1,5,36],function(i,v){ console.log(i+" "+v);});那each和each1区别?个人猜测,毕竟是原生支持的属性,every在浏览器内部运行总归要快点吧。
那还有没有其它实现?有,你还可以使用arguments代替哈
function each2(){ for(var i=0;i<arguments[0].length;i++){ if(arguments[1].call(arguments[0],i,arguments[0][i])===false){ break; } }}
其实挺无聊的,就先这么着了,但是我们要实现jQuery的each函数,$('xx').each(obj,function(i,v){})这种形式才成,不然和jQuery就没关系了。
那么$('xx')怎么实现呢?简单的好实现,复杂的,自己研究jQuery源代码吧,网络上教程也不少。
<p id="aa">1</p> <p class="bb">2</p> <p class="bb">3</p> <p>4</p>
//$()的简单实现var doc = document;function $(dom){ //dom元素简单区分 //清除空格 dom=dom.replace(/^(\s|\u00A0)+/,'').replace(/(\s|\u00A0)+$/,''); //过滤#和. var str = /[^#|\.]\w*/.exec(dom); //获得#或. var match1 = /^#|\./.exec(dom); console.log(match1) return match1 == "#"?doc.getElementById(str):(match1 == "."?doc.getElementsByClassName(str):doc.getElementsByTagName(str));}console.log($(' #aa'));console.log($('.bb'));console.log($('p'));
以上是$的简单模拟,但是问题还没有解决,它并不能链式调用,怎么办呢?采用jQuery做法,内部返回原型,可是直接返回this没用,函数中this由调用该函数的环境决定。所以我们需要封装成对象,以下是模拟jQuery插件搞得一个简单js库,可以判断是ID,clas和标签,然后做一个链式调用。
+function(window){ var aQuery = function(selector){ return new aQuery.prototype.init(selector); } aQuery.prototype ={ init : function(selector){ //dom元素简单区分 //清除空格 var doc = document; selector=selector.replace(/^(\s|\u00A0)+/,'').replace(/(\s|\u00A0)+$/,''); //过滤#和. var str = /[^#|\.]\w*/.exec(selector); //获得#或. var match1 = /^#|\./.exec(selector); this.selector = match1 == "#"?doc.getElementById(str):(match1 == "."?doc.getElementsByClassName(str):doc.getElementsByTagName(str)); return this; }, each : function(){ console.log(this.selector) for(var i=0;i<this.selector.length;i++){ if(arguments[0].call(this.selector,i,this.selector[i])===false){ break; } } return this; } } aQuery.prototype.init.prototype = aQuery.prototype; window.aQuery = window.$ = aQuery; }(window);$('.bb').each(function(i,v){ console.log(i+" "+v.innerHTML);})
简单说下原理,插件使用立即执行函数包裹,避免变量污染;使用无new构造方法,通过原型赋值实现无new方式;通过每个方法末端返回this,这里this指代aQuery对象,由于js天生原型链,所以返回的方法就可以被链式调用。
参考文章链接:http://www.cnblogs.com/aaronjs/p/3278578.html
http://www.cnblogs.com/MonaSong/p/6424366.html
- jQuery方法原生实现---each遍历
- jQuery 遍历 - each() 方法
- jQuery 遍历 - each() 方法
- jQuery 遍历 - each() 方法
- jQuery 遍历 - each() 方法
- jQuery 遍历 - each() 方法
- jQuery 遍历 - each() 方法
- JQuery遍历 each方法
- jQuery 遍历 - each() 方法
- jquery each,grap遍历方法
- jquery遍历的each方法
- jquery each,grap遍历方法
- JavaScript专题之jQuery通用遍历方法each的实现
- 实现jQuery.each方法
- JQuery遍历-$.each()||$().each()
- 原生js实现jq的$.each()方法
- Jquery 遍历数组之$().each方法与$.each()方法介绍
- Jquery 遍历数组之$().each方法与$.each()方法介绍
- emWin 2天速成实例教程016_不规则异形进度条控件实现方法
- 基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(四)FreeRTOS系统下LwIP-1.4.1的移植
- 指针二三事
- JavaScript 中 apply 、call 的详解
- 玲珑杯 1164
- jQuery方法原生实现---each遍历
- ArcEngine点集构三维面
- JSP九大内置对象和四个作用域
- 分布式和大型机优缺点
- Python Koans Solution —— String
- 编程练习
- 《Java编程思想》第7-10章
- Eclipse Jee Neon打开时报错 code=13的问题
- Linux内核链表总结