我正式读过源码的经典框架有4个,我自己的感觉就是——**解读源码之后,真正留在自己脑子里面的,是这个框架的设计思想**。当跟我看完zepto-core的源码之后,你应该会有这种体会。
<br>
## 诡异的数组
那么接下来,先通过最简单的一个例子看一眼zepto的设计。先来一个很简单的html页面,`<body>`中的代码如下:
```html
<p id="p1">测试</p>
<div>
<span>test</span>
<span>test</span>
<span>test</span>
</div>
<script type="text/javascript" src="js/zepto-1.1.6.js"></script>
```
运行页面,然后在chrome的控制台中输入代码做测试。
```js
var $p = $('p'); // $p 是数组
var $span = $('span'); // $span 是数组
```
以上代码中,`$p`和`$span`看起来都是数组,这没有问题。但是我们通过API知道,`$p.addClass`是一个函数,而一般的数组没有`addClass`这个函数。
如果都是一样的数组,那么`$p.addClass`是哪里来的呢?显然`$p`不是一个常规的数组。其实我们还有其他方法可以证明
```js
var arr = [1,2,3];
var $p = $('p');
// 对比1
arr.__proto__.constructor === Array; // true
$p.__proto__.constructor === Array; // false
// 对比2
arr instanceof Array; // true
$p instanceof Array; // false
```
种种迹象表明,`$p`是一个看似数组,而非数组的东西。像《聊斋》里的画皮,是否很诡异。。。
<br>
## 先扒一层皮
如果你对js语法不是很熟练,估计刚才就被这位『画皮』吓蒙了。不过别着急,如果它是画皮,我就是一个称职的老道士。现在先拿一张道符把它点破,然后下一节再教你一招桌妖大法,让你彻底把它打败。
```js
var arr = [1,2,3];
console.log(arr.__proto__); // 输入一个对象
```
如上代码,`arr.__proto__`输出了一个对象,对象里面包含了我们常用的操作数组的函数,例如`concat`,`push`,`map`等,**先不要管这个`__proto__`是什么意思**。就是因为这个`__proto__`有了这些函数,`arr`才能使用。
![](https://box.kancloud.cn/2016-07-04_577a764b28657.png)
js语法非常灵活(号称最大的底线就是无底线),对象是可以随便赋值的,那么我就可以将`__proto__`重新赋值,让数组具有其他函数的功能啊,例如加一个`addClass`函数。
```js
var arr = [1,2,3];
arr.__proto__ = {
addClass: function () {
console.log(123);
}
};
arr.addClass(); // 123
```
注意,经过这一步,`arr.concat`等其他功能就没有,此时`arr`就只有`addClass`这一个函数相依为命了。
![](https://box.kancloud.cn/2016-07-04_577a764cbc605.png)
但是无论如何,此时我们再去拿`arr`来做第一次的那几个验证,得到的结果就和之前的`$p`一样了,即`arr`此时也称了一个不是数组的数组。
而zepto也就是这么干的。