在JavaScript中建立一個對象有三種方式。能夠經過對象直接量、關鍵字new和Object.create()函數來建立對象。javascript
建立對象最直接的方式就是在JavaScript代碼中使用對象直接量。在ES5中對象直接量是由若干 名/值
組成的映射表, 整個映射表由{}
包含起來。每一個名/值中間使用:
進行分割,名/值之間使用,
進行分割。java
var o1 = {}; var o2 = {name: 'javascript'} var o3 = {title: 'object', o2: o2} // 數組、日期、函數、正則等做爲特殊的對象,這裏暫不討論 // ES6 也暫時不討論
上面就是使用對象直接量建立對象,這種方式比較簡單方便。數組
經過關鍵字new + 函數調用,就能夠建立一個新的對象。被調用的函數被稱爲構造函數。 根據高程
中描述,使用 new + 調用函數 建立一個對象,這種方式會經歷如下 4 個步驟:數據結構
(1) 建立一個新對象;
(2) 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象);
(3) 執行構造函數中的代碼(爲這個新對象添加屬性);
(4) 返回新對象。函數
舉個例子:測試
var Foo = function(name) { this.name = name } var foo = new Foo('我'); /* var foo = new Foo('我') 建立對象大體的流程是 (1) var obj = {}; `高程`中步驟(2),(3)若是不清楚的小夥伴,能夠參考下面的實現 (2)、(3) Foo.call(obj); call 方法可以改變函數Foo的執行上下,把this指向obj,而後執行Foo函數 (4) foo = obj; */ typeof foo; // "object" foo.constructor === Foo // true
這裏是ES5官方提供的一個建立對象的方法。this
var obj = {name: 'javascript'}; var newObj = Object.create(obj); newObj.name // => javascript
JS中每一個函數均可以當作一個對象,而原型(prototype)就是函數中的其中一個屬性。這裏要很清楚,原型是函數上面的一個屬性,這個屬性只有函數對象才能擁有,別的類型是沒有prototype屬性。而原型的做用就是它所引用的對象可以被擁有它的函數所構建的實例化對象所訪問。 spa
那麼原型是怎麼和對象創建聯繫的?prototype
編寫代碼以下:設計
let obj = {name: 'javascript'}; console.log(obj.name) // => javascript console.log(obj)
控制檯輸出以下:
咱們在程序中定義一個JavaScript對象,而後打印這個對象,這裏除了前面定義的name
屬性外,還有另一個__proto__
屬性。前面說道 函數 上面的 prototype(原型)所指向的對象可以擁有它的函數所構建的實例化對象所訪問。至於具體怎麼訪問的細節沒有說明。其實就是經過__proto__
這個屬性做爲橋樑進行的聯接。
let obj = {name: 'javascript'}; console.log(obj.__proto__ === Object.prototype) //true
對比發現__proto__
所指的對象和Object.prototype所指的是同樣的。咱們是能夠認定__proto__就是這座橋樑,那麼obj就能訪問到Object.prototype所指的對象就是理所固然了。
因而我就在猜想在使用直接定義量去定義對象的時候,在底層的實現頗有可能就是經過new Object()的這種方式實現的。
因而我編寫了下面的測試代碼:
let obj = {name: 'javascript'}; let obj1 = new Object({name: 'javascript'});
發現上面的obj與obj1二者數據結構基本一致。
原型對象簡單來講就是函數的原型所指向的對象。前面說原型的時候,說了Object.prototype所指對象就是Object(函數)的原型對象。 在每一個函數的原型對象中,默認會有constructor屬性,用於指向函數自己。
Object.prototype.constructor === Object // true let Test = function() {console.log('test')}; Test.prototype.constructor === Test // true
在最開始的時候,原型對象的constructor設計主要是爲了獲取對象
的構造函數。後來發現constructor屬性易變,不可信。推薦使用instanceof。
var Test = function() {console.log('test')}; var test = new Test(); console.log(test.constructor); // Test test.constructor = Object; console.log(test.constructor); // Object /*這裏想使用 test.constructor 來判斷是不是Test的實例化對象就不可信。而應該使用 instanceof */ test instanceof Test // true
原型對象有什麼做用,主要實現對象的繼承。
當咱們使用變量直接量定義一個對象的時候,其實咱們是沒有定義它上面的這些可以調用的方法
let obj = {};
這些方法怎麼來的,就是經過調用Object上面的原型對象而來的。
console.log(Object.prototype)
同理數組(經過調用Array.prototype),函數(經過調用Function.prototype)
ECMAScript中描述了原型鏈的概念,並將原型鏈做爲實現繼承的主要方法。其基本思想是利用原 型讓一個引用類型繼承另外一個引用類型的屬性和方法。簡單回顧一下構造函數、原型和實例的關係:每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。那麼,假如咱們讓原型對象等於另外一個類型的實例,結果會怎麼樣呢?顯然,此時的 原型對象將包含一個指向另外一個原型的指針,相應地,另外一個原型中也包含着一個指向另外一個構造函數 的指針。假如另外一個原型又是另外一個類型的實例,那麼上述關係依然成立,如此層層遞進,就構成了實 例與原型的鏈條。這就是所謂原型鏈的基本概念。