JavaScript 中,萬物皆對象!但對象也是有區別的。分爲普通對象和函數對象,Object ,Function 是JS自帶的函數對象。javascript
怎麼區分?其實很簡單,凡是經過 new Function() 建立的對象都是函數對象,其餘的都是普通對象。Function Object 也都是經過 New Function()建立的。html
構造函數可用來建立特定類型的對象。像Object和Array這樣的原生構造函數,在運行時會自動出如今執行環境中。java
function Person() {
}
var person = new Person();
person.name = 'Kevin';
console.log(person.name) // Kevin
複製代碼
按照國際慣例,構造函數始終都應該以一個大寫字母開頭,而非構造函數則應該以一個小寫字母開頭。git
要建立Person的新實例,必須使用new操做符。通常是經歷如下四個步驟:github
上面例子中,person 就用有一個constructor (構造函數)屬性,該屬性是指向Person。api
不管何時,只要建立一個新函數,就會根據一組特定的規則爲該函數建立一個prototype屬性,這個屬性指向函數的原型對象。普通對象沒有 prototype,但有 __proto__
屬性。數組
如上面例子,Person.prototype 指向了原型象,而 Person.prototype.constructor 又指回了Person。函數
而 person 只是一個對象實例。ui
而person能夠訪問保存在原型中的值,但卻不能重寫原型中的值。若是咱們在 person 中添加一個屬性,而該屬性與實例原型中的一個屬性同名,那個person中的屬性會暫時屏蔽原型中的屬性,刪除後,仍是讀回原型中的屬性this
function Person() {
}
Person.prototype.name = 'Perty';
var person = new Person();
person.name = 'Kevin';
console.log(person.name) // Kevin
delete person.name
console.log(person.name) // Perty
複製代碼
解析器的操做是:
刪除後,再運行時:
在建立對象(不管是普通對象仍是函數對象)的時候,都有一個叫作 __proto__
的內置屬性,用於指向建立它的函數對象的原型對象 prototype。以上面的例子爲例:
console.log(person.__proto__ === Person.prototype) // true
複製代碼
一樣的,Person.prototype 也一樣有 proto 屬性,它指向建立它的函數對象(Object)的prototype
console.log(Person.prototype === Object.prototype) // true
複製代碼
繼續,Object.prototype對象也有__proto__屬性,但它比較特殊,爲null
console.log(Object.prototype.__proto__) // null
複製代碼
咱們把這個有 __proto__
串起來的直到 Object.prototype.__proto__
爲null的鏈叫作原型鏈。
person.__proto__ ==> Person.prototype.__proto__ ==> Object.prototype.__proto__ ==> null
讀過zepto的源碼都瞭解到$實際上是一個函數,同時在 $ 身上又掛了不少屬性和方法。
如下代碼:
<p id="p1">段落1</p>
<p id="p2">段落2</p>
<p id="p3">段落3</p>
<script type="text/javascript" src="js/zepto-1.1.6.js"></script>
複製代碼
$('p')
返回的是類數組的同樣東西。
咱們先一步步來分析一下它到底是不是數組:
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真的只是相似數組同樣的數組。而數組是沒有addClass
,removeClass
等等的屬性。
咱們能夠看console中,運行console.log($p.__proto__)
,就能夠看$p
可調用的方法(這也是平時在使用zepto時,忘記api方法名時,能夠即時查出來)
同理,咱們查看數組下面的方法console.log(arr.__proto__)
能夠看到在arr
中是沒有addClass
,removeClass
等等的屬性的。
那咱們也爲arr
建立一個addClass
方法試試:
var arr = [1,2,3]
arr.__proto__ = {
addClass: function () {
console.log(123);
}
};
arr.addClass(); // 123
複製代碼
此時咱們再去拿arr來作第一次的那幾個驗證,獲得的結果就和以前的$p同樣了,即arr此時也稱了一個不是數組的數組
這樣就能夠成功建立了addClass
方法,而這個解析器的操做是:
[1,2,3]
addClass
運行arr.addClass()
時:
這裏只是淺析zepto的基本設計,也是瞭解zepto設計原理的開始,想要更深刻理解zepto,請移步zepto