關於javascript的原型和原型鏈,看我就夠了(二)

溫故

建立對象的三種方式

  • 經過對象直接量
  • 經過new建立對象
  • 經過Object.create()

js中對象分爲兩種

  • 函數對象
  • 普通對象 仔細觀察以下代碼
function Foo(name) {
	this.name = name;
}
var foo = new Foo('陌上寒');
console.log(foo)// Foo{name: "陌上寒"}
//---------------
var foo1 = {name:'"陌上寒"'}
//等價於
var foo1 = new Object()
foo1.name = "陌上寒"
複製代碼

綜合以上,得出結論==>普通對象都是經過函數建立的javascript

prototype

每個函數對象都有一個prototype屬性,可是普通對象是沒有的;html

遺留問題

昨天留下了一些知識點,今天重點討論java

  • constructor
  • _proto_

知新

constructor構造函數

咱們昨天說建立對象的三種方式,第二種是經過new建立對象,segmentfault

var  obj = new Object()//建立一個空對象等同於 var obj = {}
console.log(obj.constructor===Object)//true
複製代碼

Object就是一個構造函數,是js內置的構造函數,上面的例子中Object就是obj的構造函數,這個例子彷佛不太明顯,咱們繼續看瀏覽器

function Foo(name){
    this.name = name
}
var foo = new Foo("陌上寒")
console.log(foo.constructor===Foo)//true
複製代碼

咱們自定義了一個構造函數Foo,Foo是foo的構造函數,foo的構造函數就是Foo 構造函數與其餘函數的惟一區別,就在於調用它們的方式不一樣。不過,構造函數畢竟也是函數,不存在定義構造函數的特殊語法。任何函數,只要經過 new 操做符來調用,那它就能夠做爲構造函數;而任何函數,若是不經過 new 操做符來調用,那它跟普通函數也不會有什麼兩樣。 構造函數在建立時有一個約定,若是是構造函數,那麼首字母要大寫,普通函數首字母小寫函數

constructor和prototype

constructor和咱們昨天討論的prototype有什麼聯繫嗎? 觀察以下代碼的輸出ui

function Foo(name) {
    this.name = name;
}
var foo = new Foo('陌上寒');
console.log(Foo.prototype)
複製代碼

經過昨天的討論咱們得知只有函數對象才存在prototype 輸出 this

Foo.prototype是Foo的原型對象 繼續觀察

function Foo(name) {
    this.name = name;
}
var foo = new Foo('陌上寒');
 console.log(Foo.prototype.constructor===Foo)//true
複製代碼

在默認狀況下,全部原型對象都會自動得到一個 constructor(構造函數)屬性,這個屬性包含一個指向 prototype 屬性所在函數的指針。就拿前面的例子來講,Foo.prototype.constructor 指向 Foo。 咱們得出如下結論 原型對象中的constructor屬性,指向該原型對象對應的構造函數 也就是說上面的例子,Foo的原型對象是Foo.prototype,原型對象(Foo.prototype)中有一個constructor屬性,這個constructor屬性指向原型對象(Foo.prototype)對應的構造函數Foo,用一行代碼歸納spa

console.log(Foo.prototype.constructor===Foo)//true
複製代碼

以上就是constructor和prototype的關係 咱們注意到原型對象(Foo.prototype)中還存在一個屬性_proto_,這又是什麼?它和prototype,constructor又有什麼關聯呢?.net

隱式原型(_proto_)

那麼__proto__是什麼?每一個對象都會在其內部初始化一個屬性,就是_proto_。 Firefox、Safari 和 Chrome 的每一個對象上都有這個屬性 ,而在其餘瀏覽器中是徹底不可見的(爲了確保瀏覽器兼容性問題,不要直接使用 _proto_ 屬性,此處只爲演示)。咱們繼續看代碼

var arr = new Array()
console.log(arr.__proto__===Array.prototype);//true
var str = new String()
console.log(str.__proto__===String.prototype);//true
var Fun = new Function()
console.log(Fun.__proto__===Function.prototype);//true
var bool = new Boolean
console.log(bool.__proto__===Boolean.prototype);//true
var obj = new Object()
console.log(obj.__proto__===Object.prototype);//true
function MyFun() {
	console.log("我是陌上寒");
}
var myfoo = new MyFun()
console.log(myfoo.__proto__===MyFun.prototype);//true
複製代碼

再重複一次:Array,String,Function,Boolean,Object都是js內置的構造函數,MyFun是自定義的構造函數 只有函數對象才存在prototype 全部對象(除了Object.prototype)都存在_proto_ 剛纔咱們討論過,普通對象都是經過函數建立的 根據以上咱們得出結論: 普通對象__proto__指向當前函數對象的原型, 你可能發現了,有一個矛盾的地方,全部對象都存在_proto_,只有普通對象的__proto__指向當前函數對象的原型,那函數對象的__proto__指向哪裏呢?繼續看代碼

function MyFun() {
	console.log("我是陌上寒");
}
console.log(Boolean.__proto__);//ƒ () { [native code] }
console.log(Function.__proto__);//ƒ () { [native code] }
console.log(String.__proto__);//ƒ () { [native code] }
console.log(Array.__proto__);//ƒ () { [native code] }
console.log(Object.__proto__);//ƒ () { [native code] }
console.log(MyFun.__proto__);//ƒ () { [native code] }
複製代碼

函數對象的__proto__輸出的都是ƒ () { [native code] } 函數內部是[native code],也就是系統編譯好的二進制代碼函數,咱們不對此作研究 上面說到,全部對象都有_proto_,原型對象也是對象, 咱們得出結論 原型對象也存在_proto_ 結合以上我門又一次得出結論 原型對象的__proto__指向當前函數對象的原型, 仍是繼續看代碼,便於理解*

console.log('陌上寒'.__proto__===String.prototype);//true
console.log(String.prototype.__proto__===Object.prototype);//true
//等量代換,得出一下結論
console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true
//自此造成了一條鏈,===>原型鏈
複製代碼

解釋一下如上代碼, '陌上寒'是字符串類型,'陌上寒'的構造函數是String(), 因此'陌上寒'的__proto__指向String的原型 String()是js的內置構造函數,繼承自Object,也就是說Object是頂端,是原型鏈的頂端,既然是頂端,因此:

console.log(Object.prototype.__proto__)//null
複製代碼

Object的原型對象是不存在__proto__的

總結

全部對象(不包括Object.prototype)有__proto__屬性,函數對象有prototype屬性; 對象由函數生成; 生成對象時,對象的__proto__屬性指向當前函數的prototype屬性。 Object.prototyp處於原型鏈的頂端,不存在原型,不繼承任何屬性,其餘原型對象都是普通對象,普通對象都具備原型,全部的內置構造函數(以及大部分自定義構造函數)都具備一個繼承自Object.prototype的原型,例如Date.prototype的 屬性繼承自Object.prototype,所以有new Date()建立的Date對象的屬性同時繼承自Date.prototype和Object.prototype,這一系列的原型對象就是所謂的原型鏈。

原文連接

關於javascript的原型和原型鏈,看我就夠了(一)

參考連接 《JavaScript 闖關記》之原型及原型鏈

JavaScript之原型與原型鏈

一篇文章帶你理解原型和原型鏈

完全理解JavaScript原型鏈(一)—__proto__的默認指向

圖解prototype、proto和constructor的三角關係

Object.prototype 原型和原型鏈

三張圖搞懂JavaScript的原型對象與原型鏈

相關文章
相關標籤/搜索