對象的簡單認識

對象

對象其實能夠看作有許多鍵值對組合成的一個無序集合,能夠經過鍵倆訪問值。值通常由,基本數據類型 和 object 組合。javascript

對象的建立

有三種方式:java

1. new構造函數

  1. 使用new來建立一個對象
    var person = new Object();
    甚至能夠簡寫成爲: var person = new Object;json

  2. Object參數若是是一個對象,則直接返回對象自己
var o = { a : 1};
var p = new Object(o);
alert(o === p); // true
  1. 傳入原始數據類型,則返回包裝對象
var o1 = new Object("123");
console.log(o1); // String{0:"1",1:"2",2:"3",length:3,__proto__: String, [[PrimitiveValue]]: "123"}

var o2 = new Object(123);
console.log(o2) // Number{123, __proto__: Number, [[PrimitiveValue]]: 123} 

var o3 = new Object(true);
console.log(o3)
// Boolean {__proto__: Boolean, [[PrimitiveValue]]: true}

// ------------ 下面是空對象 和不傳參數同樣。
var o4 = new Object(null)
console.log(o4) // Object{__proto__: Object}

var o5 = new Object(undefined)
console.log(o5) // Object{__proto__: Object}

var o6 = new Object()
console.log(o6) // Object{__proto__: Object}

2. 對象字面量

這是咱們 最熟悉的一種,也是常用的一種,其實使用字面量只是隱藏了與使用new操做符相同的基本過程,因而也能夠叫作語法糖。
簡單示例:數組

var person = {
    age : 24,
    name: 'xiaoming',
    1: true,  
}

注意,使用對象字面量方法來定義對象的時候,屬性名會自動轉化爲字符串。
就是上面示例,自動變成下面的。函數

var person = {
    'age' : 24,
    'name': 'xiaoming',
    '1': true,  
}

Object.create()

ES5定義了一個名爲Object.create()的方法,它建立一個新對象,第一個參數就是這個對象的原型,第二個可選參數用以對對象的屬性進行進一步描述this

var o = Object({a:1})
console.log(o) // Object{a:1,__proto__:object}

注意:傳入參數null來建立一個沒有原型的新對象prototype

var o1 = Object.create(null); 

var o2 = {};

此時o1不會繼承任何東西,甚至不包括基礎方法。好比toString()和valueOf()。
若是想要建立一個普通的空對象(例如,經過{}或new Object()建立的對象),須要傳入Object.prototype, 這就是由於,這個函數的第一個參數就是原型對象。code

var o3 = Object.create(Object.prototype);
var o4 = {};

對象的引用

若是不一樣的變量名指向同一個對象,那麼它們都是這個對象的引用,也就是說指向同一個內存地址。修改其中一個變量,會影響到其餘全部變量。對象

var o = {
    a:1,
}

var p = o;
console.log(p.a)  // 1

p.a = 0;
console.log(o.a) // 0

對象的屬性

對象的屬相操做,有兩種 [] 和 點號(.)。
點號(.), 在使用的時候,屬性名必須符合標識符的命名規則。
不存在的屬性取值返回undefined。繼承

var o = {
    a : 0,
    1 : true,
}

o.b = 1;  // 能夠增長屬性,並賦值
console.log(o.a) // 能夠取值操做
console.log(o.1) // 報錯
console.log(o.b)  // undefined  不存在的變量
o.a = 2;  // 能夠賦值操做
console.log(o.a);

[] 方括號中的值, 如果字符串,則直接訪問。 若是非字符串類型且不符合標識符命名,則轉成字符串訪問,若是非字符串類型且符合標識符命名,則須要識別變量的值,變量未定義,則報錯。
在[] 訪問屬性的時候 是能夠計算屬性的

var c = 1;
var o = {}

console.log(o[0]) // undefined   o[0] --> o['0'] 訪問。
console.log(o[a]) // 報錯,a符合變量的命名規則,a未被定義,而報錯

console.log(o['a']) // undefined    o['a'] 訪問。
console.log(o[null]) // undefined , o[null] --> o['null']訪問

console.log(o[c + 1]) // undefined  o[c+1] --> o['4']訪問

注意 null和undefined不是對象,給它們設置屬性會報錯

屬性的刪除

使用delete運算符能夠刪除對象屬性(包括數組元素)。
delete是有返回值的,刪除成功則返回true,刪除不存在的屬性或非左值時,返回false。當使用delete操做符刪除不可配置的屬性時,返回false,嚴格模式下會拋出TypeError錯誤
將屬性賦值爲 null 和undefined 只是修改了屬性的值。

var o = {
    a:1
}
console.log(delete o.a);//true
console.log(o.a);//undefined
console.log('a' in o);//false   in 操做符 能夠判斷對象是否具備該屬性,可是沒法判斷是不是繼承來的

使用delete刪除數組元素時,不會改變數組長度

var a = [1,2,3];
delete a[2];
2 in a;//false
a.length;//3

屬性的檢測

每個javascript對象都和另外一個對象相關聯。「另外一個對象」就是咱們熟知的原型對象,每個對象都會從原型對象繼承屬性。
對象自己具備的屬性叫自有屬性,從原型對象繼承而來的屬性叫繼承屬性

in: in操做符能夠判斷對象是否可使用某一屬性,但沒法區別自有仍是繼承屬性
for-in: for-in循環能夠遍歷出該對象中全部可枚舉屬性
hasOwnProperty(): 能夠肯定該屬性是自有屬性仍是繼承屬性
Object.keys(): 返回全部可枚舉的自有屬性
Object.getOwnPropertyNames(): Object.keys()方法不一樣,Object.getOwnPropertyNames()方法返回全部自有屬性(包括不可枚舉的屬性)

屬性描述符

對象屬性描述符分爲, 數據屬性 訪問器屬性

數據屬性

數據屬性(data property)包含一個數據值的位置,在這個位置能夠讀取和寫入值。

  1. 可配置configuable
    • 可配置性決定是否可使用delete刪除屬性,以及是否能夠修改屬性描述符的特性,默認值爲true
    var o = {a:1};
    Object.defineProperty(o,'a',{
        configurable:false,
    });
    delete o.a; //false   嚴格模式下報錯
    console.log(o.a);//1
    • 設置Configurable:false後,將沒法再使用defineProperty()方法來修改屬性描述符
    var o = {a:1};
    Object.defineProperty(o,'a',{
        configurable:false
    });
    // 報錯不能修改屬性
    Object.defineProperty(o,'a',{
        configurable:true
    });
    • writable的狀態 只能是從true變爲false
  2. 可枚舉enumerable
    可枚舉性決定屬性是否出如今對象的屬性枚舉中,具體來講,for-in循環、Object.keys方法、JSON.stringify方法是否會取到該屬性。
    var o = {a:1}; Object.defineProperty(o,'a',{enumerable:false}); for(var i in o){ console.log(o[i]);//undefined }

  3. 可寫性writable
    可寫性決定是否能夠修改屬性的值,默認值爲true
    var o = {a:1}; Object.defineProperty(o,'a',{ writable:false }); console.log(o.a);//1 o.a = 2;//因爲設置writable爲false,因此o.a=2這個語句會默認失效,嚴格模式會報錯 console.log(o.a);//1
  4. 屬性值value
    屬性值包含這個屬性的數據值,讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置。默認值爲undefined

訪問器屬性

訪問器屬性不包含數據值;它們包含一對兒getter和setter函數(不過,這兩個函數都不是必需的)。在讀取訪問器屬性時,會調用 getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數並傳入新值,這個函數負責決定如何處理數據。

  1. 可配置性Configurable
      表示可否經過 delete 刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認值爲 true
  2. 可枚舉性Enumerable
    可枚舉性決定屬性是否出如今對象的屬性枚舉中,好比是否能夠經過for-in循環返回該屬性,默認值爲true
  3. getter 讀
      在讀取屬性時調用的函數。默認值爲undefined
  4. setter 寫
      在寫入屬性時調用的函數。默認值爲undefined
      和數據屬性不一樣,訪問器屬性不具備可寫性(Writable)。若是屬性同時具備getter和setter方法,那麼它是一個讀/寫屬性。若是它只有getter方法,那麼它是一個只讀屬性。若是它只有setter方法,那麼它是一個只寫屬性。讀取只寫屬性老是返回undefined

get是一個隱藏函數,在獲取屬性值時調用。set也是一個隱藏函數,在設置屬性值時調用,它們的默認值都是undefined。Object.definedProperty()中的get和set對應於對象字面量中get和set方法
[注意]getter和setter取代了數據屬性中的value和writable屬性
一般這裏的get和set是用來 攔截數據訪問和修改的。

var o = {
    get a(){
        return 0;
    }
}

console.log(o.a)  // 0
o.a = 1 // 沒有set方法, 默認失效
console.log(o.a)  // 0
// ---------------------------------------
Object.defineProperty(o,'b',{
    get: function(){
        return 2;
    }
})
console.log(o.b);//2
//因爲沒有設置set方法,因此o.a=3的賦值語句會靜默失敗
o.b = 1;
console.log(o.b);//2

只有set

var o = {}
Object.defineProperty(o,'a',{
    set: function(){
        return 0;
    }
})
o.a = 1;
console.log(o.a);//undefined

一般狀況下 get 和set是成對出現的, 而且你會發現,這樣作,咱們還須要空間來存儲值。 這也是數據屬性的不一樣之處吧。

var o = {};
Object.defineProperty(o,'a',{
    get: function(){
        return this._a;
    },
    set :function(val){
        this._a = val*2;
    }
})
o.a = 1;
console.log(o.a);//2

對象屬性的獲取和設置

  1. Object.getOwnPropertyDescriptor(對象,屬性名)
    查看對象的屬性,返回一個對象,包含了屬性的特性。,當查看不存在的屬性時,返回undefined。 而且只適用於自身的屬性。
var o = {a : 0};
// Object {value: 0, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
// undefined
console.log(Object.getOwnPropertyDescriptor(o,'b'));
  1. Object.defineProperty(對象,屬性名, 屬性描述)
    返回配置後的對象。
    使用該方法建立或配置對象屬性的描述符時,若是不針對該屬性進行描述符的配置,則該項描述符默認爲false
var o = {};
Object.defineProperty(o,'a',{
        value: 0,
        writable: true,
        enumerable: true,
    });
// /{value: 1, writable: true, enumerable: true, configurable: false}     沒有配置因爲沒有配置configurable,因此它的值爲false
console.log(Object.getOwnPropertyDescriptor(o,'a'))
  1. Object.defineProperties(o, 屬相描述)
    用於建立或配置對象的多個屬性的描述符,返回配置後的對象。
var o = {
    a : 1,
}

Object.defineProperties(o,{
    a:{enumerable:false},
    b:{value:2}
})

//{value: 1, writable: true, enumerable: false, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
//{value: 2, writable: false, enumerable: false, configurable: false}
console.log(Object.getOwnPropertyDescriptor(o,'b'));
  1. Object.create(原型對象,描述)
    使用指定的原型和屬性來建立一個對象。
var o = Object.create(Object.property,{
    a:{
        value: 0,
        writable: false,
        enumerable: true,
    },
    b{
        value: 1,
    }
})
//{value: 0, writable: false, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj,'a'));
// {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj,'b'))

對象的拷貝

淺拷貝

使用for-in將對象的全部屬性複製到新建的空對象中,並將器返回

function simpleClone(o,cloneObj){
    // 判斷參數
    for(var i in obj){
        cloneObj[i] = obj[i];
    }
    return cloneObj;
}

使用屬性描述符

function simpleClone(o){
    // 判斷參數
    var cloneObj = Object.create(Object.getPrototypeOf(o)); // 根據o對象的原型對象,建立新對象。
    // 獲取自身屬性並迭代。 
    Object.getOwnPropertyNames(o).forEach(function(propKey){
        // 根據自身屬性名 獲取屬相描述。
        var desc = Object.getOwnPropertyDescriptor(o,propKey);
        // 給克隆對象設置 屬性描述
        Object.defineProperty(cloneObj,propKey,desc);
    });
    return cloneObj;
}

深拷貝

複製對象的屬性時,對其進行判斷,若是是數組或對象,則再次調用拷貝函數;不然,直接複製對象屬性

function deepClone(o,cloneObj){
    if(typeof o != 'object'){
        return false;
    }
    var cloneObj = cloneObj || {};  // 保證cloneObj不是null和undefined

    for(var i in o){
        if(typeof o[i] === 'object'){ // 是對象繼續遞歸拷貝
            cloneObj[i] = (o[i] instanceof Array) ? [] : {};
            arguments.callee(o[i],cloneObj[i]);
        }else{
            cloneObj[i] = o[i];
        }
    }

}

使用 json.
先是對象轉成字符串,而後在轉成對象返回。

function jsonDeepClone(o){
    return JSON.parse(JSON.string(o))
}
相關文章
相關標籤/搜索