對象的聲明有倆種:前端
二者惟一的區別就是,字面量形式,能夠一次賦值多個,經過new Object就得一個一個賦值es6
數據類型函數
JS種7種數據類型this
簡單數據類型spa
複雜基本類型(內置對象,object子類型)雙向綁定
補充:null爲何是基本類型可是依然會出現,typeof null 會返回 object?這是一個語言的bug,原理以下:原理是這樣的,不一樣的對象在底層都表示爲二進制,在 JavaScript 中二進制前三位都爲 0 的話會被判
斷爲 object 類型,null 的二進制表示是全 0,天然前三位也是 0,因此執行 typeof 時會返回「object」。code
深刻對比基本類型和複雜類型的區別,用string和String對比對象
var str = 'hello world'; var strObj = new String('hello String'); str.length // 11 strObj.length // 12 // typeof判斷屬於那種簡單數據類型 typeof str; // "string" typeof strObj; //"object" // instanceof判斷對象實例的鼻祖是哪一個複雜類型 str instanceof String // false strObj instanceof String // true
這段代碼能夠分析出,str經過字面量形式聲明,其數據類型爲基本數據類型,並非對象,strObj 爲複雜數據類型String的實例。咱們知道str, strObj的數據類型以後,就要拋出一個問題,爲何str並非對象,它怎麼就能調用length呢?這不是一個簡單數據類型該有的呀。js向你丟出一個結論,那就是簡單數據類型存在一個隱式轉換,它會從簡單數據類型轉換爲複雜數據類型。blog
首先以對象字面量整一個對象ip
let obj = { name: 'hello', age: 12 }
訪問對象的屬性能夠經過 圓點運算符 相似於 obj.name, 還能夠經過屬性運算符 obj["name"]
訪問。
ES6 定義了Object.assign()方法實現淺複製,該方法第一個參數是目標對象,以後還能夠跟一個或多個原對象,他會遍歷一個或多個原對象全部可枚舉的自有鍵並把他們複製(使用 = 操做符賦值,因此這種僵硬的賦值操做,不會將原對象的屬性的特性複製過來)到目標對象,最後返回目標對象。
對象有本身的屬性和方法,對於咱們js對象的屬性來說,屬性還有本身的「屬性」,又稱爲屬性描述符。不要小看這個屬性描述符,可不得了,經過屬性描述符,咱們不只僅能夠配置屬性是讀寫權限,甚至經過setter,getter實現咱們的數據雙向綁定。該介紹一下這位調用屬性描述符的內置方法了:Object.defineProperty()
。這個方法接受三個參數,第一個是指定的對象,第二個是指定的對象參數,第三個固然是要修改的屬性描述符了。當對象中不存在指定的屬性,Object.defineProperty()
就建立這個屬性,當描述符中省略某些字段時,這些字段將使用它們的默認值,擁有布爾值的字段的默認值都是false
因此這也就是說,經過
Object.defineProperty()
建立的屬性,描述符是不可配置的,由於configurable:false
// 直接對一個對象使用原點運算符賦值,屬性描述符都是true var o = {}; o.a = 1; // 等同於 : Object.defineProperty(o, "a", { value : 1, writable : true, configurable : true, enumerable : true }); // 另外一方面,使用Object.defineProperty()卻將屬性修飾符關閉了 Object.defineProperty(o, "a", { value : 1 }); // 等同於 : Object.defineProperty(o, "a", { value : 1, writable : false, configurable : false, enumerable : false });
var obj = { name: 'hello', age: 12 } Object.defineProperty(obj, 'name', { value: 2, writable: true, configurable: true, enumerable: true }) obj.name; //2 not hello
接下來,咱們解釋一下屬性描述符的四大天王:value, writable, configurable, enumerable
爲啥先要介紹configurable
呢,不得不說說他的重要性,這個描述符的值是true/false,它表示屬性描述符是否可配置,當值爲false時,剩下的描述符都是不可配置的,修改也不會生效,不包括value。簡單的說,configurable控制的其餘描述符的命運!後面咱們討論的時候,默認configurable爲true,否則,討論也沒有意義,根本不會改變嘛
var a = { name: 'tom', age: 22 } Object.defineProperty(a, 'age', { enumerable: false, writable:false, configurable: false, }) a.age = 12; // a.age 爲12.即便writable 是false,由於configurable是false,因此writable其實仍是默認的true
我知道你確定是不信的,直接上圖。Object.getOwnPropertyDescriptor() 與Object.defineProperty()
互爲一對兒,一個定義,一個查看定義
並且,將configurable修改成false,這是一個單向操做,你想再次修改它的值爲true以實現從新配置屬性描述符是不可能的,一旦設置false,永遠都是false了。據說你還不信,那我再上圖
var myObject = { a:2 }; myObject.a = 3; myObject.a; // 3 Object.defineProperty( myObject, "a", { value: 4, writable: true, configurable: false, // 不可配置! enumerable: true } ); myObject.a; // 4 myObject.a = 5; myObject.a; // 5 Object.defineProperty( myObject, "a", { value: 6, writable: true, configurable: true, enumerable: true } ); // TypeError
咱們介紹一下控制讀寫的小夥伴-writable,這個屬性描述符控制咱們是否能夠對屬性進行賦值,值爲false時,賦值是無論用的。嚴格模式下,還會拋出錯誤。至於writable怎麼處理屬性是否能被賦值,留一個疑問,稍後立刻揭曉。
// configurable爲true var myObject = {}; Object.defineProperty( myObject, "a", { value: 2, writable: false, // 不可寫! configurable: true, enumerable: true } ); myObject.a = 3; myObject.a; // 2
這個屬性修飾符可能沒有那麼直觀,可是從字面來看,咱們應該是能瞭解到的,這是控制屬性是否能出如今對象可枚舉屬性中。若是將enumerable設置爲false,屬性就不會出如今可枚舉屬性中。enumerable定義了對象的屬性是否能夠在 for...in 循環和 Object.keys() 中被枚舉。
var obj = { name: 'tom', age: 12 } for(prop in obj) { console.log(prop); // name, age } Object.defineProperty(obj, 'name', { enumerable: false, }) for(prop in obj) { console.log(prop); //age }
補充一些可枚舉相關的知識,什麼叫可枚舉屬性,就是指那些屬性描述符設置爲enumerable爲true的屬性。有不少方法是基於可枚舉性的。好比,Object.keys(), in, for in 。對於上面那個例子,就是使用了for in遍歷obj對象可枚舉屬性。
writable:false 和 configurable:false
,就能夠建立一個一次賦值,不能修改的常量ES5可使用getter和setter部分改寫默認操做,可是隻能應用在單個屬性上,沒法應用在整個對象上,getter,setter都是隱藏函數,前者在獲取屬性值時自動調用,後者是在設置屬性值時自動調用。其實如今,咱們能夠總結一下前文所述。屬性描述符其實分爲兩種
而咱們前文一直在講述數據修飾符,那麼什麼是訪問修飾符呢?
當咱們給一個屬性定義getter和setter或者二者都有時,這個屬性會被定義爲」訪問描述符「,對於訪問描述符而言,JavaScript會忽略它們的value和writable特性,取而代之的是關心set/get(還有configurable和enumerable)特性
實例演示:
function Archiver() { var temperature = null; var archive = []; Object.defineProperty(this, 'temperature', { get: function() { console.log('get!'); return temperature; }, set: function(value) { temperature = value; archive.push({ val: temperature }); } }); this.getArchive = function() { return archive; }; } var arc = new Archiver(); arc.temperature; // 'get!' arc.temperature = 11; arc.temperature = 13; arc.getArchive(); // [{ val: 11 }, { val: 13 }]
一言以蔽之,setter/getter無非就是咱們在賦值或者讀取變量時,預先悄悄調用的一個隱藏方法。
還有一種經過對象文字語法建立的get,set(我也是從《你不知道的js》看到這種用法的,MDN這相關的文檔中我並無看到,學到了),這個不是經過Object.defineProperty()建立的,兩者都會在對象中建立一個不包含值的屬性,對於這個屬性的訪問會自動調用一個隱藏函數,它的返回值會被看成屬性訪問的返回值。
其實能夠更細緻的觀察到,經過對象文字語法建立的變量,他的修飾符按照規則確定是沒有value的,可是其餘配置信息是true,這一點很關鍵
大致上對象的內容就是這麼多,後續在作一個補充,MDN實在是前端寶典,看到這裏更推薦讀者閱讀MDN相關文檔:https://developer.mozilla.org...