资讯专栏INFORMATION COLUMN

JavaScript之Object

高胜山 / 427人阅读

摘要:当以非构造函数形式被调用时,等同于。因此只有字符串会以数组形式,拷贝入目标对象,其他值即数值字符串和布尔值都不会产生效果。注意,布尔值数值字符串分别转成对应的包装对象时,它们的原始值都在包装对象的内部属性上面。拥有布尔值的字段的默认值都是。

Object

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

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

方法 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 会跳过那些值为 null 或 undefined 的源对象。

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}

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

Object.defineProperty()

Object.defineProperty(obj, prop, descriptor)

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

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

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

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

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});

enumerable:表示对象的属性是否可枚举。默认为 false。

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 错误。

var a={};
Object.preventExtensions(a);
a.__proto__={}
//Uncaught TypeError: # is not extensible
Object.getPrototypeOf()

Object.getPrototypeOf(object):返回指定对象的原型(即内部[[Prototype]]属性的值)。如果没有继承属性,则返回 null 。

Object.setPrototypeOf()

Object.setPrototypeOf(obj, prototype):设置一个对象的原型。返回参数对象本身,即obj对象。

若对象是不可扩展的,则会抛出 TypeError异常。如果prototype参数不是一个对象或者null(例如,数字,字符串,boolean,或者 undefined),则什么都不做。否则,该方法将obj的原型修改为新的值。推荐使用该方法来修改对象原型。

如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。由于undefined和null无法转为对象,所以如果第一个参数是undefined或null,就会报错。

Object.setPrototypeOf(1, {}) === 1 // true

Object.setPrototypeOf(undefined, {})
// TypeError: Object.setPrototypeOf called on null or undefined
Object.prototype.isPrototypeOf()

prototypeObj.isPrototypeOf(object):用于测试prototypeObj对象是否存在于object对象的原型链上。如果 prototypeObj 为 undefined 或 null,会抛出 TypeError。

冻结、密封、扩展

一个对象默认是可扩展的。

Object.freeze()

Object.freeze(obj):冻结一个对象,该方法返回被冻结的对象。冻结对象的属性不能进行增、删操作,也不能修改该对象已有属性的属性描述符键值对。

冻结对象的所有自身属性都不可能以任何方式被修改,但对该对象原型没有影响(即仍可对该对象原型上的属性进行增、删、改操作)。任何尝试修改该对象的操作都会失败,可能是静默失败,也可能会抛出异常(严格模式中)。

数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。

var theValue=0;
var t={
  get foo(){
    return theValue;
 },
  set foo(v){
    theValue=v;
 }
}
Object.freeze(t);
//不能修改foo属性的get
Object.defineProperty(t,"foo",{
    get(){
       return 222;
   }
}) //TypeError: Cannot redefine property: foo

//由于foo是访问器属性,所以还是可以修改t.foo的值。
t.foo //0
t.foo=3;
t.foo //3

如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。

obj = {
  internal : {}
};
Object.freeze(obj);
obj.internal.a = "aValue";
obj.internal.a  // "aValue"

Object.freeze(obj)操作做了两件事:1.将对象变成不可扩展。2.将对象属性的configurable和writable变成false。

var a={
    m:111,
    get foo(){
      return 333;
  }
};
var before=Object.getOwnPropertyDescriptors(a);
Object.freeze(a);
var after=Object.getOwnPropertyDescriptors(a);

Object.isFrozen()

Object.isFrozen(obj):判断一个对象是否被冻结。

冻结对象的特征:

不可扩展。

所有自身属性的configurable为false。

所有自身数据属性(即无getter和setter的属性)的writable为false。

在 ES6中, 如果参数不是一个对象类型,则将被视为一个冻结的普通对象,因此会返回 true。但在 ES5 中,会抛出一个 TypeError异常。

Object.isFrozen(1);
// TypeError: 1 is not an object (ES5 code)

Object.isFrozen(1);
// true                          (ES2015 code)
Object.seal()

Object.seal(obj):可以让一个对象密封,并返回被密封后的对象。密封对象将会阻止向对象添加新的属性,并且会将所有已有属性的可配置性(configurable)置为不可配置(false),其效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。但是可写性描述(writable)为可写(true)的属性的值仍然可被修改。

尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError 异常(严格模式)。

不会影响从原型链上继承的属性。但__proto__ 属性的值也会不能修改。

Object.isSealed()

Object.isSealed(obj):判断一个对象是否被密封。

密封对象的特征:

不可扩展。

所有自身属性的configurable为false。

在 ES6中, 如果参数不是一个对象类型,则将被视为一个密封的普通对象,因此会返回 true。但在 ES5 中,会抛出一个 TypeError异常。

Object.isSealed(1);
// TypeError: 1 is not an object (ES5 code)

Object.isSealed(1);
// true                          (ES6 code)
Object.preventExtensions()

Object.preventExtensions(obj):让一个对象变的不可扩展,也就是永远不能再添加新的属性,并返回该不可扩展对象。

如果一个对象可以添加新的属性,则这个对象是可扩展的。preventExtensions只能阻止一个对象不能再添加新的自身属性,但仍然可以为该对象的原型添加属性。然而Object.preventExtensions会阻止一个对象将__proto__属性重新指向另一个对象。

尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败,也可能会抛出 TypeError 异常(严格模式)。在 ECMAScript 5 中可扩展的对象可以变得不可扩展,但反过来不行。

Object.isExtensible()

Object.isExtensible(obj):判断一个对象是否是可扩展的。

在 ES6中, 如果参数不是一个对象类型,则将被视为一个不可扩展的普通对象,因此会返回 true。但在 ES5 中,会抛出一个 TypeError异常。

Object.isExtensible(1);
// TypeError: 1 is not an object (ES5 code)

Object.isExtensible(1);
// false                         (ES6 code)
其他实例方法 Object.prototype.hasOwnProperty()

obj.hasOwnProperty(prop):返回一个布尔值,指示对象是否具有指定的属性作为自身属性(即不是从原型链上继承到的属性)。
prop:要检测的属性 字符串名称或者 Symbol

Object.prototype.toString()

object.toString():返回一个表示该对象的字符串。

每个对象都有一个 toString() 方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。默认情况下,toString() 方法被每个继承自Object的对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中type是对象类型。

let obj = new Object();

obj.toString();           
// 返回 [object Object]

所以可以通过Object.prototype.toString.call(obj)来检测对象类型。

var toString = Object.prototype.toString;

toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]

//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
Object.prototype.toLocaleString()

obj.toLocaleString():返回调用 toString() 方法的结果。

Object.prototype.propertyIsEnumerable()

obj.propertyIsEnumerable(prop):返回一个布尔值,表明指定的属性名是否是当前对象可枚举自身属性。

Object.prototype.valueOf()

object.valueOf():返回指定对象的原始值。

JavaScript 调用 valueOf() 方法用来把对象转换成原始类型的值(数值、字符串和布尔值)。 你很少需要自己调用此函数;当遇到一种需要转换成一个原始值情况时候, JavaScript 会自动调用此函数。

默认情况下, valueOf()会被每个对象Object继承。每一个内置对象都会覆盖这个方法为了返回一个合理的值,如果对象没有原始值,valueOf()就会返回对象自身。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87391.html

相关文章

  • javascript 面向对象版块定义多个对象属性以及读取属性特性

    摘要:返回值是一个对象,如果是访问器属性,这个对象的属性有和如果是数据属性,这个对象的属性有和。上一篇面向对象版块之对象属性下一篇面向对象版块之创建对象 这是 javascript 面向对象版块的第三篇文章,主要讲解的是多个属性的定义以及读取属性的特性。前面这几章内容目的在于加深对对象的理解,这样可以利于理解后面的原型链以及继承方面的知识,或者你也可以了解一下不一样的 javascript ...

    wendux 评论0 收藏0
  • 01.javascript数据类型

    摘要:新增了第七种类型的值数值字符串布尔值对象数据类型判断有三种方法,可以判断一个值的类型运算符运算符方法运算符运算符可以返回一个值的数据类型。运算符运算符返回一个布尔值,表示对象是否为某个构造函数的实例。 1.数据类型 JavaScript一共有六种数据类型。(ES6新增了第七种Symbol类型的值) 数值(Number) 字符串(String) 布尔值(boolean) undefin...

    Aceyclee 评论0 收藏0
  • JavaScript ES5Object.create函数详解

    介绍 在创建对象的时候,我们有2种常用方法 一个是文本标记法(var obj = {}),一种是运用Object函数进行对象的创建(new Object()). 但是这两种方式并不是创建的一个完完全全干干净净的对象,这里的干净只得是没有继承链. 幸运的是,ES5为我们提供了一种创建完全干净的对象的方法,Object.create函数,接下我将向大家介绍Obje...

    zhaofeihao 评论0 收藏0
  • JavaScript对象属性

    摘要:尽管的右操作数是构造函数,但计算过程实际是检测了对象的继承关系。通过创建的对象使用构造函数的属性作为它们的原型。 JavaScript之对象属性 Object.create()继承 ECMAScript 5定义了一个名为Object.create()的方法,它创建一个新对象, 其中第一个参数是这个对象的原型。Object.create()提供第二个可选参数,用以对对象的属性进行进一步描...

    gekylin 评论0 收藏0
  • javascript基础判断变量类型

    摘要:判断变量类型数据类型种操作符可能返回的值如下注意的能力有限,其对于类型返回的都是使用场景区分对象和原始类型要区分一种对象类型和另一种对象类型可以使用运算符或对象属性运算符用法左边的运算数是一个右边运算数是对象类的名字或者构造函数返回或如果是 判断变量类型 javaSctipt数据类型7种: Number, String, Boolean, Null, Undefined, Object...

    jsdt 评论0 收藏0
  • JavaScript基础创建对象、原型、原型对象、原型链

    摘要:在最开始的时候,原型对象的设计主要是为了获取对象的构造函数。同理数组通过调用函数通过调用原型链中描述了原型链的概念,并将原型链作为实现继承的主要方法。 对象的创建 在JavaScript中创建一个对象有三种方式。可以通过对象直接量、关键字new和Object.create()函数来创建对象。 1. 对象直接量 创建对象最直接的方式就是在JavaScript代码中使用对象直接量。在ES5...

    wangbjun 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<