衆所周知,JavaScript是一門面向對象的操做語言,而咱們想要用JavaScript對象化寫法的時候,不得不提出一個操做符,叫作new操做符,那麼不用new操做符和用new操做符有什麼區別呢?javascript
首先,咱們去看下new在JavaScript裏面的用法,按照javascript語言精粹中所說,若是在一個函數前面帶上new來調用該函數,那麼將建立一個隱藏鏈接到該函數的prototype成員的新對象,同時this將被綁定到那個新對象上。這句話說得很抽象,咱們根據代碼來理解。java
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } //沒用new關鍵字 var foo2 = foo(); console.log(foo2);//23 //用new關鍵字 var foo3 = new foo(); console.log(foo3);//foo {name: "John", age: 23}
經過上面的代碼能夠明顯看出區別,當咱們不用new關鍵字的時候咱們只是把foo函數運行了一遍,若是有返回值就就得到這個返回值,沒有返回值就輸出underfind,只是簡單的函數運行一遍而已。
可是當咱們用new關鍵字的時候,咱們就能夠看到不一樣了,new關鍵字是生成一個對象,而且生成的對象裏面的屬性是foo函數公有屬性(即只有用this關鍵字定義的變量),而忽略掉私有變量(即用var定義的變量)和函數返回值,這樣上面關於new關鍵字的解釋就好理解了,即經過new操做符建立一個鏈接到foo函數的對象,對象裏包含foo函數裏面全部屬性和方法。這就是new關鍵字的做用,而且this是指向咱們當前的對象foo3.chrome
js語言沒有類這個概念,因此提出用原型來代替類來實現js面向對象寫法。js規定每一個函數都具備prototype對象,而且prototype對象在函數外部是能夠訪問的,能夠經過"prototype.xxx"來爲當前函數增長屬性和方法,因此prototype屬性能夠理解爲當咱們想爲這個函數添加屬性或者方法時咱們能夠在prototype屬性下面添加,而不須要去改變構造函數的代碼。編程
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } console.log(foo.prototype);//Object {}
chrome的運行結果以下圖:瀏覽器
能夠看到foo函數裏的prototype是能夠訪問的,而且咱們所添加的函數是在prototype對象裏的。這樣,咱們就能夠經過prototype屬性向對象添加屬性和方法。編程語言
在上面的咱們看到chrome瀏覽器運行結果的圖中,咱們打印foo函數prototype對象能夠發現裏面包含有constructor屬性,因此constructor屬性的是prototype對象下的一個屬性,即:函數
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } console.log(foo.prototype.constructor == foo);//true
能夠看到原型對象下的constructor事指向當前構造函數的,函數在建立時就會自動生成constructor屬性來指向當前對象,實例化對象時constructor屬性也會一併繼承到新的對象下面。this
__proto__屬性當咱們經過new關鍵字構造函數實例化建立一個對象時,這個對象裏面含有__proto__屬性,__proto__屬性指向構造函數prototype屬性以及prototype屬性下面的對象。即:spa
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } var foo2 = new foo(); console.log(foo2.__proto__ == foo.prototype)//true console.log(foo2.__proto__)//Object {ccc:function(),constructor: foo()}
console.log(foo2.__proto__)在chrome裏的運行結果以下圖:prototype
能夠看到__proto__對象是等於foo.prototype對象的,而且foo.prototype對象下面的方法和屬性都已經在實例化對象foo2下的__proto__下面了。
js沒有其餘面向對象編程語言的多態的概念,因此如何實現多態的概念。這時,js提出了原型鏈的概念,經過原型鏈來實現擴展方法以及屬性的功能。看以下代碼
function foo(){ this.name = "John"; this.age = 23; var born = 1993; return this.age; } foo.prototype.ccc = function(){ console.log(this.name); } var foo2 = new foo(); foo2.ccc();//John var foo3 = new foo(); foo3.ccc();//John //修改foo3對象下面ccc方法 foo3.ccc = function(){ console.log(this.age); } foo3.ccc();//23
從上面代碼實例化對象時新的對象不只克隆了構造的函數屬性和方法,也克隆了構造函數原型下的屬性以及方法,在foo3對象中,當咱們沒有修改ccc方法時,函數會在當前對像下查找,沒查找到就會去原型對象裏查找該方法,在原型對象裏找到了ccc方法,打印出this.name爲「John」,當咱們重寫了ccc方法時,ccc方法就已經foo3當前對象下面了,因此在當前對象下面找到了ccc方法,運行ccc方法,而且中止查到,不會再繼續向下查,因此js原型鏈會遵循就近查找原則,若是查找不到當前方法會到原型下去查找,查找不到再去原型下面的原型去查找,直到查找到全部原型爲止。
咱們答應下foo3對象,console.log(foo3),在chrome運行結果以下圖:
能夠看出foo3對象下面擁有一個ccc方法,而且在原型對象下面也擁有一個ccc方法,遵循就近查找原則,會找到foo3對象下面的ccc方法,而不會去查到原型對象裏的ccc方法。因此經過js的原型鏈能夠修改對象的屬性和方法。