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

复制代码
相关文章
相关标签/搜索