Object.defineProperty

Official note:

DefineProperty (obj,prop, Descriptor) Defines a new property on an Object, or modifies an existing property of an Object, and returns the Object. MDN

Popular understanding:

A javaScript object is a collection of properties. The basic feature of an object is a key-value pair, that is, the name of the property corresponds to the value of the property.

In ES5, attribute descriptors are added to describe or control different operations on object attributes.

Object. DefineProperty (obj,prop, Descriptor) and Object. DefineProperties (descriptorsObj) combine attribute descriptors to define attribute characteristics of objects.

It is also affected by methods such as Object.freeze and object.seal.

Attribute descriptor

As the name implies, it is a description of some characteristics of an object property.

Attribute descriptors are divided into the following two types:

Data descriptors: Value, Writable, Enumerable, freely configurable.

Access descriptors :getter functions, setter functions.

So how do I view object property descriptors? We can:

  • Object.getOwnPropertyDescriptor(obj,prop) MDN

    • Returns a property descriptor that specifies its own property on an object

    • The specified property of the object does not exist, returns undefined.

  • Object.getOwnPropertyDescriptors(obj) MDN

    • Returns a descriptor for all of an object’s own properties.

    • Object returns an empty object if it does not have any properties of its own.

    Own properties: Properties that are directly assigned to the object and do not need to be looked up on the stereotype chain.

Data Descriptors

Object properties are defined in a normal way

The property values of objects defined in the normal way are writable, enumerable, and configurable by default.

The normal way is to use the properties added by the dot operator or the properties that are declared with the object literal.

const obj = { name: 'csz'.age: 26 };

// Objects declared as object literals have properties that are writable, enumerable, and configurable by default.
Object.getOwnPropertyDescriptor(obj, 'name');
// {value: "csz", writable: true, enumerable: true, configurable: true} 

// The property descriptor for an object that does not have its own property returns undefined
Object.getOwnPropertyDescriptor(obj, 'money'); // undefined 

// Getting the descriptors for all attributes on an object returns the property descriptors for all attributes of the specified object in the form of an object.
Object.getOwnPropertyDescriptors(obj);
/ / {
// age: {value: 26, writable: true, enumerable: true, configurable: true},
// name: {value: "csz", writable: true, enumerable: true, configurable: true}
// } 

// Get all property descriptors of objects without any property of their own.
Object.getOwnPropertyDescriptors({}); / / {}
Copy the code
1. The value attribute value

Property value, whether can be reassigned based on writable, default undefined.

2. Writable can write

Whether the property can be reassigned.

const obj = { name: 'csz'.age: 26 };

obj.name = 'csz1';
obj.name; // 'csz1' 

Object.defineProperty(obj,'name', {value:'csz2'
})
obj.name; // 'csz2'
Copy the code
3. The enumerable can be enumerated

Can this attribute be used in for… Are enumerated in the in loop and object.keys (), Object.values(), object.entries ().

const obj = { name: 'csz'.age: 26 };

for(key in obj){
  console.log(key);
}
// name age

Object.keys(obj);
// ["name", "age"]

Object.values(obj);
// ["csz", 26]

Object.entries(obj);
// [["name", "csz"],["age", 26]]
Copy the code
4. The configurable can be configured

The descriptor of the property can be changed, and the property can also be deleted from the corresponding object by DELETE.

const obj = { name: 'csz'.age: 26 };

// Because the object literal declaration of obj defaults to writable, Enumerable, and different is true
// Change the name attribute to the following three descriptors
Object.defineProperty(obj,'name', {value:'csz1'.writable:false.enumerable:false,})// Check the name property descriptor again and find that the corresponding descriptor has been modified
Object.getOwnPropertyDescriptor(obj,'name');
// {value: "csz1", writable: false, enumerable: false, configurable: true}

// Delete the name attribute with delete. The name attribute is deleted successfully
delete obj.name; // true
obj;// {age: 26} 
Copy the code
Object.defineproperty defines the value of an Object attribute

Attribute values added via Object.defineProperty are by default non-writable, non-enumerable, and non-configurable.

const objcxk = {name:'cxk'};

// Add the Object. DefineProperty hobby to basketball
Object.defineProperty(objcxk,'hobby', {value:'basketball'
});

objcxk.hobby; // "basketball"

// View the added Hobby property descriptor
Object.getOwnPropertyDescriptor(objcxk,'hobby');
// {value: "basketball", writable: false, enumerable: false, configurable: false}
// Attribute values added via Object.defineProperty are not writable, enumerable, or configurable by default.

// No one can change my hobby
// TypeError is reported in strict mode
objcxk.hobby = 'singing';
objcxk.hobby; // 'basketball'

// Unenumerable hobby (I can only hide my love of basketball)
for(key in objcxk){
  console.log(key);
}
// name
Object.keys(objcxk);
// ["name"]

// Unconfigurable -- delete cannot delete hobby (does not abandon basketball)
delete objcxk.hobby; // false
objcxk; // {name: "cxk", hobby: "basketball"}

// Not configurable -- The Hobby property descriptor (for basketball) cannot be changed
Object.defineProperty(objcxk,'hobby', {value:'singing'.writable:true.enumerable:true.configurable:true});// Uncaught TypeError: Cannot re-define Property: Hobby


// Then look again at the Hobby property descriptor
Object.getOwnPropertyDescriptor(objcxk,'hobby');
// {value: "basketball", writable: false, enumerable: false, configurable: false}
// The property is false, and its descriptor cannot be changed. The property cannot be deleted from the corresponding object through delete


// View the property descriptors for all properties of the object
Object.getOwnPropertyDescriptors(objcxk);
/ / {
// hobby: {value: "basketball", writable: false, enumerable: false, configurable: false}
// name: {value: "cxk", writable: true, enumerable: true, configurable: true}
// }
// Except for Hobby, the property descriptor of the original property name is still writable, enumerable, and configurable by default
Copy the code
The special case that the signals are false

TypeError is raised if you try to change the value of non-configurable properties (except for the value and writable properties) unless the current value is the same as the new value. The only thing you can do is change writable to false in one direction.

configurable enumerable writable conclusion
false true/false false 1. The descriptor cannot be modified.

2. Value If the value is a basic type, no error message will be reported.

3. The value of a complex data type cannot be completely replaced, but some changes can be made inside it. For example, the array can be changed using methods such as push and splice, and its internal attributes can be changed if it is an object.
false true/false true You can redefine the value of value by changing writable to false.
const objcxk = {name:'cxk'};

Object.defineProperty(objcxk,'job', {value:'singer'.writable:true.enumerable:true.configurable:false}); objcxk.job;// 'singer'

// Can be written (actually I am an actor)
objcxk.job = 'performer';
objcxk.job; // 'performer'

---------------------------------------------------------------
  
// Writable true => false although not configurable
Object.defineProperty(objcxk,'job', {writable:false});// No longer writable (I am an actor)
objcxk.job = 'singer';
objcxk.job; // 'performer'

---------------------------------------------------------------

// It is neither configurable nor writable, rewrites with the original value, essentially unchanged and does not throw an exception
Object.defineProperty(objcxk,'job', {value:'performer'
})

// Throw an exception if it is any other value!!
Object.defineProperty(objcxk,'job', {value:'athlete'
})
// Uncaught TypeError: Cannot redefine property: job

-------------------------------------------------------------
 
// For complex data types, where values are stored differently, non-writable should be understood as non-replaceable
// Define a new hobby property with an array value that is not writable by default
Object.defineProperty(objcxk,'hobby', {value: ['sing'.'jump'.'basketball']
})
objcxk.hobby; // ["sing", "jump", "basketball"]
objcxk.hobby.push('playGame'); // The array is actually changed
objcxk.hobby; // ["sing", "jump", "basketball","playGame"]
objcxk.hobby = []; // Completely replacing a new array does not work
objcxk.hobby; // ["sing", "jump", "basketball","playGame"]
Copy the code

Access Descriptors

  • bygetterFunctions andsetterFunction that is called when the property is readget(), assignment callset(newValue).
  • (valuewritable) and (getset) are mutually exclusive. Both cannot exist at the same time; otherwise, an exception will be thrown.
  • ingetsetYou can’t change it again after you define it,thisPoints to the object whose properties are accessed and modified.
The data was hijacked

For example, setting a property value changes the value of other properties of an object. Returns the values of other properties when one property is fetched.

The underscore before // _hobby is a common notation used to indicate properties that can only be accessed through object methods
const obj = { name: 'cxk'._hobby:'basketball' };

// Define two property descriptors with Object.defineProperties
Object.defineProperties(obj, {
    hobby: {
        get: function () {
          	console.log(`get value:The ${this._hobby}`);
            return this._hobby; 
        },
        set: function (newValue) {
          	console.log(`set newValue:${newValue}`)
            this._hobby = newValue;
            // Notice what happens if you write it like this
            // this.hobby = newValue;
        }
      	// If get or set is defined, neither of the following can occur. Otherwise, an exception is reported
        // value:'',      
      	// writable:true, 
    },
    job: {
        value: 'singer'.writable: true}}); obj;// {name: "cxk", _hobby: "basketball", job: "singer"}
obj.hobby; // get value:basketball (hobby value comes from _hobby)
obj.hobby = 'dance'; // set newValue:dance (hobby is actually assigned to _hobby)
obj; // {name: "cxk", _hobby: "dance", job: "singer"}
Copy the code
The simplest two-way data binding
<! DOCTYPE HTML > < HTML lang="en"> <head> <title> <meta charset="UTF-8"> </head> <body> <div id="app"> <input type="text" id=" TXT ">< p id="show-txt"></p> </div> </body> Object.defineproperty (obj,' TXT ',{// define setter (triggered when data Object property value changes) set:function(newValue){document.getelementById (' TXT ').value = newValue document.getelementById ('show-txt').innerhtml = newValue}}) // Listen for keyboard events to assign values to data objects document.addEventListener('keyup',function(e){ obj.txt = e.target.value }) </script> </html>Copy the code
Setters and getters in ES6 classes

As in ES5, you can use the get and set keywords inside a “class” to set the store and value functions for an attribute and intercept the access behavior of that attribute.

// .ts
---------------------------------------------------------------
class MyClass{
  constructor(){}get prop() {return 'getter';
  }
  set prop(value) {console.log('setter:'+value); }}let inst = new MyClass();
inst.prop = 123; // setter:123
inst.prop; // 'getter'

---------------------------------------------------------------
/ / to js
var MyClass = / * *@class * / (function () {
    function MyClass() {}Object.defineProperty(MyClass.prototype, "prop", {
        get: function () {
            return 'getter';
        },
        set: function (value) {
            console.log('setter: ' + value);
        },
        enumerable: false.configurable: true
    });
    returnMyClass; } ());var inst = new MyClass();
inst.prop = 123; // setter:123
inst.prop; // 'getter'
Copy the code