Javascript規定,每個函數都有一個prototype對象屬性,指向另外一個對象(原型鏈上面的)。
prototype(對象屬性)的全部屬性和方法,都會被構造函數的實例繼承。這意味着,咱們能夠把那些不變(公用)的屬性和方法,直接定義在prototype對象屬性上。閉包
prototype就是調用構造函數所建立的那個實例對象的原型(proto)。框架
prototype可讓全部對象實例共享它所包含的屬性和方法。也就是說,沒必要在構造函數中定義對象信息,而是能夠直接將這些信息添加到原型中。函數
實例對象與原型之間的鏈接,叫作原型鏈。proto( 隱式鏈接 )
JS在建立對象的時候,都有一個叫作proto的內置屬性,用於指向建立它的函數對象的原型對象prototype。
內部原型(proto)和構造器的原型(prototype)
一、每一個對象都有一個proto屬性,原型鏈上的對象正是依靠這個屬性連結在一塊兒
二、做爲一個對象,當你訪問其中的一個屬性或方法的時候,若是這個對象中沒有這個 方法或屬性,那麼Javascript引擎將會訪問這個對象的proto屬性所指向上一個對 象,並在那個對象中查找指定的方法或屬性,若是不能找到,那就會繼續經過那個對象 的proto屬性指向的對象進行向上查找,直到這個鏈表結束。學習
每個函數都有一個原型屬性prototype(對象屬性),裏面放置的是共有、公有的屬性或者方法。(通常狀況屬性是私有的)。注意,只有函數纔有prototyoe屬性,this
function Person() { } var p = new Person() console.log(Person.prototype); // Object{} console.log(p.prototype); //undefined
這個例子能夠發現,函數是存在prototype屬性的prototype
在 Javascript 語言中,constructor 屬性是專門爲 function 而設計的,它存在於每個 function 的prototype 屬性中。這個 constructor 保存了指向 function 的一個引用。設計
function Person() { } var p = new Person() console.log(Person.prototype); // Object{} console.log(p.prototype); // undifined console.log(p.constructor); //function Person(){} 此處的p是經過 Person函數構造出來的,因此p的constructor屬性指向Person console.log(Person.constructor); //function Function(){} 以前提過,每一個函數實際上是經過new Function()構造的 console.log({}.constructor); // function Object(){} 每一個對象都是經過new Object()構造的 console.log(Object.constructor); // function Function() {} Object也是一個函數,它是Function()構造的 console.log([].constructor); //function Array(){}
console.log(Object.constructor); // function Function() {}
可能你們對於這個有些不理解,畢竟咱們實際開發中哪見過這玩意code
console.log(Function instanceof Object); // true console.log(Object instanceof Function); // true
這樣你們是否是就明白了呢 函數是對象構造的 對象也是函數構造的,倆者便是函數也是對象,因此爲何構造函數它是一個函數卻返回一個對象,倆者是互相繼承的關係對象
var o1 = new f1(); typeof o1 //"object"
function Person(name,age){ this.name = name; this.age = age; this.sayHello = function(){ console.log(this.name + "say hello"); } } var girl = new Person("bella",23); var boy = new Person("alex",23); console.log(girl.name); //bella console.log(boy.name); //alex console.log(girl.sayHello === boy.sayHello); //false
再看下面的代碼blog
function Person(name,age){ this.name = name; this.age = age; } Person.prototype.sayHello=function(){ console.log(this.name + "say hello"); } var girl = new Person("bella",23); var boy = new Person("alex",23); console.log(girl.name); //bella console.log(boy.name); //alex console.log(girl.sayHello === boy.sayHello); //true
var obj = {} 此處等價於 var obj = new Object() console.log(obj.__proto__ === Object.prototype)//true
__proto__
的內置屬性,用於指向建立它的構造函數的原型對象。根據前面的例子咱們很清楚,obj是經過new Object 構造出來的一個對象,那咱們Object的原型對象就是Object.prototype,在Object下面構造出來的全部對象,都有一個__proto__
指向它的原型,咱們稱這個爲原型鏈
var obj = [] console.log(obj.__proto__ === Array.prototype)//true
這個也是同樣的道理
console.log(Array.prototype.constructor)//Array{}
function Person(name,age){ this.name = name; this.age = age; } Person.prototype.sayHello=function(){ console.log(this.name + "say hello"); } var girl = new Person("bella",23); var boy = new Person("alex",23); console.log(Person.prototype.constructor); //Person console.log(girl.__proto__==Person.prototype); //true console.log(girl.constructor==Person); //true
如今看是否是特別簡單 注意這裏是兩個下劃線__proto__
叫 槓槓proto槓槓
接下來給一串代碼
function Person(){ } var person1=new Person()
快速回答
1.person1.__proto__
==
2.person1.constructor
==
3.Person.__proto__
==
4.Person.prototype.constructor
==
5.person1.prototype.constructor
==
6.Person.prototype
==
你們能夠測測輸入的答案打印是否是爲true 若是你很快打出,說明你理解的已經很透徹了
function A(){ } function B(a){ this.a = a; } function C(a){ if(a){ this.a = a; } } A.prototype.a = 1; B.prototype.a = 1; C.prototype.a = 1; console.log(new A().a); //1 console.log(new B().a);//undefined console.log(new C(2).a);//2
咱們先觀察第一個
new A() 很明顯它是A()構造的實例對象,在下面A函數prototype共享了一個屬性a=1,那麼實例對象也能夠經過這個屬性訪問到他的值==1
第一個比較簡單,咱們看第二個
第二個實際上是個坑,首先B()函數它聲明的時候設置了一個參數,注意裏面的方法this,此時this指向的是window,咱們都知道,然而在構造函數以後this指向了new B(),然而此時B 沒有傳入參數,也就是說此時的參數a==undefined,
所以new B()下的屬性a==this.a==undefined (不知道這麼說能不能理解 ̄□ ̄||)
若是咱們給B 傳入一個數(能夠是a,但a必定要先聲明)
console.log(new B(3).a); //3 console.log(new B(5).a); //5
這樣應該就好理解了,總不能咱們本身設置的屬性還覆蓋不來爸爸給你的屬性吧
第三個很好理解,從第二個的角度分析,若是傳入參數,輸出參數,若是沒有 輸出1
function Fun(){ var getName = function(){ console.log(1); } return this; } Fun.getName = function(){ console.log(2); } Fun.prototype.getName = function(){ console.log(3); } var getName = function(){ console.log(4); } function getName(){ console.log(5); } Fun().getName(); //4 getName(); //4 new Fun().getName();//3 new new Fun().getName();//3
作題必定要一步步來,先看第一個 Fun().getName();
很明顯此時是Fun()調用getName(),咱們看看Fun(),注意,函數的返回值永遠是return,此處return返回了this,在函數中這裏的this指向window,也就是說第一步Fun( )返回的是window,轉換一下就是window.getName(),
咱們在什麼找一下全局的getName,最終輸出4
第二個其實很簡單,我感受就是來迷惑咱們的,前面省略了window,很明顯仍是4
第三個也太簡單了,只要你理解了我上面寫的內容,一看就知道輸出3
第四個,兩個new? 不要慌 咱們來分析一下
new後面跟的確定是函數,用來構造實例對象,因此new Fun()這是不能拆的,
很明顯此時new Fun()是一個構造函數,雖然稱之爲函數,但其實它是一個對象,由於函數是方法,而方法是不能調用屬性的,可是對象能夠,既然是對象,何來new 構造呢,因此此處分析能夠獲得new Fun ().getName纔是一體連着的,
那很明顯就是原型下的方法咯,因此輸出3
轉載於:https://www.jianshu.com/p/72156bc03ac1