Javascript之對象

1、建立對象

建立對象有兩種方法:1,聲明形式;2,構造形式。javascript

//聲明形式
let obj = {
    a:2,
    ...
}
//構造形式
let obj = new Object();
obj.a = 2;
...
複製代碼

2、一個bug

js中有6中數據類型:string,number,boolean,null,undefined,object,簡單數據類型string,number,boolean,null,undefined自己並非對象,可是null有時會被當作對象,但這是js語言的一個bug,即在執行typeof null時會返回object,實際上null是基本數據類型。其原理是,不一樣的對象在底層都是用二進制來表示的,在javascript中二進制前三位爲0就表示是對象,null的二進制表示是全0,即前三位都是0,因此執行typrof null時返回objectjava

3、內置對象

js中有一些對象子類型,稱爲內置對象:String,Number,Boolean,Object,Function,Array,Date,RegExp,Error。在必要時語言會把基本數據類型隱式的轉換成其對應的構造形式。 null 和 undefined沒有對應的構造形式,只有文字形式,Date沒有文字形式,只有構造形式。es6

4、內容訪問

訪問對象的屬性能夠有兩種方式:1,.a語法一般叫作「屬性訪問」;2,['a']語法一般叫作「鍵訪問」。主要區別在於.操做符須要屬性名知足標識符的命名規範,[..]操做符能夠接受任意的字符串。 在ES6中新增長了計算屬性,能夠在聲明形式中使用[]包裹一個表達式表示一個屬性名:數組

let pre = 'pre';
let obj = {
    [per + 'foo']:'foo',
    [per + 'baz']: 'baz'
}
obj['prefoo'];//'foo'
obj['prebaz'];//'baz'
複製代碼

5、數組的屬性

你能夠向數組中添加屬性,添加的屬性不會修改數組的長度,而且能夠正常的訪問它。bash

let arr = [2,3,4];
arr.foo = 'foo';
arr.length;// 3
arr.foo;// 'foo'
複製代碼

可是若是你向數組添加一個「看起來」像數字的屬性,那它會變成一個數值下標,從而改變數值而不是成爲數值的屬性。ui

let arr = [2,3,4];
arr['3'] = 'foo';
arr.length;// 4
arr[3];// 'foo'
複製代碼

6、對象的複製

js語言自己並無提供內置的深拷貝方法,可是有一種巧妙的運用JSON的方法能夠實現對象的深拷貝:this

let newObj = JSON.parse(JSON.stringify(obj))
複製代碼

ES6提供了對象的淺拷貝方法:Object,assign(),Object.assign()方法第一個參數爲目標對象,後面跟一個或多個源對象,遍歷源對象中因此可枚舉的屬性添加到目標對象,而且返回目標對象。Object.assign()使用的是=操做符來複制,因此並不會複製屬性的一些特性(好比writable)。spa

7、屬性描述符

對象的每個屬性有三個特性:writable(決定是否能夠修改屬性的值),enumerable(是否可枚舉),configurable(是否可配置),當咱們建立一個屬性時都會使用特性的默認值,即都爲true,咱們可使用Object.defineProperty()來新建一個屬性或者修改一個已存在屬性的特性。prototype

let obj = {};
Object.defineProperty(obj,'a',{
    value:'foo',
    writable:true,
    enumerable:true,
    configurable:true,
});
obj.a;// 'foo'
複製代碼

configurable設置爲false時,除了沒法修改,還會禁止刪除該屬性。code

1,建立一個常量屬性: 將一個對象的writableconfigurable都設置爲false,就能夠建立一個真正的常量屬性,不可修改,不可設置,不可刪除。

2,禁止擴展: 若是要禁止一個對象添加新的屬性而且保留已有的屬性,可使用Object.preventExtensions()

lat obj = {
    a:'foo',
}
Object.preventExtensions(obj);
obj.b = 'baz';
obj.b;// undefined
複製代碼

在非嚴格模式下建立屬性b默認失敗,在嚴格模式下會拋出TypeError錯誤。

3,密封:Object.seal()會建立一個密封的對象,該方法其實是在一個對象上調用Object.preventExtensions()方法,而且把因此屬性標記爲configurable:false,使得對象不能添加新屬性,不能配置,不能刪除任何屬性。

4,凍結:object.freeze()會建立一個凍結對象,該方法實際是在對象上調用Object.seal(),並把屬性標記爲writable:false,使得對象不可新增屬性,不可刪除屬性,屬性不可配置,屬性不可修改。

8、Get和Put

當咱們訪問對象的屬性時,其實是在調用對象默認的Get方法,Get如今對象的屬性上查找是否有該屬性,若是有就返回;若是沒有就遍歷其可能存在的[prototype]鏈;若是不管如何都找不到就返回undefined

當給對象賦值時會觸發Put,若是這個屬性已經存在啦:1,首先判斷屬性是不是訪問描述符(定義了getter,setter或者二者都有),若是存在setter就調用setter;2,屬性的數據描述符中writable是否爲false,是的話嚴格模式下拋出TypeError錯誤,非嚴格模式下靜默失敗。3,若是都不是將該值設爲屬性的值。

注:當給一個屬性設置getter、setter或者二者都有時,這個屬性會被定義爲‘訪問描述符‘’,和‘數據描述符’相對。對於訪問描述符,js會忽略它的valuewritable特性,會關心它的set和get還有configurable和enumerable

9、存在性

檢查對象中是否存在一個屬性可使用in操做符,或者使用hasOwnProperty()方法。in操做符會檢查對象的屬性和它的[prototype]鏈;hasOwnProperty()只會檢測對象的屬性列表。

Object.keys()會返回包含全部可枚舉的屬性的數組;Object.getOwnPropertyNames()返回包含全部屬性的數組,不管是否可枚舉。

10、遍歷

es6新增了for..of循環,for...of循環首先會向被訪問的對象請求一個迭代器對象,而後經過調用迭代器對象的next()方法來遍歷因此返回值。數組有內置的@@iterator,所以for...of循環能夠直接做用在數組上。

let arr = [1,2,3];
for(let v of arr){
    console.log(v);
}
//1,2,3
複製代碼

若是想用for...of遍歷對象的屬性值,咱們須要在對象上定義@@iterator:

let obj = {
    a:2,
    b:3,
}
Object.defineProperty(obj,Symbol.iterator,{
    enumerable:false,
    writable:false,
    configurable:true,
    value:function(){
        let o = this;
        let keys = 0;
        let k = Object.keys(o);
        return {
            next:function(){
                return {
                    value:o[k[keys++]],
                    done:keys > k.length
                }
            }
        }
    }
})
//手動遍歷
let it = obj[Symbol.iterator]();
it.next();//{value:2,done:false}
it.next();//{value:3,done:false}
it.next();//{value:undefined,done:true}
//使用for...of遍歷
for(let v of obj){
    console.log(v);
}
//2 3
複製代碼
相關文章
相關標籤/搜索