JavaScript中萬物皆對象,但對象之間也是有區別的。分為函數對象和普通對象
普通對象和函數對象
凡是通過new Function創建的對象都是函數對象,其他都是普通對象(通常通過Object創建),可以通過typeof來判斷。
由function創造出來的函數,比如
function f1(){};
typeof f1 //"function"
var f2 = function() {}
typeof f2 // "function"
var o1 = new f1();
typeof o1 //"object"
var o2 = {};
typeof o2 //"object"
可能有人會問,不是通過new Function創建的對象才是函數對象嗎?注意下面這兩種寫法是一樣的
function f1(){}; 等價於 var f1 = new Function();
寫了這麼多,有些人可能不展示了,這跟原型有什麼關係呢?
下面兩句話很重要
1、每一個函數對象都有一個prototype屬性,但是普通對象是沒有的;
prototype下面又有個construetor,指向這個函數。
2、每個對象都有一個名為_proto_的內部屬性,指向它所對應的構造函數的原型對象,原型鏈基於_proto_;
普通對象
var o = {};
1、o的確沒有prototype屬性
2、o是Object的實例
console.log(o.prototype); //undefined
console.log(o instanceof Object); //true
函數對象
function Fun(){};
var f1 = new Fun ();
1、Fun是函數對象,f1還是普通對象
2、f1是Fun的實例
console.log(f1.prototype); //undefined
console.log(f1 instanceof Fun); //true
原型對象
說到原型對象,我們先了解下構造函數是什麼?構造函數與其他函數唯一的區別在於調用方式不同。任何函數只要通過new來調用就可以作為構造函數,它是用來創建特定類型的對象。
下面定義一個構造函數Animal:
function Animal (name){
this.name = name;
this.species = '動物';
}
通過new命令來生成一個Animal實例:
var cat = new Animal ("貓")
這裡,構造函數Animal就是實例對象cat的原型!!!Animal裡的this關鍵字就指的是cat這個對象!
new出來的cat對象此時已經和Animal再無聯繫了!也就是說每一個new出來的實例都有自己的屬性和方法的副本,是獨立的的!修改其中一個不會影響另一個!
var dog = new Animal("狗");
dog.species = '食肉動物';
console.log(cat.species) // 動物
console.log(dog.species) // 食肉動物
但是,我們希望構造函數中的species屬性是一個共有屬性,那麼此時用這樣的方法,每個實例中都有一個相同的species屬性,會造成資源極大的浪費!
那麼原型對象就即將登場了!給每一個構造函數都設置一個prototype屬性,這個屬性就指向原型對象。其實原型對象就只是個普通對象,裡面存放著所有實例對象需要共享的屬性和方法!所以,我們把需要共享的放到原型對象裡,把那些不需要共享的屬性和方法存在構造函數里!
那麼上面的代碼怎麼修改呢?
function Animal (name){
this.name = name;
}
Animal.prototype.species = '動物';
var cat = new Animal ("貓");
var dog = new Animal("狗");
console.log(cat.species) // 動物
console.log(dog.species) // 動物
Animal.prototype.species = '食肉動物';
console.log(cat.species) // 食肉動物
console.log(dog.species) // 食肉動物
可以看出,修改prototype屬性會影響它的所有實例的species的值!!
實例一旦創建出來就會自動引用prototype對象的屬性和方法!所以實例對象的屬性和方法一般分為兩種:一種是自身的,一種是引用自prototype的。
具體實現是這樣的:
每當代碼讀取某個對象的某個屬性的時候,都會執行一次搜索。首先從對象實例本身開始,如果在實例中找到了該屬性,則返回該屬性的值,如果沒有找到,則順著原型鏈指針向上,到原型對象中去找,如果找到就返回該屬性值。
原型鏈
事實上,js裡完全依靠"原型鏈"(prototype chain)模式來實現繼承。
上面說完原型對象。下面要扒一扒__proto__、prototype、constructor
__proto__:事實上就是原型鏈指針!!
prototype:上面說到這個是指向原型對象的
constructor:每一個原型對象都包含一個指向構造函數的指針,就是constructor
繼承實現方式:
為了實現繼承,__proto__會指向上一層的原型對象,而上一層的結構依然類似,那麼就利用__proto__一直指向Object的原型對象上!Object.prototype.__proto__ = null;表示到達最頂端。如此形成了原型鏈繼承。
下面有個圖解非常經典,可以手畫幾遍去理解,非常有效~
閱讀更多 web前端技術 的文章
關鍵字: 動物 對象 JavaScript