萬物皆對象
在JavaScript中除值類型之外眯停,其他的都是對象,為了說明這點(diǎn),我們舉幾個例子
我們可以使用typeof
來做類型判斷
typeof a; // undefined
typeof 1; // number
typeof 'wclimb'; // string
typeof true; // boolean
typeof function(){}; // function
typeof []; // object
typeof null; // object
typeof {}; // object
除了undefined
巷屿、number
、string
墩虹、boolean
屬于值類型之外嘱巾,其他都是對象。你可能要問了诫钓,不是還有一個是function
嗎旬昭?要校驗(yàn)他是不是應(yīng)該對象可以這樣做:
var fn = function(){}
fn instanceof Object // true
由上面的例子所示,函數(shù)確實(shí)是對象菌湃,為什么呢问拘?我們看一下下面的例子
function Person(name){
this.name = name;
}
var person = new Person('wclimb');
console.log(person) // Person {name: "wclimb"}
由此我們可以得知,對象都是通過函數(shù)創(chuàng)建的,這么說你可能又會說不對骤坐,你看下面的就不是函數(shù)創(chuàng)建的
var person = {name:'wclimb'}
你咋就這么飄呢绪杏?我竟無言以對,沒錯纽绍,這是個意外蕾久、意外、意外拌夏。但是歸根結(jié)底他還是通過函數(shù)創(chuàng)建的
var person = new Object()
person.name = 'wclimb'
so僧著,現(xiàn)在你只要知道對象是通過函數(shù)創(chuàng)建的就可以了,來跟著我讀:
第一遍 對象都是通過函數(shù)創(chuàng)建的
第二遍 對象都是通過函數(shù)創(chuàng)建的
第三遍 對象都是通過函數(shù)創(chuàng)建的
構(gòu)造函數(shù)(constructor)
function Person(name){
this.name = name
}
var person1 = new Person('wclimb 1')
var person2 = new Person('wclimb 2')
上面Person
就是一個構(gòu)造函數(shù)辖佣,我們通過new
的方式創(chuàng)建了一個實(shí)例對象person
我們來看看person1和person2的constructor
(構(gòu)造函數(shù))是不是指向Person的
person1.constructor === Person // true
person2.constructor === Person // true
原型(prototype)
在JavaScript中霹抛,每定義一個函數(shù)都會產(chǎn)生一個prototype
(原型)屬性,這個屬性指向函數(shù)的原型對象
function Person(){}
Person.prototype.name = 'wclimb'
Person.prototype.age = '24'
Person.prototype.sayAge = function(){
console.log(this.age)
}
var person = new Person()
person.sayAge(); // 24
那么這個prototype
到底是什么呢卷谈?跟構(gòu)造函數(shù)有關(guān)系嗎杯拐?
上圖就可以反映出他們之間的關(guān)系
其實(shí)函數(shù)的prototype
指向函數(shù)的原型對象,每個對象都會關(guān)聯(lián)另外一個對象世蔗,也就是原型端逼,上面的例子改成:
Person.prototype = {
name: 'wclimb',
age: 24,
satAge: function(){
console.log(this.age)
}
}
隱式原型(__proto__
)
上面我們說到每定義一個函數(shù)都會產(chǎn)生一個原型,每個函數(shù)它不止有原型污淋,還有一個__proto__
(隱式原型)
每個對象都有一個__proto__
屬性顶滩,指向創(chuàng)建該對象函數(shù)的prototype
,我們可以來試試寸爆,還是上面的例子:
function Person(){}
var person = new Person()
person.__proto__ === Person.prototype // true
現(xiàn)在他們的關(guān)系圖如下
由上圖我們可以知道:
Person.prototype.constructor = Person
person.__proto__ = Person.prototype
person.constructor = Person
我們可以看到person.__proto__
指向構(gòu)造函數(shù)的原型礁鲁,那么構(gòu)造函數(shù)的原型即Person
的__proto__
指向哪里呢?
我們知道構(gòu)造函數(shù)其實(shí)就是由Function
來創(chuàng)建的赁豆,由此得出:
Person.__proto__ === Function.prototype
那么構(gòu)造函數(shù)的原型即Person.prototype
的__proto__
指向哪里呢仅醇?
原型對象其實(shí)是通過Object
生成的,自然而然的得出:
Person.prototype.__proto__ === Object.prototype
那么Object.prototype
的__proto__
指向哪里呢魔种?答案是null
析二,最終得到下面的圖
拋開這張圖,來看看下面幾道題
person.__proto__
Person.__proto__
Person.prototype.__proto__
Object.__proto__
Object.prototype.__proto__
解:
- 每個對象都有一個
__proto__
屬性节预,指向創(chuàng)建該對象函數(shù)的prototype
叶摄,因?yàn)镻erson是person的構(gòu)造函數(shù)
Person === person.constructor
為true
,所以:person.__proto__ === Person.prototype
-
Person
構(gòu)造函數(shù)是由Function
創(chuàng)建的,所以可以得出Person.__proto__ === Fucntion.prototype
- 我們上面說過
Person.prototype
其實(shí)是一個對象安拟,而對象是由Object
創(chuàng)建的蛤吓,所以Person.prototype.__proto__ === Object.prototype
-
Object
對象都是函數(shù)創(chuàng)建的,所以Object.__proto__ === Function.prototype
- 雖然
Object.prototype
是一個對象但是他的__proto__
為null
實(shí)例和原型
當(dāng)我們要取一個值的時候去扣,會先從實(shí)例中取柱衔,如果實(shí)例中存在樊破,則取實(shí)例的值,如果實(shí)例不存在唆铐,則會順著原型里找哲戚,直到找到
function Person(){}
Person.prototype.name = '我來自原型'
var person = new Person()
person.name = '我來自實(shí)例'
console.log(person.name); // 我來自實(shí)例
delete person.name
console.log(person.name)); // 我來自原型
首先person實(shí)例中有這個屬性,返回我來自實(shí)例
,然后將它刪除之后艾岂,會從原型中招顺少,也就是person.__proto__
,因?yàn)?code>Person.prototype === person.__proto__王浴,所以得到我來自原型
總結(jié)
原型和原型鏈基本已經(jīng)講解完脆炎,不過還有待完善,如有錯誤氓辣,還望指正
GitHub:wclimb