對象
JavaScript中伞梯,萬物皆對象!分為普通對象帚屉、函數(shù)對象谜诫。
普通對象:
1、最普通的對象攻旦,有proto屬性(指向其原型)喻旷,沒有prototype屬性。
2牢屋、原型對象(Person.prototype) 原型對象還有constructor屬性指向構(gòu)造函數(shù)對象且预。函數(shù)對象
凡是通過new Function()創(chuàng)建的都是函數(shù)對象。
Function烙无、Object锋谐、Array、Date皱炉、String厘肮、自定義函數(shù)
特例:Function.prototype(原型對象岛请,卻也是函數(shù)對象)钮莲;
新建對象:用new Object或者{}建的對象是普通對象凉唐。它沒有prototype屬性,只有__ proto __屬性肘习,它指向Object.prototype。
Object:Object是一個函數(shù)對象,Object的原型就是一個Object對象惯退,它里面存在著一些對象的方法和屬性,例如常見的toString方法从藤。
Array:也是一個函數(shù)對象催跪,它的原型就是Array.prototype。它里面存在一些數(shù)組的方法和屬性夷野,例如常見的push懊蒸,pop等方法。
Function:Function也是一個函數(shù)對象悯搔,但它有點特殊骑丸,它的原型就是一個function空函數(shù)。
自定義函數(shù):它的原型就是你給它指定的東西妒貌。如果你不指定通危,那它的原型就是一個Object.prototype。
prototype
原型的概念:每一個JavaScript對象(除null外)創(chuàng)建的時候灌曙,就會與之關(guān)聯(lián)另一個對象菊碟,這個對象就是我們所說的原型,每個對象都會從原型中“繼承”屬性在刺。
在JavaScript中逆害,每個函數(shù)都有一個prototype屬性,這個屬性指向函數(shù)的原型對象增炭。
function Person (age) {
this.age = age
}
Person.prototype.name = "kavin";
var p1 = new Person();
var p2 = new Person();
console.log(p1.name); // kavin
console.log(p2.name); // kavin
上述例子中忍燥,函數(shù)的prototype指向了一個對象,而這個對象正是調(diào)用構(gòu)造函數(shù)時創(chuàng)建的實例的原型隙姿,也就是p1和p2的原型梅垄。
構(gòu)造函數(shù)和原型之間的關(guān)系:
Person(構(gòu)造函數(shù)) →→→→ prototype →→→→ Person.prototype(原型)
proto
每個對象(除null外)都會有的屬性,叫做proto输玷,這個屬性會指向該對象的原型队丝。
function Person() {
// 同上
}
var p3 = new Person();
console.log(person.__proto__ === Person.prototype); // true
補充說明:
絕大部分瀏覽器都支持這個非標準的方法訪問原型,然而它并不存在于Person.prototype中欲鹏,實際上机久,它來自于Object.prototype。與其說是一個屬性赔嚎,不如說是一個getter/setter膘盖,當使用Obj.__ proto __時胧弛,可以理解返回了Object.getPrototypeOf(obj)。
實例對象與原型的關(guān)系:
Person(構(gòu)造函數(shù)) →→→→ prototype →→→→ Person.prototype(原型)
↓ ↑
↓ ↑
p3(實例) →→→→→→→→→→→→→→→→→→→→→→→→→→→→→ __proto__
constructor
每個原型都有一個constructor屬性侠畔,指向該關(guān)聯(lián)的構(gòu)造函數(shù)结缚。
function Person() {
// ... 同上
}
console.log(Person === Person.prototype.constructor); // true
PPS:
function Person() {
// ... 同上
}
var p4 = new Person();
console.log(p4.__proto__ === Person.prototype); // true
console.log(Person === Person.prototype.constructor); // true
console.log(Object.getPrototypeOf(person) === Person.prototype); // true
console.log(p4.constructor === Person); // true
最后一條,當獲取p4.constructor時软棺,其實p4中并沒有constructor屬性红竭,當不能讀取到constructor屬性時,會從p4的原型也就是Peson.prototype中讀取喘落,正好原型中有該屬性茵宪,所以:p4.constructor === Person.prototype.constructor (即:p4.constructor === Person.prototype.constructor === Person)
補充原型指向構(gòu)造函數(shù)指針后的關(guān)系圖:
→→→→ prototype →→→→
Person(構(gòu)造函數(shù)) Person.prototype(原型)
↓ ←←←← constructor ←←←← ↑
↓ ↑
p3(實例) →→→→→→→→→→→→→→→→→→→→→→→→→→→→→→ __proto__
實例與原型
讀取實例的某一項屬性時,如果自身沒有瘦棋,就會查找與自身對象關(guān)聯(lián)的原型中的是否含有這一項屬性稀火,若還無,則遞歸的查找原型的原型赌朋,直至找到最頂層(ps:原型也是一個對象憾股,Object)。
eg:
function Person() {
// ...
}
Person.prototype.sex = "Alpha";
var p5 = new Person;
p5.sex= "Omage";
console.log(p5.sex); // Omage
delete p5.sex;
console.log(p5.name); // Alpha
原型鏈
Ps:上方的“原型”就是對“原型對象”的簡述箕慧。
構(gòu)造函數(shù)、原型茴恰、實例的關(guān)系總結(jié):每個構(gòu)造函數(shù)都有一個原型對象颠焦,原型對象都包含一個指向構(gòu)造函數(shù)的指針,而實例都包含一個指向原型對象的內(nèi)部指針往枣。
每個對象都有一個指向它的原型對象(prototype)的內(nèi)部鏈接伐庭。這個原型對象又有自己的原型,直到某個對象的原型為null為null為止(也就是不再有原型指向)分冈,組成這條鏈的最后一環(huán)圾另。這種一級一級的鏈結(jié)構(gòu)就稱為原型鏈(prototype chain)。
PPS:
Object.prototype.__proto__ === null; // true;
// null 表示“沒有對象”雕沉,即該處不應(yīng)該有值集乔。所以O(shè)bject.prototype.__proto__的值為null,表達的意思就是Object.prototype沒有原型坡椒。
// 當查找屬性查到Object.prototype就可以停止繼續(xù)查找了扰路。
最終的原型鏈關(guān)系圖:
→→→→ prototype →→→→
Person(構(gòu)造函數(shù)) Person.prototype(原型) →→→→
↓ ←←←← constructor ←←←← ↑ ↓
↓ ↑ ↓
p3(實例) →→→→→→→→→→→→→→→→→→→→→→→→→→→→→→ __proto__ __proto__
↓
↓
←←←←←←←←←←←←← ↓
→→→→ prototype →→→→ ↓
Object(構(gòu)造函數(shù)) Object.prototype(原型)
←←←← constructor ←←←← ↓
↓
__proto__
↓
↓
null
上方相互關(guān)聯(lián)的原型組成的鏈狀結(jié)構(gòu)就是原型鏈,也就是:p3(實例) --> Person.prototype(原型) --> Object.prototype(原型) --> null