Object中的方法

1. Object.assign(target, ...sources);

方法用於將全部可枚舉屬性的值從一個或多個源對象複製到目標對象。返回目標對象數組

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3, [Symbol()]: 'd' };

Object.assign(target, source1, source2);  // {a: 1, b: 2, c: 3, Symbol(): "d"} 後面屬性會覆蓋前面同名屬性值

Object.assign方法實行的是淺拷貝,而不是深拷貝。
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
console.log(obj2.a.b) //2
obj2.a.b = 3
console.log(obj1.a.b) //3

# 特殊狀況:
let obj = {a: 1};
Object.assign(obj, undefined) === obj  // truesource爲null undefined,會忽略該參數
Object.assign(obj) === obj // true  只有一個參數,直接返回該參數
Object.assign([1, 2, 3], [4, 5])        // [4, 5, 3] 數組下標被做爲了key處理
Object.assign(null, obj) // TypeError  undefined和null放在首位報錯,非首位不報錯直接忽略

# 繼承屬性和不可枚舉屬性是不能拷貝的
const obj = Object.create({foo: 1}, { // foo 是個繼承屬性。
    bar: {
        value: 2  // bar 是個不可枚舉屬性。
    },
    baz: {
        value: 3,
        enumerable: true  // baz 是個自身可枚舉屬性。
    }
});

const copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

# 異常會打斷後續拷貝任務
const target = Object.defineProperty({}, "foo", {
    value: 1,
    writable: false
}); // target 的 foo 屬性是個只讀屬性。

Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意這個異常是在拷貝第二個源對象的第二個屬性時發生的。

console.log(target.bar);  // 2,說明第一個源對象拷貝成功了。
console.log(target.foo2); // 3,說明第二個源對象的第一個屬性也拷貝成功了。
console.log(target.foo);  // 1,只讀屬性不能被覆蓋,因此第二個源對象的第二個屬性拷貝失敗了。
console.log(target.foo3); // undefined,異常以後 assign 方法就退出了,第三個屬性是不會被拷貝到的。
console.log(target.baz);  // undefined,第三個源對象更是不會被拷貝到的。

注:
    1. 淺拷貝源對象自身且可枚舉的屬性(包含Symbol)到目標對象
    2. 後面屬性會覆蓋前面同名屬性值
    3. 繼承屬性和不可枚舉屬性是不能拷貝的,拷貝 symbol 類型的屬性
    4. 異常會打斷後續拷貝任務
複製代碼

2. Object.create(proto, [propertiesObject]); 建立一個新對象

  1. proto 新建立對象的原型對象。
  2. propertiesObject 可選。若是沒有指定爲 undefined,要添加到新建立對象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應的屬性名稱。這些屬性對應Object.defineProperties()的第二個參數。
# 若是propertiesObject參數是 null 或非原始包裝對象,則拋出一個 TypeError 異常。
const obj = Object.create({a:1}, {b: {value: 2}})
obj.__proto__.a === 1      // true 繼承原型 
obj.b = 3;
console.log(obj.b)      // 2 自身屬性

//建立一個可寫的,可枚舉的,可配置的屬性p
obj2 = Object.create({}, {
  p: {  // p 會成爲所建立對象的數據屬性
    value: 2,       // 屬性值
    writable: true,     //  是否能夠重寫值
    enumerable: true,   //是否可枚舉
    configurable: true  //是否能夠修改以上幾項配置
  }
});

obj2.p = 3;
console.log(obj2.p)     // 3

注意: enumerable 會影響如下
forin  遍歷包括對象原型上屬性
Object.keys()   只能遍歷自身屬性
JSON.stringify  只能序列化自身屬性
複製代碼

3. Object.defineProperties(obj, props);

在一個對象上定義新的屬性或修改現有屬性,並返回該對象。bash

var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    get: function() { return property2 },
    set: function(value) { property2 = value }
  }
  // etc. etc.
});
複製代碼

4. Object.defineProperty(obj, prop, descriptor)

在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。函數

添加數據屬性
var obj = {};

// 1.添加一個數據屬性
Object.defineProperty(obj, "newDataProperty", {
    value: 101,
    writable: true,
    enumerable: true,
    configurable: true
});

obj.newDataProperty    // 101
// 2.修改數據屬性
Object.defineProperty(obj, "newDataProperty", {
    writable:false
});

//添加訪問器屬性
var obj = {};
Object.defineProperty(obj, "newAccessorProperty", {
    set: function (x) {
        this.otherProperty = x;
    },
    get: function () {
        return this.otherProperty;
    },
    enumerable: true,
    configurable: true
});

注意:  1.第一個參數必須爲對象
        2.descriptor 不能同時具備 (value/ writable 特性)(get/ set 特性)。
        3.configurable 爲false 時,不能從新修改裝飾器, 同時該屬性也能從對應的對象上被刪除
複製代碼

5. Object.entries(obj)

返回一個給定對象自身可枚舉(不含繼承 / Symbol / enumerable: false)屬性的鍵值對數組測試

console.log(Object.entries({[Symbol()]: 123, foo: 'abc'})); // [ ['foo', 'abc']]

//  string
Object.entries('abc')   // [['0', 'a'], ['1', 'b'], ['2', 'c']]
Object.entries(100)   // []
複製代碼

6. Object.values(obj)

返回自身(不含繼承 / Symbol / enumerable: false)可枚舉屬性值數組ui

let arr = ["a", "b", "c"];
let obj = { foo: "bar", baz: 42 };

Object.values(arr)      // ["a", "b", "c"]
Object.values(obj)      // ["bar",42]
複製代碼

7. Object.keys(obj)

返回自身可枚舉屬性(不含繼承 / Symbol屬性 / enumerable: false) 數組this

console.log(Object.keys({[Symbol()]: 123, foo: 'abc', baz: 42 })); // [ ['foo', 'baz']]
複製代碼

8. Object.freeze(obj)

凍結一個對象 &Object.isFrozen(obj) 判斷一個對象是否已經被凍結spa

凍結對象是指那些不能添加新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性的對象。也就是說,這個對象永遠是不可變的。

1.先講freeze 方法:
let o3 = {a: 1}

o3.b = 2      //添加屬性b成功
Object.freeze(o3)
Object.isFrozen(o3)    //true 對象已被凍結

o3.a = 2       //修改屬性a值失敗
o3.c = 5       //添加屬性c失敗
delete o3.b   //刪除屬性b失敗

const obj1 = { a:1 };
const obj2 = Object.freeze(obj1);
obj1 === obj2; // 返回原來的對象
Object.isExtensible(obj2);  // false
Object.getOwnPropertyDescriptor(obj2,'a'); 
// {value: 1, writable: false, enumerable: true, configurable: false}

總結:
    1.凍結對象的全部自身屬性都不可能以任何方式被修改。但能夠改變原型上的屬性。
    2.任未嘗試修改該對象的操做都會失敗,多是靜默失敗,也可能會拋出異常(嚴格模式中)。
    3.數據屬性的值不可更改,訪問器屬性(有getter和setter)也一樣(但因爲是函數調用,給人的錯覺是仍是能夠修改這個屬性)。
    4.若是一個屬性的值是個對象,則這個對象中的屬性是能夠修改的,除非它也是個凍結對象。
    
Object.freeze作了三件事情,
 (1)給對象設置,Object.preventExtension(obj1), 禁止更改原型,禁止添加屬性,
 (2)爲對象的每個屬性設置,writable:false, 禁止更改屬性值,
 (3)爲對象的每個屬性設置,configurable:false。禁止刪除屬性.
注:
禁止添加屬性,是Object.preventExtensions控制的,而禁止刪除屬性,是configuable:false控制的。
    
淺凍結與深凍結:
(function () {
    obj = {
        internal :{}
    };
    Object.freeze(obj);//淺凍結
    obj.internal.a = "aValue";
    console.log(obj.internal.a);//"aValue"

    //想讓一個對象變得徹底凍結,凍結全部對象中的對象,可使用下面的函數.
    function deepFreeze(o){
        var prop,propKey;
        Object.freeze(o);//首先凍結第一層對象
        for(propKey in o){
            prop = o[propKey];
            if(!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)){
                continue;
            }
            deepFreeze(prop);//遞歸
        }
    }

    deepFreeze(obj);
    obj.internal.b = "bValue";//靜默失敗
    console.log(obj.internal.b);//undefined
})();

複製代碼

9. Object.getOwnPropertyDescriptor(obj, prop)

獲取該屬性的描述對象,包含 不可列舉/ Symbolprototype

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')

//  { value: 123, writable: true, enumerable: true, configurable: true }
複製代碼

10. Object.getOwnPropertyDescriptors(obj)

返回指定對象全部自身屬性(非繼承屬性)的描述對象,包含 不可列舉/ Symbol指針

const obj = {
  foo: 123,
  get bar() { return 'abc' }
};
 
console.dir(Object.getOwnPropertyDescriptors(obj))
//   { foo: { value: 123,
//            writable: true,
//            enumerable: true,
//            configurable: true },
//     bar:{ get: [Function: bar],
//           set: undefined,
//           enumerable: true,
//           configurable: true } 
//     }


使用場景:
Object.assign() 方法只能拷貝源對象的可枚舉的自身屬性,同時拷貝時沒法拷貝屬性的特性,並且訪問器屬性會被轉換成數據屬性,也沒法拷貝源對象的原型

Object.create() 方法能夠實現上面說的這些,配合getPrototypeOf,以及getOwnPropertyDescriptors實現全面淺拷貝

Object.create(
  Object.getPrototypeOf(obj), 
  Object.getOwnPropertyDescriptors(obj) 
);

複製代碼

11. Object.getOwnPropertyNames(obj)

與keys類似,但包含遍歷包含自身不可枚舉屬性,不包含Symbol屬性code

var my_obj = Object.create({}, {
  [Symbol('name')]: { value: 'chup'},
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

my_obj.foo = 1;
Object.getOwnPropertyNames(my_obj).sort()
複製代碼

12. Object.getOwnPropertySymbols(obj)

返回對象自身的全部 Symbol 屬性的數組

var obj = {};
obj[Symbol("a")] = "localSymbol";
obj[Symbol.for("b")] = "globalSymbol";
var objectSymbols = Object.getOwnPropertySymbols(obj);

console.log(objectSymbols.length); // 2
console.log(objectSymbols)         // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0])      // Symbol(a)
複製代碼

13. Object.getPrototypeOf(obj)

獲取指定對象的原型

const prototype1 = {};
const object1 = Object.create(prototype1);

console.log(Object.getPrototypeOf(object1) === prototype1);   // true
複製代碼

14. Object.is()

比較兩個值是否嚴格相等,與嚴格比較運算符(===)的行爲基本一致

Object.is('foo', 'foo')     // true
Object.is({}, {})           // false

不一樣於 === 之處
+0 === -0                   //true
NaN === NaN                     // false

Object.is(+0, -0)           // false
Object.is(NaN, NaN)         // true
複製代碼

15. Object.isExtensible(obj)

判斷一個對象是否可擴展

let empty = {}
Object.isExtensible(empty)    //true
Object.preventExtensions(empty)  //將對象變爲不可拓展
Object.isExtensible(empty)    //false
複製代碼

16. Object.isFrozen(obj)

判斷一個對象是否被凍結

let o = {a: 1}
console.log(Object.isFrozen(o))  // false
Object.freeze(o)
console.log(Object.isFrozen(o))  // true
複製代碼

17. Object.isSealed(obj)

判斷一個對象是否爲密封的

18. Object.preventExtensions(obj)

**讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性&isExtensible 判斷一個對象是否可擴展, **

let empty = {}

Object.isExtensible(empty)    //true
empty.a = 1             //添加成功

Object.preventExtensions(empty) //將對象變爲不可拓展
Object.isExtensible(empty)    //false

empty.b = 2         //靜默失敗,不拋出錯誤
empty.a = 5         //修改a屬性值爲5  修改爲功

// 一個不可擴展對象的原型是不可更改的,__proto__是個非標準魔法屬性,能夠更改一個對象的原型.
var fixed = Object.preventExtensions({});
fixed.__proto__ = { oh: "hai" }; // 拋出TypeError異常
fixed.__proto__.oh = 'hai' // fixed.oh ->  hai

總結:
    1.preventExtensions 該對象變的不可擴展,也就是不能填自身新的屬性。
    2.不可擴展對象的屬性一般仍然能夠被刪除。
    3.Object.preventExtensions 只能阻止自身屬性不能再新增,仍然可在原型上添加屬性。
    4.嘗試給一個不可擴展對象添加新屬性的操做將會失敗,不過多是靜默失敗,也可能會拋出 TypeError 異常(嚴格模式)。
複製代碼

19. Object.prototype.hasOwnProperty()

返回一個布爾值,判斷對象自身屬性(含Symbol / 不可列舉)中是否具備指定的屬性(不含繼承屬性)

let o = {}
Object.defineProperties(o,{
	[Symbol.for('a')]: { value: 'a'},
    b: {value: 'b', enumerable: false},
    c: {value: 'c'}
})
o.__proto__.d = 'd'

o.hasOwnProperty(Symbol.for('a'));  //true
o.hasOwnProperty('b')   //true
o.hasOwnProperty('c')   //true   
o.hasOwnProperty('d')   //false  不能檢測對象原型鏈上的屬性

常與for...in 配合遍歷全部自身屬性
var buz = {
    fog: 'stack'
};
for (var name in buz) {
    if (buz.hasOwnProperty(name)) {
       console.log("this is fog (" + name + ") for sure. Value: " + buz[name]);
    }
    else {
       console.log(name); // toString or something else
    }
}
注: for...in遍歷對象自身和繼承的可枚舉屬性(enumerable: true / 不含Symbol屬性)
複製代碼

20. Object.prototype.isPrototypeOf()

測試一個對象是否存在於另外一個對象的原型鏈上

function Foo() {}
function Bar() {}
function Baz() {}

Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);

var baz = new Baz();

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
複製代碼

21. Object.prototype.valueOf()

返回對象的原始值

備註:js對象中的valueOf()方法和toString()方法很是相似,可是,當須要返回對象的原始值而非字符串的時候才調用它,尤爲是轉換爲數字的時候。若是在須要使用原始值的上下文中使用了對象,JavaScript就會自動調用valueOf()方法。

const o = {a: 1, valueOf: function(){ return 123123 } }
Number(o)    //123123

// 給你們出一個題
const o2 = {
    x: 1,
    valueOf: function(){
        return this.x++
    }
}

if(o2 == 1 && o2 == 2 && o2 == 3){
    console.log('down')
    console.log(o2.x)
}else{
    console.log('faild')
}

// Array:返回數組對象自己
var array = ["CodePlayer", true, 12, -5];
array.valueOf() === array;   // true

// Date:當前時間距1970年1月1日午夜的毫秒數
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
date.valueOf()     // 1376838719230

// Number:返回數字值
var num =  15.26540;
num.valueOf()     // 15.2654

// 布爾:返回布爾值truefalse
var bool = true;
bool.valueOf() === bool    // true
// new一個Boolean對象
var newBool = new Boolean(true);
// valueOf()返回的是true,二者的值相等
newBool.valueOf() == newBool     // true
// 可是不全等,二者類型不相等,前者是boolean類型,後者是object類型
newBool.valueOf() === newBool     // false

// Function:返回函數自己
function foo(){ 
}
foo.valueOf() === foo      // true
var foo2 =  new Function("x", "y", "return x + y;");
foo2.valueOf() === foo2    // true

// Object:返回對象自己
var obj = {name: "張三", age: 18};
obj.valueOf() === obj        // true

// String:返回字符串值
var str = "http://www.365mini.com";
str.valueOf() === str       // true
// new一個字符串對象
var str2 = new String("http://www.365mini.com");
// 二者的值相等,但不全等,由於類型不一樣,前者爲string類型,後者爲object類型
str2.valueOf() === str2      // false

複製代碼

22. Object.seal(obj)

將一個對象密封 isSealed 判斷一個對象是否爲密封的

密封對象是指那些不能添加新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可枚舉性、可配置性、可寫性,但可能能夠修改已有屬性的值的對象。

1. 先講seal 方法:
var o2 = {b: 1}
o2.d = 2    //添加成功
var obj2 = Object.seal(o2);
obj2 === o2         //true  方法返回原對象,棧指針指向同一塊內存
Object.getOwnPropertyDescriptor(obj2,'a');  // {value: 1, writable: true, enumerable: true, configurable: false}
Object.isSealed(o2)   // true

o2.b = 111       //修改b屬性值成功

o2.f = 222       //靜默失敗,屬性f沒有成功添加
delete o2.b      //靜默失敗,屬性b沒有成功刪除

2. 講isSealed 方法:
let o = {};
Object.isSealed(o)    //false

// 以後經過Object.preventExtensions方法將空對象設置爲不可擴展。
Object.preventExtensions(o);
Object.isSealed(o)    // true

可是若是爲非空對象呢?

let o2 = {a: 1}
Object.preventExtensions(o2);
Object.isSealed(o2)    // false

由於屬性 a 是可配置的(configurable爲true),因此不是密封的對象,修改方法以下:
let o2 = {a: 1}
Object.preventExtensions(o2);
Object.defineProperty(o2, "a", { configurable: false });
Object.isSealed(o2)    //true


總結: 
    1.密封一個對象會讓這個對象變的不能添加新屬性,且全部已有屬性會變的不可配置。
    2.屬性不可配置的效果就是屬性變的不可刪除,以及一個數據屬性不能被從新定義成爲訪問器屬性,或者反之。
    3.但屬性的值仍然能夠修改。
    4.嘗試刪除一個密封對象的屬性或者將某個密封對象的屬性從數據屬性轉換成訪問器屬性,結果會靜默失敗或拋出TypeError 異常(嚴格模式)。
    
Object.freeze作了兩件事情,
(1)給對象設置,Object.preventExtension(obj1),禁止更改原型,禁止添加屬性,
(2)爲對象的每個屬性設置,configurable:false,禁止更改屬性值,

與Object.freeze不一樣的是,Object.seal後的對象是可寫的writable:true複製代碼

23. Object.setPrototypeOf()

設置一個指定的對象的原型

const obj = {a: 1}, proto = {b:2}

Object.setPrototypeOf(obj, proto)

obj.__proto__ === proto     //true

複製代碼
相關文章
相關標籤/搜索