JavaScript Object 对象方法

2 minute read

Object.defineProperty

Object.defineProperty(obj, prop, descriptor) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。方法接收三个参数:分别为需定义属性的目标对象、属性名和熟悉描述符。

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

数据描述符和存取描述符两种形式下均可选键值:

  • configurable true 表示该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
  • enumerable true 表示该属性能够出现在对象的枚举属性(for in、Objecet.keyes)中。默认为 false。

数据描述符可选键值:

  • value 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
  • writable true 表示该属性能被赋值运算符改变。默认为 false。

存取描述符可选键值:

  • get 该方法返回值被用作属性值。默认为 undefined。
  • set 接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined。
// 数据描述符使用
function withValue(value) { // 循环使用同一对象
  var d = withValue.d || (
    withValue.d = {
      enumerable: false,
      writable: false,
      configurable: false,
      value: null
    }
  );
  d.value = value;
  return d;
}

var obj = {};
Object.defineProperty(obj, "key", withValue("static"));

使用存取描述符,可实现数据绑定,观察者模式。

var bValue;
Object.defineProperty(o, "b", {
  get : function(){
    return bValue;
  },
  set : function(newValue){
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

o.b = 38; // 对象o拥有了属性b,值为38

Object.getOwnPropertyDescriptor

返回对象的属性描述符,只能取得对象自身的属性描述符而不能获取原型对象的属性描述符。

var object1 = {
  property1: 42
}

var descriptor = Object.getOwnPropertyDescriptor(object1, 'property1');
console.log(descriptor.configurable); // true

Object.create

使用指定的原型对象或属性对象,创建一个新的对象

var o;
// 创建一个原型为null的空对象
o = Object.create(null);

o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);

o = Object.create(Object.prototype, {
  // foo会成为所创建对象的数据属性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar会成为所创建对象的访问器属性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});

function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码

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

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

o.q = 12
for (var prop in o) {
   console.log(prop)
}
//"q"

delete o.p
//false

//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
  p: {
    value: 42, 
    writable: true,
    enumerable: true,
    configurable: true 
  } 
});

Object.assign

用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。返回目标对象。如果属性存在,后面的参数对象会覆盖掉前面的。拷贝深度仅为一层,假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。

  • 继承属性和不可枚举属性不能拷贝
var obj = Object.create({foo: 1}, { // foo 是个继承属性。
    bar: {
        value: 2  // bar 是个不可枚举属性。
    },
    baz: {
        value: 3,
        enumerable: true  // baz 是个自身可枚举属性。
    }
});

var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }
  • 拷贝访问器
var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

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

// 下面这个函数会拷贝所有自有属性的属性描述符
function completeAssign(target, ...sources) {
  sources.forEach(source => {
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});

    // Object.assign 默认也会拷贝可枚举的Symbols
    Object.getOwnPropertySymbols(source).forEach(sym => {
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

Object.keys

返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 for-in 循环还会枚举其原型链上的属性)。

与 Object.hasOwnProperty 和 in 操作符检测检测的属性不同的是,后两者检测对象是否存在某个属性,不论属性是否可被枚举。

Object.hasOwnProperty 只会检测对象自身是否存在属性,而不会检测原型链上的对象。

in 操作符可检测一切对象及其原型链上对象存在的属性。

var pro = {'a': 1};
var obj = Object.create(pro);

Object.defineProperties(obj, {
  'b': {value: 2},
  'c': {value: 3, enumerable: true},
  'd': {value: 4, configurable: true}
});

Object.keys(obj);
// ['c']

for(var prop in obj) {
  console.log(prop);
}
// output
// 'c'
// 'a'

'a' in obj
// true
'b' in obj
// true

obj.hasOwnProperty('a')
// false
obj.hasOwnProperty('b')
// true

Object.getPrototypeOf

返回指定对象的原型

var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true