原型是 JavaScript 中一個比較難理解的概念,原型相關的屬性也比較多,對象有"[[prototype]]"屬性,函數對象有"prototype"屬性,原型對象有"constructor"屬性。segmentfault
開始原型的介紹以前,咱們首先說說什麼是原型?數組
在 JavaScript 中,原型也是一個對象,經過原型能夠實現對象的屬性繼承,JavaScript 的對象中都包含了一個"[[prototype]]"內部屬性,這個屬性所對應的就是該對象的原型。
"[[prototype]]"做爲對象的內部屬性,是不能被直接訪問的。全部爲了方便查看一個對象的原型,Chrome 等大型瀏覽器廠商提供了"__proto__"這個非標準的訪問器(ECMA 引入了標準對象原型訪問器 "Object.getPrototype(Object)")瀏覽器
function Animal(name, type) { this.name = name; this.type = type; this.getInfo = function(){ console.info("當前動物屬性==>",this.name + 'is' + this.type) } } let dog = new Animal("狗", "犬科哺乳動物") // 當前動物屬性==> 狗is犬科哺乳動物
Step-->1: 查看對象 dog 的原型函數
console.info("__proto__",dog.__proto__); // __proto__ Objectconstructor: ƒ Animal(name, type)__proto__: console.info("constructor=====>",dog.constructor) //constructor=====> ƒ Animal(name, type) { // this.name = name; // this.type = type; // this.getInfo = function(){ // console.info("當前動物屬性==>",this.name + 'is' + this.type)
// 拓展 能夠判斷一個對象是否是數組類型 function isArray(arr){ return arr.constructor.toString().indexOf("Array") > -1; }
*在這裏,dog 對象自己沒有"constructor"這個屬性,可是經過原型鏈查找,這到了 dog 原型(dog.__proto__)的 "constructor"屬性,並找到了Animal函數this
Step-->2: 查看對象 dog 的原型(dog.__proto__)的原型spa
既然 dog 的原型"Animal{}"也是一個對象,那麼咱們就一樣能夠來查看 dog 的原型(dog.__proto__)的原型prototype
console.info(dog.__proto__ === Animal.prototype) console.info(Animal.prototype.__proto__) console.info(Animal.prototype.constructor) console.info(Animal.prototype.constructor === Animal)
經過上面能夠看到,"Animal.prototype"對象和 Animal 函數對象經過"constructor"和 "prototype"屬性實現了相互引用code
Step-->3: 查看對象 Object 的原型對象
經過前一部分能夠看到,will的原型的原型是"Object{}"對象。實際上在JavaScript中,全部對象的原型都將追溯到"Object {}"對象。
下面經過一段代碼看看"Object {}"對象:blog
console.log(Animal.prototype.__proto__ === Object.prototype); console.log(typeof Object); console.log(Object); console.log(Object.prototype); console.log(Object.prototype.__proto__); console.log(Object.prototype.constructor);
Step-->4: 查看對象Function的原型
在上面的例子中,Animal是一個構造函數,在JavaScript中函數也是對象,因此,咱們也能夠經過"__proto__"屬性來查找Animal函數對象的原型。
console.log(Animal.__proto__ === Function.prototype); console.log(Animal.constructor === Function) console.log(typeof Function); console.log(Function); console.log(Function.prototype); console.log(Function.prototype.__proto__); console.log(Function.prototype.constructor);
對於"prototype"和"__proto__"這兩個屬性有的時候可能會弄混,"Person.prototype"和"Person.__proto__"是徹底不一樣的。
在這裏對"prototype"和"__proto__"進行簡單的介紹:
"hasOwnProperty"是"Object.prototype"的一個方法,該方法能判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,由於"hasOwnProperty" 是 JavaScript 中惟一一個處理屬性可是不查找原型鏈的函數。
相信你還記得文章最開始的例子中,經過dog咱們能夠訪問"constructor"這個屬性,並獲得dog的構造函數Animal。這裏結合"hasOwnProperty"這個函數就能夠看到,dog對象並無"constructor"這個屬性。
從下面的輸出能夠看到,"constructor"是dog的原型(dog.__proto__)的屬性,可是經過原型鏈的查找,dog對象能夠發現並使用"constructor"屬性。
"hasOwnProperty"還有一個重要的使用場景,就是用來遍歷對象的屬性。
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.getInfo = function(){ console.log(this.name + " is " + this.age + " years old"); }; var will = new Person("Will", 28); for(var attr in will){ console.log(attr); } // name // age // getInfo for(var attr in will){ if(will.hasOwnProperty(attr)){ console.log(attr); } } // name // age
本文介紹了JavaScript中原型相關的概念,對於原型能夠概括出下面一些點:
全部的對象都有"[[prototype]]"屬性(經過__proto__訪問),該屬性對應對象的原型
全部的函數對象都有"prototype"屬性,該屬性的值會被賦值給該函數建立的對象的"__proto__"屬性
全部的原型對象都有"constructor"屬性,該屬性對應建立全部指向該原型的實例的構造函數
函數對象和原型對象經過"prototype"和"constructor"屬性進行相互關聯
經過這些介紹,相信必定能夠對原型有個清晰的認識。