Object 的种种要领

分类

Object() 函数

Object 本身是一个函数,用来将恣意值转为对象。

如果参数为空(或许为 undefinednull),Object() 返回一个空对象。

var obj = Object();
// 等同于
var obj = Object(undefined);
var obj = Object(null);

obj instanceof Object // true

如果参数是原始范例的值,Object 要领将其转为对应的包装对象的实例。

var obj = Object(1);
obj instanceof Object // true
obj instanceof Number // true

var obj = Object('foo');
obj instanceof Object // true
obj instanceof String // true

var obj = Object(true);
obj instanceof Object // true
obj instanceof Boolean // true

如果 Object 要领的参数是一个对象,它老是返回该对象,即不必转换。

var arr = [];
var obj = Object(arr);  // 返回原数组
obj === arr             // true

var value = {};
var obj = Object(value) // 返回原对象
obj === value           // true

var fn = function () {};
var obj = Object(fn);  // 返回原函数
obj === fn             // true

因而,能够写一个推断变量是不是为对象的函数。这个要领常用于保证某个值一定是对象。

function isObject(value) {
  return value === Object(value);
}

isObject([]) // true
isObject(true) // false

组织函数 new Object()

Object 组织函数的重要用处,是直接经由过程它来天生新对象。

var obj = new Object();

// 等同于
var obj = {}

new Object() 组织函数与 Object() 的用法很相似,险些如出一辙。运用时,能够接收一个参数,如果该参数是一个对象,则直接返回这个对象;如果是一个原始范例的值,则返回该值对应的包装对象。

var o1 = {a: 1};
var o2 = new Object(o1);
o1 === o2 // true

var obj = new Object(123);
obj instanceof Number // true

二者区别是语义差别。Object(value) 示意将 value 转成一个对象,new Object(value) 则示意新天生一个对象,它的值是 value

Object 对象的原生要领

Object 对象的原生要领分红两类:Object 本身的要领与Object 的实例要领。

(1) 本身的要领

本身的要领就是直接定义在 Object 对象的要领。

1. 遍历对象属性
  • Object.keys():遍历对象本身的(非继续的)可罗列属性,返回属性名。
  • Object.getOwnPropertyNames():遍历对象本身的(非继续的)悉数(可罗列+不可罗列历)属性。
  • Object.values():遍历对象本身的(非继续的)可罗列属性,返回属性值。
  • Object.entries():遍历对象本身的(非继续的)可罗列属性,返回键值对。
2. 对象的属性形貌对象相干要领
  • Object.getOwnPropertyDescriptor():猎取某个属性的形貌对象。
  • Object.getOwnPropertyDescriptors():猎取对象的一切属性的形貌对象。
  • Object.defineProperty():定义某个属性的形貌对象。
  • Object.defineProperties():定义多个属性的形貌对象。
3. 掌握对象状况的要领
  • Object.preventExtensions():防备对象扩大,没法增添新属性。
  • Object.isExtensible():推断对象是不是可扩大。
  • Object.seal():制止对象设置,没法增添新属性,没法删除属性。
  • Object.isSealed():推断一个对象是不是可设置。
  • Object.freeze():凝结一个对象,没法增添新属性,没法删除属性,没法转变属性值。
  • Object.isFrozen():推断一个对象是不是被凝结。
4. 原型链相干要领
  • Object.create():以参数为原型返回一个新的实例对象。
  • Object.getPrototypeOf():猎取对象的原型对象。
  • Object.setPrototypeOf():设置对象的原型对象。
5. 别的
  • Object.assign()
  • Object.is()

(2) 实例要领

实例要领就是定义在 Object 原型对象 Object.prototype 上的要领。它能够被 Object 实例直接运用。

Object 实例对象的要领,重要有以下六个:

  • Object.prototype.valueOf():返回当前对象对应的值。
  • Object.prototype.toString():返回当前对象对应的字符串情势。
  • Object.prototype.toLocaleString():返回当前对象对应的当地字符串情势。
  • Object.prototype.hasOwnProperty():推断某个属性是不是为当前对象本身的属性,照样继续自原型对象的属性。
  • Object.prototype.isPrototypeOf():推断当前对象是不是为另一个对象的原型。
  • Object.prototype.propertyIsEnumerable():推断对象本身的(非继续的)属性是不是可罗列。

要领引见

猎取属性相干

1. Object.keys() , Object.getOwnPropertyNames()

Object.keys 要领和 Object.getOwnPropertyNames 要领都用来遍历对象的属性。

Object.keys 要领的参数是一个对象,返回一个数组。该数组的成员都是该对象本身的(非继续的)一切属性名,且只返回可罗列的属性。

var obj = Object.defineProperties({}, {
  p1: { value: 1, enumerable: true },
  p2: { value: 2, enumerable: false }
});

Object.keys(obj)  // ["p1"]

Object.getOwnPropertyNames 要领与 Object.keys 相似,也是接收一个对象作为参数,返回一个数组,该数组的成员是参数对象本身的(非继续的)悉数属性的属性名,不论该属性是不是可罗列。

var a = ['Hello', 'World'];

Object.keys(a)                   // ["0", "1"]
Object.getOwnPropertyNames(a)    // ["0", "1", "length"]

上面代码中,数组的 length 属性是不可罗列的属性,所以只出现在 Object.getOwnPropertyNames 要领的返回效果中。

由于 JavaScript 没有供应盘算对象属性个数的要领,所以能够用这两个要领替代。

var obj = { p1: 123, p2: 456 };

Object.keys(obj).length                  // 2
Object.getOwnPropertyNames(obj).length   // 2

平常状况下,险些老是运用 Object.keys 要领,遍历对象的属性。

2. Object.values()

Object.values() 要领返回一个数组,成员是参数对象本身的(非继续的)一切可罗列属性的属性值。

var obj = { p1: 123, p2: 456 };
Object.values(obj)   // [123, 456]

3. Object.entries()

Object.entries() 要领返回一个数组,成员是参数对象本身的(非继续的)一切可罗列属性的键值对数组。

var obj = { p1: 123, p2: 456 };
Object.entries(obj)  // [["p1", "123"], ["p2", 456]]

4. Object.prototype.hasOwnProperty()

实例对象的 hasOwnProperty() 要领接收一个字符串作为参数,返回一个布尔值,示意该实例对象本身是不是具有该属性。有返回 true,没有或是继续的属性都返回 false

var obj = { p: 123 };

obj.hasOwnProperty('p')            // true
obj.hasOwnProperty('toString')     // false

原型链相干

1. Object.getPrototypeOf()

Object.getPrototypeOf() 要领返回参数对象的原型。这是猎取原型对象的规范要领。

var F = function () {};
var f = new F();
Object.getPrototypeOf(f) === F.prototype // true

Object.prototype 的原型是 null

Object.getPrototypeOf(Object.prototype) === null // true

2. Object.setPrototypeOf()

Object.setPrototypeOf() 要领为参数对象设置原型,返回该参数对象。它接收两个参数,第一个是现有对象,第二个是原型对象。

var a = {};
var b = {x: 1};
Object.setPrototypeOf(a, b);

Object.getPrototypeOf(a) === b // true
a.x // 1

new 敕令能够运用 Object.setPrototypeOf() 要领模仿。

var F = function () { this.foo = 'bar'; };

var f = new F();
// 等同于
var f = Object.setPrototypeOf({}, F.prototype);
F.call(f);

3. Object.prototype.__proto__

实例对象的 __proto__ 属性,返回该对象的原型。该属性可读写。

var obj = {};
var p = {};

obj.__proto__ = p;
Object.getPrototypeOf(obj) === p   // true

依据言语规范,__proto__ 属性只需浏览器才须要布置,其他环境能够没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应当对运用者暴露。因而,应当只管罕用这个属性,而是用 Object.getPrototypeof()Object.setPrototypeOf(),举行原型对象的读写操纵。

4. Object.prototype.isPrototypeOf()

实例对象的 isPrototypeOf() 要领,用来推断该对象是不是为参数对象的原型。

var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);

o2.isPrototypeOf(o3)   // true
o1.isPrototypeOf(o3)   // true

只需实例对象处在参数对象的原型链上,isPrototypeOf() 要领都返回true。

Object.prototype.isPrototypeOf({})                   // true
Object.prototype.isPrototypeOf([])                   // true
Object.prototype.isPrototypeOf(/xyz/)                // true
Object.prototype.isPrototypeOf(Object.create(null))  // false

由于 Object.prototype 处于原型链的最顶端,所以对种种实例都返回 true,只需直接继续自 null 的对象除外。

5. Object.create()

Object.create() 要领接收一个对象作为参数,目的是以参数对象为原型,返回一个实例对象。该实例完整继续原型对象的属性。

许多时刻,须要从一个实例对象 A 天生另一个实例对象 B,如果 A 是由组织函数建立的,那末能够很轻松的获得 A 的组织函数从新天生实例 B,然则许多时刻,A 只是一个一般的对象,并非由组织函数天生的,这时刻就须要运用Object.create() 要领由 A 天生 B。

var A = {
  print: function () {
    console.log('hello');
  }
};

var B = Object.create(A);

Object.getPrototypeOf(B) === A    // true
B.print()                         // hello
B.print === A.print               // true

Object.create() 要领兼容性处置惩罚,即天生实例的本质:

if (typeof Object.create !== 'function') {
  Object.create = function (obj) {
    function F() {}       // 新建一个空的组织函数 F
    F.prototype = obj;    // 让 F.prototype 属性指向参数对象 obj
    return new F();       // 末了返回一个 F 的实例
  };
}

下面三种体式格局天生的新对象是等价的:

var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object();

如果想要天生一个不继续任何属性(比方没有 toStringvalueOf 要领)的对象,能够将 Object.create 的参数设为 null。由于天生的实例对象原型是 null,所以它就不具备定义在 Object.prototype 原型上面的要领。

var obj = Object.create(null);

Object.create() 要领还能够接收第二个参数。该参数是一个属性形貌对象,它所形貌的对象属性,会增添到实例对象,作为该对象本身的属性。

var obj = Object.create({}, {
  p1: {
    value: 123,
    enumerable: true,
    configurable: true,
    writable: true,
  },
  p2: {
    value: 'abc',
    enumerable: true,
    configurable: true,
    writable: true,
  }
});

// 等同于
var obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'abc';

Object.create() 要领天生的对象,继续了它的原型对象的组织函数。

function A() {}
var a = new A();
var b = Object.create(a);

b.constructor === A   // true
b instanceof A        // true

属性形貌对象相干

1. Object.getOwnPropertyDescriptor() , Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptor() 能够猎取某个属性的属性形貌对象。它的第一个参数是对象,第二个参数是对象的某个属性名。返回的是该属性的属性形貌对象。

var obj = { p1: 'a',  p2: 'b'};

Object.getOwnPropertyDescriptor(obj, 'p1')
// { value: "a",
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

只能用于对象本身的(非继续的)属性。继续的或不存在的属性返回 undefined

Object.getOwnPropertyDescriptor(obj, 'toString')   // undefined

Object.getOwnPropertyDescriptors() 能够猎取参数对象的一切属性的属性形貌对象。ES2017 引入规范。

Object.getOwnPropertyDescriptors(obj)
// { p1: {value: "a", writable: true, enumerable: true, configurable: true}
//   p2: {value: "b", writable: true, enumerable: true, configurable: true}
// }

2. Object.defineProperty() ,Object.defineProperties()

Object.defineProperty() 要领许可经由过程属性形貌对象,定义或修正一个属性,然后返回修正后的形貌对象。

Object.defineProperty(object, propertyName, attributesObject)

Object.defineProperty() 要领接收三个参数,顺次以下。

  • object:属性地点的对象
  • propertyName:字符串,示意属性名
  • attributesObject:属性形貌对象
var obj = Object.defineProperty({}, 'p', {
  value: 123,
  writable: false,
  enumerable: true,
  configurable: false
});
obj.p         // 123
obj.p = 246;
obj.p         // 123

注重,上例中第一个参数是{ }(一个新建的空对象),p属性直接定义在这个空对象上面,然后返回这个对象,这是 Object.defineProperty() 的罕见用法。

如果属性已存在,Object.defineProperty() 要领相当于更新该属性的属性形貌对象。

Object.defineProperties() 要领能够定义或修正多个属性。接收两个参数。

var obj = Object.defineProperties({}, {
  p1: { value: 123, enumerable: true },
  p2: { value: 'abc', enumerable: true },
  p3: { get: function () { return this.p1 + this.p2 },
    enumerable:true,
    configurable:true
  }
});

obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"

注重,一旦定义了取值函数 get 或存值函数 set,就不能同时定义 writable 属性或 value 属性,不然会报错。

元属性默许值

Object.defineProperty()Object.defineProperties() 参数内里的属性形貌对象,writableconfigurableenumerable 这三个属性的默许值都为 false

var obj = {};
Object.defineProperty(obj, 'foo', {});
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
//   value: undefined,
//   writable: false,
//   enumerable: false,
//   configurable: false
// }

3. Object.prototype.propertyIsEnumerable()

实例对象的 propertyIsEnumerable() 要领返回一个布尔值,用来推断某个属性是不是可罗列。

var obj = {};
obj.p = 123;

obj.propertyIsEnumerable('p')           // true
obj.propertyIsEnumerable('toString')    // false

注重,这个要领只能用于推断对象本身的属性,关于继续的属性一概返回 false

掌握对象状况相干

偶然须要凝结对象的读写状况,防备对象被转变。JavaScript 供应了三种凝结要领,最弱的一种是 Object.preventExtensions(),其次是 Object.seal(),最强的是 Object.freeze()

1. Object.preventExtensions()

Object.preventExtensions() 要领能够使得一个对象没法再增添新的属性。

var obj = new Object();
Object.preventExtensions(obj);

Object.defineProperty(obj, 'p', { value: 'hello' });
// TypeError: Cannot define property p, object is not extensible.

obj.p = 1;
obj.p      // undefined

2. Object.isExtensible()

Object.isExtensible() 要领用于搜检是不是能够为一个对象增添属性。能够增添返回 true,不能够增添返回 false

var obj = new Object();

Object.isExtensible(obj) // true
Object.preventExtensions(obj);
Object.isExtensible(obj) // false

3. Object.seal()

Object.seal() 要领使得一个对象既没法增添新属性,也没法删除旧属性。

var obj = { p: 'hello' };
Object.seal(obj);

delete obj.p;
obj.p // "hello"

obj.x = 'world';
obj.x // undefined

Object.seal 本质是把属性形貌对象的 configurable 属性设为 false,因而属性形貌对象就不能再转变了。

var obj = { p: 'a' };

// seal要领之前
Object.getOwnPropertyDescriptor(obj, 'p')  // {... configurable: true }

Object.seal(obj);

// seal要领今后
Object.getOwnPropertyDescriptor(obj, 'p')  // {... configurable: false }

Object.defineProperty(obj, 'p', {
  enumerable: false
})
// TypeError: Cannot redefine property: p

Object.seal 只是制止新增或删除属性,并不影响修正某个属性的值。

var obj = { p: 'a' };
Object.seal(obj);
obj.p = 'b';
obj.p // 'b'

Object.seal 要领对 p 属性的 value 无效,是由于此时 p 属性的可写性由writable 决议。

4. Object.isSealed()

Object.isSealed() 要领用于搜检一个对象是不是运用了 Object.seal 要领。未运用返回false,运用了返回 true

var obj = { p: 'a' };

Object.seal(obj);
Object.isSealed(obj) // true

此时,Object.isExtensible() 要领也返回 false

Object.isExtensible(obj) // false

5. Object.freeze()

Object.freeze() 要领能够使得一个对象没法增添新属性、没法删除旧属性、也没法转变属性的值,使得这个对象现实上变成了常量。

var obj = { p: 'hello' };

Object.freeze(obj);

obj.p = 'world';
obj.p             // "hello"

obj.t = 'hello';
obj.t             // undefined

delete obj.p     // false
obj.p            // "hello"

6. Object.isFrozen()

Object.isFrozen() 要领用于搜检一个对象是不是运用了Object.freeze要领。未运用返回false,运用了返回 true。此时 Object.isExtensible() 也返回 false

var obj = { p: 'hello' };

Object.freeze(obj);
Object.isFrozen(obj)        // true
Object.isExtensible(obj)    // false

局限性

以上三个要领锁定对象有局限性,并非完整凝结。

  1. 能够经由过程转变原型对象,来为对象增添新属性。

    var obj = new Object();
    Object.preventExtensions(obj);
      
    var proto = Object.getPrototypeOf(obj);
    proto.t = 'hello';
    obj.t    // hello
    

    解决方案是,把 obj 的原型也凝结住。

    Object.preventExtensions(proto);
          
    proto.t = 'hello';
    obj.t   // undefined
    
    
  2. 如果属性值是对象,以上三个要领只能凝结属性指向的对象地点,而不能凝结对象本身。

     var obj = {
       foo: 1,
       bar: ['a', 'b']
     };
     Object.freeze(obj);
      
     obj.bar.push('c');
     obj.bar // ["a", "b", "c"]
    

    obj.bar 属性指向一个数组,obj 对象被凝结今后,这个指向没法转变,即没法指向其他值,然则所指向的数组是能够转变的。

完整凝结

var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach((key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize(obj[key]);
    }
  });
};

var obj = {
  foo: 1,
  bar: ['a', 'b']
};
constantize(obj);

obj.bar.push('c'); 
// TypeError: Cannot add property 2, object is not extensible

对象的兼并及拷贝

1. Object.assign()

Object.assign() 要领用于对象的兼并,将一切本身的(非继续的)可罗列属性的值从一个或多个源对象复制到目的对象。返回目的对象。目的对象本身也会转变。

Object.assign(target, ...sources)
  • target: 目的对象。
  • sources: 源对象。

如果目的对象中的属性具有雷同的键,则属性将被源中的属性掩盖。厥后的源的属性将相似地掩盖新近的属性。

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

var obj = Object.assign({}, o1, o2, o3);
obj    // { a: 1, b: 2, c: 3 }

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

var o1 = { a: null, b: 1};
var o2 = { c: undefined };
    
var obj = Object.assign({}, o1, o2);
obj   // {a: null, b: 1, c: undefined}

Object.assign() 拷贝的是属性值。如果源对象的属性值是一个指向对象的援用,它也只拷贝谁人援用值。

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

obj2.b.c = 3;
obj1   // { a: 0, b: { c: 3 } };
obj2   // { a: 0, b: { c: 3 } };

因而针对深拷贝,须要运用其他要领。

var obj1 = { a: 0 , b: { c: 0}};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj1.b.c = 4;
obj2    // { a: 0, b: { c: 0}}

Object.assign() 如果碰到存取器定义的属性,会只拷贝值。

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

var copy = Object.assign({}, obj); 
copy  // { foo: 1, bar: 2 }

因而必需运用 Object.getOwnPropertyDescriptors() 要领合营 Object.defineProperties() 要领,就能够完成准确拷贝。但仅限于可拷贝 gettersetter ,关于属性的援用范例照样属于浅拷贝。


var obj = {
  foo: { a : 0 },
  get bar() { return 2; }
};
var target = Object.defineProperties({},
  Object.getOwnPropertyDescriptors(obj)
);
Object.getOwnPropertyDescriptor(target, 'bar')
// { get : ƒ bar(),
   set : undefined,
   enumerable : true, 
   configurable : true }
   
obj.foo.a = 6
target.foo.a   // 6

如果属性不可写,会激发报错,如果在激发毛病之前增添了任何属性,则能够变动target对象。

别的

1. Object.is()

Object.is() 用来比较两个值是不是严厉相称,与严厉比较运算符(===)的行动基础一致。返回布尔值,相称返回 true,不相称返回 false。

差别之处只需两个:一是+0不即是-0,二是NaN即是本身。

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

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

概况见 JavaScript 的相称比较

ES5 能够经由过程下面的代码,布置 Object.is

Object.defineProperty(Object, 'is', {
  value: function(x, y) {
    if (x === y) {
      // 针对+0 不即是 -0的状况
      return x !== 0 || 1 / x === 1 / y;
    }
    // 针对NaN的状况
    return x !== x && y !== y;
  },
  configurable: true,
  enumerable: false,
  writable: true
});

2. Object.prototype.valueOf()

valueOf 要领的作用是返回一个对象的“值”,默许状况下返回对象本身。

var obj = new Object();
obj.valueOf() === obj      // true

重要用处是,JavaScript 自动范例转换时会默许挪用这个要领。因而,如果给实例对象自定义 valueOf() 要领,掩盖 Object.prototype.valueOf(),就能够获得想要的效果。

var obj = new Object();
obj.valueOf = function () {
  return 2;
};

1 + obj // 3

3. Object.prototype.toString()

toString 要领的作用是返回一个对象的字符串情势,默许状况下返回范例字符串。

var obj = {};
obj.toString()   // "[object Object]"

JavaScript 自动范例转换时也会挪用这个要领。因而能够经由过程自定义实例对象的 toString 要领,掩盖掉 Object.prototype.toString(),获得想要的字符串情势。

var obj = new Object();

obj.toString = function () {
  return 'hello';
};

obj + ' ' + 'world'     // "hello world"

数组、字符串、函数、Date 对象都离别布置了自定义的 toString 要领,掩盖了 Object.prototype.toString() 要领。

[1, 2, 3].toString() // "1,2,3"

'123'.toString() // "123"

(function () {
  return 123;
}).toString()
// "function () {
//   return 123;
// }"

(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"

Object.prototype.toString.call(value) 可用于推断数据范例,概况见 推断数据范例的种种要领

4. Object.prototype.toLocaleString()

Object.prototype.toLocaleString 要领与 toString 的返回效果雷同,也是返回一个值的字符串情势。

var obj = {};
obj.toString(obj)         // "[object Object]"
obj.toLocaleString(obj)   // "[object Object]"

这个要领的重要作用是留出一个接口,让种种差别的对象完成本身版本的 toLocaleString,用来返回针对某些地区的特定的值。

现在,重要有三个对象自定义了 toLocaleString 要领。

  • Array.prototype.toLocaleString()
  • Number.prototype.toLocaleString()
  • Date.prototype.toLocaleString()

日期的实例对象的 toStringtoLocaleString 返回值就不一样,而且 toLocaleString 的返回值跟用户设定的地点地区相干。

var date = new Date();
date.toString()       // "Thu Nov 29 2018 16:50:00 GMT+0800 (中国规范时间)"
date.toLocaleString() // "2018/11/29 下昼4:50:00"

参考链接:JavaScript 教程 Object 对象

    原文作者:Dora36
    原文地址: https://segmentfault.com/a/1190000017237523
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞