js之Object.defineProperty和Object.defineProperties详解

 1. Object.defineProperty() 

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

备注:应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用。

语法:

Object.defineProperty(obj, prop, descriptor)

obj

要定义属性的对象。

prop

要定义或修改的属性的名称或 Symbol 。

descriptor

要定义或修改的属性描述符。

例子

在我们平常的使用中,给对象添加一个属性时,直接使用object.param的方式就可以了,或者直接在对象中挂载。

const person = {
    name: 'hj'
}

在ECMAScript5中,对每个属性都添加了几个属性类型,来描述这些属性的特点。他们分别是

  • configurable:   默认false

configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

当第一次设置为false后,再改写是不可以的。属性值也是不能被删除的。

var o = {};
Object.defineProperty(o, 'a', {
  get() { return 1; },
  configurable: false
});
// 定义为false 后  enumerable set get configurable value 都是不能再设置了。 delete o.a 也是删不了的
Object.defineProperty(o, 'a', {
  configurable: true
}); // throws a TypeError  抛出错误
Object.defineProperty(o, 'a', {
  enumerable: true
}); // 抛出错误
Object.defineProperty(o, 'a', {
  set() {}
}); // 报错
Object.defineProperty(o, 'a', {
  get() { return 1; }
}); // throws a TypeError
// (even though the new get does exactly the same thing)
Object.defineProperty(o, 'a', {
  value: 12
}); // throws a TypeError // ('value' can be changed when 'configurable' is false but not in this case due to 'get' accessor)

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1  还存在说明没删掉

 

  • enumerable:  默认false

enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

for...in 循环和 Object.keys()  定义: 任意顺序遍历一个对象的除Symbol以外的可枚举属性。

var o = {};
Object.defineProperty(o, "a", { value : 1, enumerable: true });
Object.defineProperty(o, "b", { value : 2, enumerable: false });
Object.defineProperty(o, "c", { value : 3 }); // enumerable 默认为 false
o.d = 4; // 如果使用直接赋值的方式创建对象的属性,则 enumerable 为 true
Object.defineProperty(o, Symbol.for('e'), {
  value: 5,
  enumerable: true
});
Object.defineProperty(o, Symbol.for('f'), {
  value: 6,
  enumerable: false
});

for (var i in o) {
  console.log(i);
}
// 只会打印a 和 d 

Object.keys(o); // ['a', 'd']

打印 对象 o 在谷歌浏览器中查看 

o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
o.propertyIsEnumerable('d'); // true
o.propertyIsEnumerable(Symbol.for('e')); // true
o.propertyIsEnumerable(Symbol.for('f')); // false

var p = { ...o }
p.a // 1
p.b // undefined
p.c // undefined
p.d // 4
p[Symbol.for('e')] // 5
p[Symbol.for('f')] // undefined
  • writable:  默认false

当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

var o = {}; // 创建一个新对象

Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); //  37
o.a = 25; // No error thrown  不会抛出错误,但是也更改不了这个值,因为这个不是在严格模式下
// (it would throw in strict mode,
// even if the value had been the same)
console.log(o.a); // 还是37 

// strict mode
(function() {
  'use strict';
  var o = {};
  Object.defineProperty(o, 'b', {
    value: 2,
    writable: false
  });
  o.b = 3; // throws TypeError: "b" is read-only
  return o.b; // returns 2 without the line above
}());
  •  value :  默认undefined

如果对象中不存在指定的属性,Object.defineProperty() 会创建这个属性。当描述符中省略某些字段时,这些字段将使用它们的默认值。

var o = {}; // 创建一个新对象

// 在对象中添加一个属性与数据描述符的示例
Object.defineProperty(o, "a", {
  value : 37,
  writable : true,
  enumerable : true,
  configurable : true
});

// 对象 o 拥有了属性 a,值为 37

// 在对象中添加一个设置了存取描述符属性的示例
var bValue;
Object.defineProperty(o, "b", {
  // 使用了方法名称缩写(ES2015 特性)
  // 下面两个缩写等价于:
  // get : function() { return bValue; },
  // set : function(newValue) { bValue = newValue; },
  get() { return bValue; },
  set(newValue) { bValue = newValue; },
  enumerable : true,
  configurable : true
});

o.b; // 38
// 对象 o 拥有了属性 b,值为 38
// 现在,除非重新定义 o.b,o.b 的值总是与 bValue 相同

// 数据描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
  value: 0x9f91102,
  get() { return 0xdeadbeef; } 
});
// 抛出错误 TypeError: value appears only in data descriptors, get appears only in accessor descriptors
  • get: 当我们通过person.name访问name的值时,get将被调用。该方法可以自定义返回的具体值是多少。get默认值为undefined
  • set: 当我们通过person.name = 'Jake'设置name的值时,set方法将被调用。该方法可以自定义设置值的具体方式。set默认值为undefined

考虑特性被赋予的默认特性值非常重要,通常,使用点运算符和 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
});

需要注意的是,不能同时设置value、writable 与 get、set的值。

 

var person = {}

// 通过get与set自定义访问与设置name属性的方式
Object.defineProperty(person, 'name', {
    get: function() {
        // 一直返回TOM
        return 'TOM'
    },
    set: function(value) {
        // 设置name属性时,返回该字符串,value为新值
        console.log(value + ' in set');
    }
})

// 第一次访问name,调用get
console.log(person.name)   // TOM

// 尝试修改name值,此时set方法被调用
person.name = 'alex'   // alex in set

// 第二次访问name,还是调用get
console.log(person.name) // TOM

请尽量同时设置get、set。如果仅仅只设置了get,那么我们将无法设置该属性值。如果仅仅只设置了set,我们也无法读取该属性的值。

2.Object.defineProperties

当我们想要同时设置多个属性的特性时,需要使用Object.defineProperties

语法:  Object.defineProperties(obj, props)

参数说明

obj

在其上定义或修改属性的对象。

props

要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅Object.defineProperty())。描述符具有以下键:

configurable

true 当且仅当该属性描述符的类型可以被改变并且该属性可以从对应对象中删除。
默认为 false

enumerable

true 当且仅当在枚举相应对象上的属性时该属性显现。
默认为 false

value

与属性关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。
默认为 undefined.

writable

true当且仅当与该属性相关联的值可以用assignment operator改变时。
默认为 false

get

作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。
默认为 undefined

set

作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。
默认为 undefined

用法除了格式基本与Object.defineProperty相同

var person = {}

Object.defineProperties(person, {
    name: {
        value: 'Jake',
        configurable: true
    },
    age: {
        get: function() {
            return this.value || 22
        },
        set: function(value) {
            this.value = value
        }
    }
})

person.name   // Jake
person.age    // 22

读取属性的特性值

我们可以使用Object.getOwnPropertyDescriptor方法读取某一个属性的特性值。

 

var person = {}

Object.defineProperty(person, 'name', {
    value: 'alex',
    writable: false,
    configurable: false
})

var descripter = Object.getOwnPropertyDescriptor(person, 'name');

console.log(descripter);  // 返回结果如下

descripter = {
    configurable: false,
    enumerable: false,
    value: 'alex',
    writable: false
}

 

  • 38
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值