脚本宝典收集整理的这篇文章主要介绍了

JavaScript之Object

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。

Object

Object构造函数创建一个对象包装器。如果给定值是 null or undefined,将会创建并返回一个空对象,否则,将返回一个与给定值对应类型的对象。布尔值、数值、字符串分别转成对应的包装对象时,它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面。只有字符串的包装对象,会产生可枚举属性。

clipboard.png

当以非构造函数形式被调用时,Object 等同于 new Object()。

clipboard.png

方法

Object.assign()

Object.assign(target, ...sources)

target:目标对象。sources:(多个)源对象。

该方法用于将所有可枚举的属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
obj===o1; //true, obj与o1完全相等

注意:

1.拷贝的属性为源对象自身的并且可枚举的(包括Symbol 类型的属性)。

2.若目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。覆盖时直接替换。

var target = { a: { b: 'c', d: 'e' } }
var source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
//target对象的a属性被source对象的a属性整个替换掉

3.在属性拷贝过程中产生异常时,该方法会抛出一个 TypeError 异常,拷贝过程中断,已经拷贝成功的属性不会受到影响,还未拷贝的属性将不会再被拷贝。

4.Object.assign 会跳过那些值为 nullundefined 的源对象。

5.Object.assign方法实行的是浅拷贝,而不是深拷贝。 也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2
//Object.assign拷贝得到的是这个对象的引用。这个对象的任何变化,都会反映到目标对象上面。

6.若参数不是对象,则会先转成对象。由于undefined和null无法转成对象,所以当null 和 undefined不在首参数时,会被忽略。在首参数,则报错。Object.assign不会拷贝对象的内部属性[[PrimitiveValue]]。因此只有字符串会以数组形式,拷贝入目标对象,其他值(即数值、字符串和布尔值)都不会产生效果。

var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")

var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
//注意,布尔值、数值、字符串分别转成对应的包装对象时,它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面。只有字符串的包装对象,会产生可枚举属性,这些属性会被拷贝。因此其他类型的值(即数值、字符串和布尔值)不在首参数,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

Object(true) // {[[PrimitiveValue]]: true}
Object(10)  //  {[[PrimitiveValue]]: 10}
Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}

7.Object.assign可以用来处理数组,但是会把数组视为对象。

Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//Object.assign把数组视为属性名为0、1、2的对象,因此源数组的0号属性4覆盖了目标数组的0号属性1。

8.拷贝访问器时,只拷贝其值,访问器属性会被转换成数据属性。

var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

// copy.bar的值来自obj.bar的getter函数的返回值 
var copy = Object.assign({}, obj);  // { foo: 1, bar: 2 }

Object.getOwnPropertyDescriptor(copy,"bar");
//{value: 2, writable: true, enumerable: true, configurable: true}
//可以看到bar在obj对象里为存取描述,而在copy对象里面变成了数据描述。

可通过以下代码进行完整拷贝。该方法为浅拷贝。

Object.create(
  Object.getPrototypeOf(obj), 
  Object.getOwnPropertyDescriptors(obj) 
);
var t={
      a:{
        a1:11,
        a2:12
      },
      b:2
};
var c=Object.getOwnPropertyDescriptors(t);
var m=Object.create({},c);
m.a.a1=333;
t.a.a1 //333
//可以看到拷贝时属性值是浅拷贝

Object.create()

Object.create(proto, [ propertiesObject ])

proto:一个对象,应该是新创建的对象的原型,也可以是null。propertiesObject:可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,只能是属性描述符。propertiesObject也可以是undefined。

该方法使用指定的原型对象及其属性去创建一个新的对象。

// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })

// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 333
o.p
//42

注意:

1.propertiesObject参数对象不能是 null,并且只有该对象中自身拥有可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。

var a={
 //foo会成为所创建对象的数据属性
  foo:{
    writable:true,
    configurable:true,
    value: 222
  },
  // abc会成为所创建对象的访问器属性
  abc: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.abc` to", value);
    }
  }
};
//原型链上的属性不会出现
a.__proto__={
   bar:{
      writable:true,
      configurable:true,
      value: 555,
      enumerable:true
   }
};
//three属性可枚举,因此会出现在o对象中
Object.defineProperty(a,"three",{
     value:{
        value:333
     },
     enumerable:true
});
//four属性不可枚举,因此不会出现在o对象中
Object.defineProperty(a,"four",{
     value:{
        value:444
     },
     enumerable:false
})
var o = Object.create(Object.prototype,a);
o //{foo: 222, three: 333}

clipboard.png

2.如果 proto参数不是 null 也不是对象,则抛出一个 TypeError 异常。

Object.defineProperty()

Object.defineProperty(obj, prop, descriptor)

obj:需要被操作的目标对象。prop:目标对象需要定义或修改的属性的名称。descriptor:将被定义或修改的属性的描述符。

该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。描述符必须是两种形式之一;不能同时是两者。

数据描述符的键值:configurable,enumerable,value,writable。
存取描述符的键值:configurable,enumerable,get,set。

  1. configurable:表示对象的属性是否可以被删除,以及除writable和value外的其他特性是否可以被修改。默认为 false。如果一个属性的 configurable 为 false,则其 writable 特性也只能修改为 false。

     var a={};
     Object.defineProperty(a,"m",
     {enumerable:true,configurable:false,value:111,writable:true});
    
     //将enumerable改为false,报错TypeError: Cannot redefine property: m
     Object.defineProperty(a,"m",
     {enumerable:false,configurable:false,value:111,writable:true});
    
     //将writable改为false,成功
     Object.defineProperty(a,"m",
     {enumerable:true,configurable:false,value:111,writable:false});
    
     //再将writable改为true,报错TypeError: Cannot redefine property: m
     Object.defineProperty(a,"m",
     {enumerable:true,configurable:false,value:111,writable:true});
  2. enumerable:表示对象的属性是否可枚举。默认为 false。
  3. writable:表示对象的属性是否能被赋值运算符改变。默认为 false。

注意:

1.当描述符中省略某些字段时,这些字段将使用它们的默认值。拥有布尔值的字段的默认值都是false。value,get和set字段的默认值为undefined。定义属性时如果没有get/set/value/writable,那它被归类为数据描述符。

var o = {}; // 创建一个新对象
Object.defineProperty(o, "a", {
  enumerable : true,
  configurable : true
});
Object.getOwnPropertyDescriptor(o,"a")
//{value: undefined, writable: false, enumerable: true, configurable: true}

2.使用点运算符和Object.defineProperty()为对象的属性赋值时,数据描述符中的属性默认值是不同的。

var o = {};

o.a = 1;
// 等同于 :
Object.defineProperty(o, "a", {
  value : 1,
  writable : true,
  configurable : true,
  enumerable : true
});


// 另一方面,
Object.defineProperty(o, "a", { value : 1 });
// 等同于 :
Object.defineProperty(o, "a", {
  value : 1,
  writable : false,
  configurable : false,
  enumerable : false
});

Object.defineProperties()

Object.defineProperties(obj, props)
obj:将要被添加属性或修改属性的对象。props:该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置。

该方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

var obj = {};
Object.defineProperties(obj, {
  "property1": {
    value: true,
    writable: true
  },
  "property2": {
    value: "Hello",
    writable: false
  }
  // 等等.
});
alert(obj.property2) //弹出"Hello"

Object.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor(obj, prop)
obj:需要查找的目标对象。prop:目标对象内属性名称(String类型)。

该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)。即只查找自有属性。若不存在则返回 undefined。

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors(obj)
obj:任意对象。

该方法用来获取一个对象的所有自身属性的描述符。如果没有任何自身属性,则返回空对象。

Object.is()

Object.is(value1, value2):确定两个值是否相同。
Object.is() 会在下面这些情况下认为两个值是相同的:

  • 两个值都是 undefined
  • 两个值都是 null
  • 两个值都是 true 或者都是 false
  • 两个值是由相同个数的字符按照相同的顺序组成的字符串
  • 两个值指向同一个对象
  • 两个值都是数字并且

    • 都是正零 +0
    • 都是负零 -0
    • 都是 NaN
    • 都是除零和 NaN 外的其它同一个数字

Object.is()与严格相等运算符 === 不同,“===”会把 -0 和 +0 这两个数值视为相同的,还会把两个 NaN 看成是不相等的。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

属性的遍历

  • Object.keys(obj):返回一个数组,成员是参数对象自身的所有可枚举属性的键名(不含Symbol属性)。
  • Object.values(obj):返回一个数组,成员是参数对象自身的所有可枚举属性的键值(不含Symbol属性)。
  • Object.entries(obj):返回一个数组,成员是参数对象自身的所有可枚举属性的键值对数组(不含Symbol属性)。该功能为试验中功能。
  • for...in:循环遍历对象自身的和继承可枚举属性(不含Symbol属性)。
  • Object.getOwnPropertyNames(obj):返回一个数组,成员是参数对象自身可枚举和不可枚举属性的名称(不含Symbol属性)。
  • Object.getOwnPropertySymbols(obj):返回一个数组,成员是参数对象自身所有symbol属性的名称。
  • Reflect.ownKeys(obj):返回一个数组,成员是参数对象自身所有属性的名称,不管属性名是Symbol或字符串,也不管是否可枚举。Reflect.ownKeys的返回值等同于Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))。

以上的方法遍历对象的属性,都遵守同样的属性遍历的次序规则。

  • 首先遍历所有属性名为数值的属性,按照数字排序。
  • 其次遍历所有属性名为字符串的属性,按照生成时间排序。
  • 最后遍历所有属性名为Symbol值的属性,按照生成时间排序。

原型

改变一个对象的 [[Prototype]] 属性,是一个非常慢且影响性能的操作。推荐使用 Object.create()创建带有你想要的[[Prototype]]的新对象。

_proto_

Object.prototype 的 _proto_ 属性是一个访问器属性。可使用_proto_ 进行原型的获取与设置。但这个是过时且不推荐使用的。使用_proto_ 进行原型的设置时,对象应是可扩展的,不然会抛出一个 TypeError 错误。