1.在典型的oop的語言中,如java,都存在類的概念,類就是對象的模板,對象就是類的實例。但在js中不存在類的概念,js不是基於類,而是經過構造函數(constructor)和原型鏈(prototype chains)實現的。但在ES6中引入了類(class)這個概念,做爲對象的模板,新的class寫法知識讓原型對象的寫法更加清晰,這裏不重點談這個java
2.首先咱們來詳細瞭解下什麼是構造器ide
構造函數的特色:函數
a:構造函數的首字母必須大寫,用來區分於普通函數oop
b:內部使用的this對象,來指向即將要生成的實例對象this
c:使用New來生成實例對象spa
eg1:prototype
1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 this.sayHello = function(){ 5 console.log(this.name +"say hello"); 6 } 7 } 8 9 var boy = new Person("bella",23); 10 boy.sayHello(); // bella say hello
構造函數的缺點:code
全部的實例對象均可以繼承構造器函數中的屬性和方法。可是,同一個對象實例之間,沒法共享屬性對象
解決思路:blog
a:全部實例都會經過原型鏈引用到prototype
b:prototype至關於特定類型全部實例均可以訪問到的一個公共容器
c:那麼咱們就將重複的東西放到公共容易就行了
eg2:
1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 this.sayHello = function(){ 5 console.log(this.name + "say hello"); 6 } 7 } 8 var girl = new Person("bella",23); 9 var boy = new Person("alex",23); 10 console.log(girl.name); //bella 11 console.log(boy.name); //alex 12 console.log(girl.sayHello === boy.sayHello); //false
一個構造函數Person生成了兩個對象實例girl和boy,而且有兩個屬性和一個方法。可是sayHello方法是不同的。如上圖(圖畫得很醜)。也就是說當New一個實例對象的時候,都會去建立一個sayHello方法,這就浪費了內存資源,由於sayHello方法使同樣的行爲的,徹底能夠被兩個實例對象共享。
因此,缺點就是:同一個構造函數的對象實例之間沒法共享屬性和方法。
爲了解決構造函數的這個缺點,js提供了prototype屬相來解決該問題。
prototype屬性的做用
js中每一個數據類型都是對象,除了null 和 undefined(這個能夠參考另外一篇將null 和 undefined的博客),而每一個對象都是繼承自一個原型對象,只有null除外,它沒有本身的原型對象,最終的Object的原型爲null
eg3:
1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 } 5 Person.propotype.sayHello = function(){ 6 console.log(this.name + "say hello"); 7 } 8 var girl = new Person("bella",23); 9 var boy = new Person("alex",23); 10 console.log(girl.name); //bella 11 console.log(boy.name); //alex 12 console.log(girl.sayHello === boy.sayHello); //true
由上圖能夠看出,prototype是構造函數的屬性,而consructor則是構造函數的prototype屬性所指向的那個對象,也就是說constuctor是原型對象的屬性。
constructor屬性是定義在原型對象上面,意味着也能夠被實例對象繼承
eg4:
1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 } 5 Person.propotype.sayHello = function(){ 6 console.log(this.name + "say hello"); 7 } 8 var girl = new Person("bella",23); 9 console.log(girl.construcotr); //Person() 10 console.log(girl.construcotr == Person.propotype.construcotr); //true
constructor屬性的做用
a:分辨原型對象究竟是哪一個構造函數
1 function Person(){}; 2 var person1 = new Person(); 3 console.log(person1.construcotr === Person); //true
b:從實例新建另外一個實例
1 function Person(){}; 2 var person1 = new Person(); 3 var person2 = new person1.construcotr(); 4 console.log(person2 instanceof Person); //true
c:因爲constructor屬性是一種原型對象和構造函數的關係,因此在修改原型對象的時候,必定 要注意construtor的指向問題,避免instanceof失真,關於這一點,會在繼承中講到。
3.瞭解了構造器,咱們來看下原型prototype
JS中萬物都是對象,可是對象也分爲:普通對象和函數對象,也就是Object 和 Function.
那麼怎麼區分普通對象和函數對象呢? ---凡是經過New Function()建立的對象都是函數對象,其餘的都是普通對象.
須要注意的是:普通對象沒有propotype(prototype便是屬性也是對象),可是有__proto__屬性。
js建立對象的時候都有一個__propo__內置屬性,用於指向建立它的函數對象的原型對象prototype。
咱們仍是來根據eg3的代碼來分析原型鏈
console.log(girl.__proto__ === Person.protype);//true
console.log(Persion.propotype.__proto__ === Object.propotype);//true
console.log(Object.porpotype.__proto__); //null
經過__proto__串起來直到Object.propotype.__proto__爲null的鏈叫作原型鏈(矩形表示函數對象,橢圓形表示普通對象)
也許看到這個圖會有幾個疑問
a:爲何Object.__proto__指向Function.prototype?
Object是函數對象,是經過new Function()建立的,因此...
b:Function.__proto__ === Function.prototype //true
Function也是對象函數,經過new Function()建立,因此...