Open youngwind opened 8 years ago
让我们回顾一下之前我们已经完成的功能。
但是,还存在这样的问题。如图
跟jquery对比我们就会发现目前我们的代码还有以下问题:
我们先来看第一个问题。 我的代码之前是通过把dom元素存储在this.dom中,this还有addClass、removeClass等方法,this是一个对象。但是,jquery返回的居然是一个数组,而且关键是这个数组还能有addClass这些方法!我觉得这是让我非常疑惑的地方。 我去查看jquery的源码,发现了这个
jQuery.fn = jQuery.prototype = { // The default length of a jQuery object is 0 length: 0, splice: arr.splice };
我很奇怪为什么需要定义一个length属性呢?prototype不是一个对象吗?而且splice方式不是array才有的方法吗? 后来google到这篇文章,让我豁然开朗。http://mao.li/javascript/array-like-objects-in-javascript/
没错,问题的核心就是类数组对象:这是一个对象,但是它具有数组的特性。举个例子。
var a = { id: 1, name: "youngwind" }; for (var i = 0; i < a.length; i++) { console.log(a[i]) }
这段代码运行的结果是:没有任何输出。 因为a是一个对象,而且它没有length属性,a.length是undefined,所以循环不会被执行。
我们来改造一下这段代码
var a = { 0: 1, 1: "youngwind", length: 2, }; for (var i = 0; i < a.length; i++) { console.log(a[i]) }
执行结果:输出1,youngwind 到目前为止依然没什么大问题。因为对象获取属性的值本来就可以通过[]来获取。
我再改一下代码。
var a = { 0: 1, 1: "youngwind" }; for (var i = 0; i < a.length; i++) { console.log(a[i]) } Array.prototype.push.call(a, 'blabal') console.log(a);
程序执行结果:循环没有输出。最后输出{0: "blabal", 1: "youngwind", length: 1} 有没有觉得很奇怪?为什么a明明是一个对象,却可以使用数组的push方法?而且调用之后第0项被重置,还多了一个length属性!而且length属性为毛是1啊!我明明有两个属性啊!
犀牛书上7.11章节给出了答案: 这个一个类数组对象,其实在js中,对象和数组的区别并没有看起来那么大 所谓数组背后的实现也不过是key值为非负整数的对象而已。这就不难解释为什么对象可以使用数组的方法了,虽然使用的结果会出现很怪异的情况,就像上面的例子。
ok,我们就到这儿。不去深究更多的数组和对象的细微区别。现在我想知道的是: 如何让一个对象表现得像数组?也就是说,如果让T('selector')返回的对象在浏览器中被解析成数组,而且我通过数组的各种方法去操作这个对象的时候,不会出现怪异的情况。
jquery的源码和刚刚那篇文章给了我们指引。 再改代码
var a = { 0: 1, 1: "youngwind", length: 2, splice: [].splice }; for (var i = 0; i < a.length; i++) { console.log(a[i]) }
结果如图所示
ok,这样我们终于可以返回一个类数组了!这也为后面的链式调用做好了准备。
所谓链式调用,也就是《js语言精粹》中提到的级联,每次执行完方法都返回this,这样就可以一个接口一个接口的调用下去了。有了上面的准备,this既是一个拥有各种方法的对象,也是一个可以直接遍历的类数组,所以我们可以直接return this作为每个函数的返回了。下面给出代码。
T.prototype = { splice: [].splice, length: 0, init: function (selector) { var ele = document.querySelectorAll(selector); for (var i = 0; i < ele.length; i++) { this[i] = ele[i]; } this.length = ele.length; return this; }, addClass: function (className) { for (var i = 0; i < this.length; i++) { this[i].classList.add(className); } return this; }, removeClass: function (className) { for (var i = 0; i < this.length; i++) { this[i].classList.remove(className); } return this; } };
效果图
问题
让我们回顾一下之前我们已经完成的功能。
但是,还存在这样的问题。如图
跟jquery对比我们就会发现目前我们的代码还有以下问题:
类数组对象
我们先来看第一个问题。 我的代码之前是通过把dom元素存储在this.dom中,this还有addClass、removeClass等方法,this是一个对象。但是,jquery返回的居然是一个数组,而且关键是这个数组还能有addClass这些方法!我觉得这是让我非常疑惑的地方。 我去查看jquery的源码,发现了这个
我很奇怪为什么需要定义一个length属性呢?prototype不是一个对象吗?而且splice方式不是array才有的方法吗? 后来google到这篇文章,让我豁然开朗。http://mao.li/javascript/array-like-objects-in-javascript/
没错,问题的核心就是类数组对象:这是一个对象,但是它具有数组的特性。举个例子。
这段代码运行的结果是:没有任何输出。 因为a是一个对象,而且它没有length属性,a.length是undefined,所以循环不会被执行。
我们来改造一下这段代码
执行结果:输出1,youngwind 到目前为止依然没什么大问题。因为对象获取属性的值本来就可以通过[]来获取。
我再改一下代码。
程序执行结果:循环没有输出。最后输出{0: "blabal", 1: "youngwind", length: 1} 有没有觉得很奇怪?为什么a明明是一个对象,却可以使用数组的push方法?而且调用之后第0项被重置,还多了一个length属性!而且length属性为毛是1啊!我明明有两个属性啊!
犀牛书上7.11章节给出了答案: 这个一个类数组对象,其实在js中,对象和数组的区别并没有看起来那么大 所谓数组背后的实现也不过是key值为非负整数的对象而已。这就不难解释为什么对象可以使用数组的方法了,虽然使用的结果会出现很怪异的情况,就像上面的例子。
ok,我们就到这儿。不去深究更多的数组和对象的细微区别。现在我想知道的是: 如何让一个对象表现得像数组?也就是说,如果让T('selector')返回的对象在浏览器中被解析成数组,而且我通过数组的各种方法去操作这个对象的时候,不会出现怪异的情况。
jquery的源码和刚刚那篇文章给了我们指引。 再改代码
结果如图所示
ok,这样我们终于可以返回一个类数组了!这也为后面的链式调用做好了准备。
链式调用
所谓链式调用,也就是《js语言精粹》中提到的级联,每次执行完方法都返回this,这样就可以一个接口一个接口的调用下去了。有了上面的准备,this既是一个拥有各种方法的对象,也是一个可以直接遍历的类数组,所以我们可以直接return this作为每个函数的返回了。下面给出代码。
效果图