js中的類型有:後端
number,string,boolean,object,undefined,function
因此對象能夠這麼分類:函數
因此函數對象能夠大聲唱咱們不同,既然不同確定得有一點不同的煙火,函數對象的不同在什麼地方呢? 每個函數對象都有一個prototype屬性(Function.prototype除外)this
做爲一個傻傻的後端的我一直覺得每個對象都有一個prototype屬性。每個對象都有的是一個叫作__proto__的隱藏屬性,它指向的就是對象所對應的函數對象的prototype(也就是傳說中的原型對象)prototype
後面咱們再舉例子來講明原型對象,咱們先看一下那些是函數對象,方便理解。code
function FN() {} var FA = function() {} var FF = new Function('arg1', 'arg2', 'console.log(arg1 + arg2)'); FF('a','b'); console.log('typeof Object:' + typeof Object); //function console.log('typeof Object.prototype:' + typeof Object.prototype); //object console.log('typeof Function:' + typeof Function); //function console.log('typeof Function.prototype:' + typeof Function.prototype); //function console.log('typeof FN:' + typeof FN); //function console.log('typeof FA:' + typeof FA); //function console.log('typeof FF:' + typeof FF); //function
不那麼精確的總結一下就是:對象
這裏說一下Function.prototype,由於它又是一個不同的煙火。由於通常的函數對象的prototype都是普通對象,可是Function.prototype是一個函數對象,而且這個函數對象沒有prototype屬性。原型鏈
全部的函數對象的__proto__都指向的是Function.prototypeget
可使用:原型
console.log(Object.getOwnPropertyNames(Function.prototype))
打印一下Function.prototype的屬性,會發現都是一下公共函數。string
咱們把問題簡化來處理,看一個最多見的簡化的原型鏈:
function Person(name, age) { this.name = name; this.age = age; this.hobby = function() { return '實例對象hobby'; } } Person.hobby = function() { return '函數對象hobby'; } Person.prototype.hobby = function(){ return 'prototype hobby'; } var p1 = new Person("tim",20); var p2 = new Person("alice",20); console.log(p1.hobby === p2.hobby);//false console.log(p1.__proto__ == Person.prototype);//true console.log(p2.__proto__ == Person.prototype);//true console.log(p1.__proto__ == p2.__proto__);//true console.log(p1.__proto__.hobby == p2.__proto__.hobby);//true console.log(p1.hobby());//實例對象hobby console.log(Person.hobby());//函數對象hobby
從前面介紹的咱們知道Person是一個函數對象,既然是一個函數對象,那麼Person是有prototype屬性的,因此給Person的prototype的屬性添加一個hobby屬性也是合理的事情了。
Person是一個函數對象,那麼說Person是一個對象也是合理的了,給Person添加一個hobby屬性也是合理的了。
下面就要看一下關鍵的new關鍵字的行爲了,咱們知道Person是一個函數對象,new一個函數對象,基本上執行的就是屬性拷貝,而後把new出來的對象的__proto__指向函數對象的prototype的屬性。
因此上面的p1.hobby === p2.hobby是false是由於他們是2個對象中不一樣的屬性,是2個不一樣的引用。
而p1.proto.hobby == p2.proto.hobby是true是由於這2個都是Person.prototype對象上的屬性hobby是同一個引用。
js原型鏈查找方式就是在當前對象中查找這個屬性,若是沒有就在__proto__指向的對象中去查找,依次查找到Object.prototype結束,由於Object.prototype.proto == null
下面思考一個問題:若是把上面的:
Person.hobby = function() { return '函數對象hobby'; }
去掉會有問題嗎?
答案是會有問題,這個問題有點繞,可是記住咱們前面總結的,全部的函數對象的__proto__指向的都是Function.prototype
全部若是沒有上面的代碼Person.hobby()這個調用在Person函數對象中找不到hobby屬性,就會在Funtion.prototype對象中找,依次找到Object.prototype,顯然是找不到的。
注意原型鏈,不是在Person.prototype中查找,那不在Person對象的原型鏈。