我正式讀過源碼的經典框架有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`才能使用。

js語法非常靈活(號稱最大的底線就是無底線),對象是可以隨便賦值的,那么我就可以將`__proto__`重新賦值,讓數組具有其他函數的功能啊,例如加一個`addClass`函數。
```js
var arr = [1,2,3];
arr.__proto__ = {
addClass: function () {
console.log(123);
}
};
arr.addClass(); // 123
```
注意,經過這一步,`arr.concat`等其他功能就沒有,此時`arr`就只有`addClass`這一個函數相依為命了。

但是無論如何,此時我們再去拿`arr`來做第一次的那幾個驗證,得到的結果就和之前的`$p`一樣了,即`arr`此時也稱了一個不是數組的數組。
而zepto也就是這么干的。