Object.defineProperty()的学习

本文详细解析了Object.defineProperty方法,探讨其在属性定义、修改及访问器描述符的应用,揭示了前端开发中双向数据绑定等高级特性的底层实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2019年养成记录笔记的习惯,好好学习前端知识

vue的双向数据绑定,const实现原理,很多知识点都和Object的这个方法紧密相关,所以查看了MDN API 文档,记录学习

介绍

Object.defineProperty()是Object的静态方法,作用是可以给对象定义新属性,或修改已经存在的属性,并返回该对象。
可以直接在Object构造函数上调用此方法,而不是在Object类型的实例上调用此方法。
复制代码

语法

Object.defineProperty(obj, prop, descriptor)

参数: 1. obj:  需要定义或修改属性的对象自身
       2. prop: 需要定义或者修改属性的名称
       3. descriptor:  属性所拥有的一些特性
返回值: 被修改了属性或新增属性的对象自身 
复制代码

描述

desciptor: 给对象的属性添加特性描述,目前提供两种形式:数据描述和访问器描述(getter-setter)。
描述符必须是这两种风格之一,不能两者兼而有之,下面会分别介绍

数据描述和访问器描述都是对象,他们存在共同的可选属性:
1. configurable: 目标属性是否可被删除或者可再次修改特性 true | false (default: false)
2. enumerable: 目标属性是否可以被枚举。true | false,也就是是否可以用 for····in,或 Object.keys()获取,(default: false)

数据描述符才存在的可选属性:
1. value: 属性对应的值,可以使任意类型的值.(default: undefined)
2. writable: 是否可以使用赋值运算符更改属性的值 true | false (default: false)

访问器描述才存在的可选属性:
1. get: 属性getter的函数(default: undefined), 是一种获取属性值的方法
2. set: 属性setter的函数(default: undefined), 是一种设置属性值的方法

note: 直接在对象上定义的属性,writable, configurable, enumerable默认值为true。eg
var o = {};
0.name = "test";
name的上面上个描述如为true;这就是点操作符和用Object.defineProperty()的不同
复制代码

使用

新增属性

当对象中不存在指定的属性时,Object.defineProperty()将按照描述创建新属性。
eg: //使用数据描述新增属性
var o = {}; // Creates a new object
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
//'a' 属性就存在了o对象上,并且值为37

如果用访问器描述新增属性,则:
var bValue = 38;
Object.defineProperty(o, 'b', {
  get() { return bValue; },
  set(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});
o.b;//38;
复制代码

修改属性

writable属性(false代表属性值不可以更改)

var o = {}; // Creates a new object
Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); // 37
o.a = 25; // 不会抛出错误,但是也并不会生效
// (在严格模式下会抛出错误,即使赋值是和以前一样的也会抛出错误)
console.log(o.a); // logs 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 直接报错了
}());
复制代码
Enumerable 属性(Object.assign()或spread运算符是否选择该属性,for····in循环和Object.keys()是否可以获取该属性)
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 defaults to false,默认是false

o.d = 4;//enumerable defaults to true ,上面有提到过,直接在对象上定义属性,这几个描述符属性默认值为true

// Symbol是ES6引入的一种新的原始数据类型,表示独一无二的值。后面我会好好学习
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);
}
Object.keys(o); // ['a', 'd']
//logs 'a' and 'd', 所以用Symbol定义的属性,无论enumerable设置的是false还是truefor···in都循环不出来
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
复制代码
Configurable 属性(控制是否可以从对象中删除属性以及是否可以再次更改属性的特性)
var o = {};
Object.defineProperty(o, 'a', {
  get() { return 1; },
  configurable: false
});

Object.defineProperty(o, 'a', {
  configurable: true
}); // Uncaught TypeError: Cannot redefine property: a

Object.defineProperty(o, 'a', {
  enumerable: true
}); // Uncaught TypeError: Cannot redefine property: a
复制代码
getter and setter
function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get() {
      console.log('get!');
      return temperature;
    },
    set(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
//所以可以劫持setter和getter做很多事情,so const这些的原理应该知道了
复制代码
思考定义在原型上的属性
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
复制代码
function myclass() {
}

Object.defineProperty(myclass.prototype, "x", {
  get() {
    return this.stored_x;
  },
  set(x) {
    this.stored_x = x;
  }
});

var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined
复制代码

转载于:https://juejin.im/post/5c2ed65151882523730a2cd8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值