「Object.defineProperty」 深入浅出

113 阅读3分钟

Object.defineProperty是什么?

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

语法

Object.defineProperty(obj, prop, descriptor)

参数

  • obj

    要定义属性的对象。

  • prop

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

  • descriptor

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

返回值

  • 被传递给函数的对象。

示例

返回值

 let obj1 = {
   name: "张三",
 };
 Object.defineProperty(obj1, "name", {
   value: "李四",
 });
 console.log(obj1);//{name: '李四'}

添加新的属性

  • configurable 可配置的
  • writable 可写的
  • enumerable 可枚举的

这仨属性是默认是false的 让我们先来演示一遍。

let obj1 = {
  name: "张三",
};
Object.defineProperty(obj1, "age", {
  value: 24,
  configurable: false,
  writable: false,
  enumerable: false,
});
console.log(obj1); //{name: '张三', age: 24}
//修改属性
obj1.age = 26;
console.log(obj1); //{name: '张三', age: 24}
//删除属性
delete obj1.age;
console.log(obj1); //{name: '张三', age: 24}
//for in 遍历
for (let i in obj1) {
  console.log(obj1[i]); //只打印了张三
}
//通过Object.key()来获取键 获取不到
console.log(Object.keys(obj1)); //['name']

//如果我们就是想获取里面的属性名怎么办呢  可以通过getOwnPropertyNames来获取自身的属性
console.log(Object.getOwnPropertyNames(obj1)); //['name', 'age']

//或者我们用来判断自身有没有age这个属性 可以通过hasOwnProperty来判断是否存在
console.log(obj1.hasOwnProperty("age")); //true

这仨设置为true重复上面操作,发现都是你想要的结果了。

get和set

因为getset的劫持 增加了操作的灵活性,可以在get、set方法里进行一些操作。

let obj1 = {
  name: "张三",
};
let value = null;
Object.defineProperty(obj1, "name", {
  get() {
    console.log("get!");
    return value;
  },
  set(newVal) {
    console.log("set!");
    value = newVal;
  },
});
obj1.name;//get!
obj1.name = "李四";// 'set!'
console.log(obj1.name); //李四

下面的例子展示了如何实现一个自存档对象。当设置temperature 属性时,archive 数组会收到日志条目。

function Archiver() {
  var temperature = null;
  var archive = [];
  Object.defineProperty(this, "temperature", {
    get() {
      return temperature;
    },
    set(value) {
      temperature = value;
      archive.push(temperature);
    },
  });
  this.getArchive = function () {
    return archive;
  };
}
var arc = new Archiver();
arc.temperature = 11;
arc.temperature = 12;
console.log(arc.getArchive()); // [11, 12]

描作符存在异常的情况

如果一个描述符同时拥有valuewritablegetset 键,则会产生一个异常。

  • 也就说valuewritable出现的地方,getset都不能出现
  • getset出现的地方,valuewritable都不能出现
  • 否则就会抛出一个异常
let obj1 = {};
Object.defineProperty(obj1, "name", {
  value: "张三",
  get() {},
});
//Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute

继承

一个不可写的属性被继承的话 继承过来之后还是不可写!

function Person() {}
Person.prototype.name = "张三";
Object.defineProperty(Person.prototype, "age", {
  writable: false,
  value: 8,
});
let p1 = new Person();
p1.name = "李四";
p1.age = 10;
p1.hobby = "Games";
console.log(p1); //{name: '李四', hobby: 'Games'}

与Object.defineProperties的区别

Object.defineProperties语法

该方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象,和Object.defineProperty类似,但参数不同

Object.defineProperties(obj, props)

区别

Object.defineProperties可以操作一个对象新增或修改多个属性

let sample1 = {};
Object.defineProperties(sample1, {
  prop1: {
    value: "Jerry",
    configurable: false,
    writable: false,
    enumerable: false,
  },
  prop2: {
    value: "Tom",
    configurable: false,
    writable: false,
    enumerable: false,
  },
});
sample1.prop1 = "Nacy";
sample1.prop2 = "Nacy";
console.log(sample1.prop1); //Jerry
console.log(sample1.prop2); //Tom

经典面试题

请在控制台打印'今天吃🍔'

if (a === 1 && a === 2 && a === 3) {
  console.log("success");
}
答案
let i = 1;
Object.defineProperty(window, "a", {
  get() {
    return i++;
  },
});
    
每次调用a的时候都会走到get方法里面,返回i++
    
if (a === 1 && a === 2 && a === 3) {
  console.log("今天吃🍔");
}