美文网首页
Object.defineProperty()

Object.defineProperty()

作者: 学的会的前端 | 来源:发表于2020-04-20 17:00 被阅读0次

对象

对象是由多个名/值对组成的无序的集合。对象中每个属性对应任意类型的值。
在JS中有一下几种方法为对象定义属性

var o = {};
o.name = "frank";
o['age'] = 18;
Object.defineProperty(o, "city", {
  value: "上海"
});
属性定义方法.PNG

Object.defineProperty()

  • MDN定义:Object.defineProperty()方法会直接在对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
  • 兼容性: IE8以下不可。
  • 语法:
Object.defineProperty(obj,prop,descriptor)
obj: 要定义属性的对象
prop: 要定义或修改的属性名称或Symbol
descriptor:要定义或修改的属性描述符
返回值: 此对象,即第一个参数obj
  • 给对象的属性添加特性描述,目前提供两种形式:数据描述符合存取描述符


    描述符可拥有的键值.PNG

创建属性

如果对象中不存在指定的属性,Object.defineProperty()会创建这个属性
一旦使用Object.defineProperty给对象添加属性,那么如果不设置属性的特性,那么configurable、enumerable、writable这些值都为默认的false

var o = {};
Object.defineProperty(o, "b", {
  value: "37",
  enumerable: true,
  configurable: true,
  writable: true
});
创建属性b.PNG

value属性

value属性对应的值,可以使任意值,默认是undefined。

var o = {}
Object.defineProperty(o, 'a', {})
Object.defineProperty(o, 'b', {
  value: 'lili'
})
console.log(o.a) //undefined
console.log(o.b) // lili

writable属性

writable属性对应的值是布尔值,当为false时,该属性被称为不可写,它不能被重新赋值

var o = {};
Object.defineProperty(o, "a", {
  value: 37,
  writable: false
});
o.a = 38; //没有错误被抛出
console.log(o.a); //37 a的值并未修改

enumerable属性

enumerable属性定义了对象的属性是否可以在for...in循环和Object.keys()中被枚举。enumerable的默认值为false,但是如果使用赋值方式o.a=1enumerable的默认值是true。

var o = {};
Object.defineProperty(o, "a", {
  value: 1,
  enumerable: true
});
Object.defineProperty(o, "b", {
  value: 2,
  enumerable: false
});
Object.defineProperty(o, "c", {
  value: 3
}); //此种方式默认为false
o.e = 4; //此种方式默认为true
for (let i in o) {
  console.log(i); //a , e
}
console.log(Object.keys(o)); //[a,e]

configurable属性

configurable属性作用:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。

var o = {};
Object.defineProperty(o, "a", {
  get() {
    return 1;
  },
  configurable: false
});
Object.defineProperty(o, "a", {
  configurable: true
}); // throws a TypeError
Object.defineProperty(o, "a", {
  enumerable: true
});
Object.defineProperties(o, "a", {
  set() {}
});
console.log(o.a); // logs 1
delete o.a; // Nothing happens,并没有删除a
console.log(o.a); // logs 1

存取器描述:getter/setter

注意:当使用了getter或setter方法,不允许使用writable和value这两个属性
getter 是一种获得属性值的方法
setter是一种设置属性值的方法。

var o = {};
var initValue = "hello";
Object.defineProperty(o, "name", {
  get() {
    return initValue;
  },
  set(value) {
    initValue = value;
    return initValue;
  }
});
console.log(o.name); //hello
o.name = "lili";
console.log(o.name); //lili

get或set不是必须成对出现,任写其一就可以。如果不设置方法,则get和set的默认值为undefined

继承属性

  1. 如果访问者的是属性是被继承的,它的get和set方法会在子对象的属性被访问或者修改时被调用,如果这些方法用一个变量存执,该值会被所有对象共享
function myClass() {}
var value; //定义一个变量,存储属性值,但是会共用属性值
Object.defineProperty(myClass.prototype, "x", {
  get() {
    return value;
  },
  set(x) {
    value = x;
  }
});

var a = new myClass();
var b = new myClass();
a.x = 1;
console.log(b.x); //1
// a与b公用属性x
  1. 这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
function myClass() {}
Object.defineProperty(myClass.prototype, "x", {
  get() {
    return this.stored_x;
  },
  set(x) {
    stored_x = x;
  }
});

var a = new myClass();
var b = new myClass();
a.x = 1; 
console.log(b.x); //undefied
  1. 如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。
function myclass() {}
myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
  writable: false,
  value: 1
});
var a = new myclass();
a.x = 2;
console.log(a.x); // 2
console.log(myclass.prototype.x); // 1
a.y = 2; // Ignored, throws in strict mode
console.log(a.y); // 1
console.log(myclass.prototype.y); // 1

实际运用

  1. MVVM中数据‘双向绑定’实现
    如vue,qjs等大部分mvvm框架(angular用的是脏处理)都是通过Object.defineProperty来实现数据绑定的。
  2. 优化对象获取和修改属性方式
Object.defineProperty(dom, 'translateX', {
set: function(value) {
        var transformText = 'translateX(' + value + 'px)';
        dom.style.webkitTransform = transformText;
        dom.style.transform = transformText;
}
//这样再后面调用的时候, 十分简单
dom.translateX = 10;
dom.translateX = -10;
//甚至可以拓展设置如scale, originX, translateZ,等各个属性,达到下面的效果
dom.scale = 1.5;  //放大1.5倍
dom.originX = 5;  //设置中心点X
}
  1. 增加属性获取和修改时的信息
    通过修改get属性方法,让用户调用废弃属性时抛错并带上自定义的错误信息。
[
  xxxxx
].forEach(function (name) {
  Object.defineProperty(exports, name, {
    get: function () {
      throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
    },
    configurable: true
  });
});

相关文章

网友评论

      本文标题:Object.defineProperty()

      本文链接:https://www.haomeiwen.com/subject/vrydihtx.html