Deep Understanding of JavaScript Objects Series 3 - Mysterious Property Descriptors

previous words

For files in the operating system, we can easily set them to read-only, hidden, system files, and normal files. For objects, property descriptors provide a similar function to describe the value of the property in the object, whether it can be configured, whether it can be modified, and whether it can be enumerated.

First, the attribute descriptor type:

There are two types of property descriptors for objects: data properties and accessor properties.

data attribute

A data property contains the location of a data value where the value can be read and written. Data attributes have 4 properties.
[1]: Configurable (configurability)
Configurability determines whether the property can be deleted using delete, and whether the properties of the property descriptor can be modified. The default is true.
[2]: Enumerable (enumerable)
Enumerability determines whether the attribute appears in the attribute enumeration of the object, such as whether the attribute can be for-intraversed and returned through a loop. The default value is true.
[3]: writable (writable) Writability
determines whether the value of the attribute can be modified, the default is true.
[4]: value (attribute value)
The attribute value contains the data value of this attribute. When reading the attribute value, read from this position; when writing the attribute value, save the new value in this position. The default value is undefined.

accessor property

Object properties are made up of a name, a value, and a set of property descriptors. The property value can be replaced by one or two methods, getter和setterand this type of property is called an accessor property.

[1]: Configurable (configurability)
Configurability determines whether the property can be deleted using delete, and whether the properties of the property descriptor can be modified. The default is true.
[2]: Enumerable (enumerable)
Enumerability determines whether the attribute appears in the attribute enumeration of the object, such as whether the attribute can be for-intraversed and returned through a loop. The default value is true.
[3]: The function called by the getter
when the property is read. The default value is undefined.
[4]: The function called by the setter
when writing the property value, the default value is undefined.

Unlike data properties, accessor properties are not Writable. A property is a read/write property if it has both getter and setter methods. If it only has getter methods, then it is a read-only property. If it only has setter methods, then it is a write-only property. Read, write-only properties (meaning no value is written) always return undefined.

Descriptor details

Writable (writable): Determines whether the value of the property can be modified, the default is true.
var o = {a:1};
o.a = 2;
console.log(o.a);//2

When writable is set, the assignment statement will be invalid.

var o = {a:1};
Object.defineProperty(o,'a',{
    writable:false
});
console.log(o.a);//1
//由于设置了writable为false,所以o.a=2这个语句会静默失效
o.a = 2;
console.log(o.a);//1
Object.defineProperty(o,'a',{
    writable:true
});
//由于writable设置为true,所以o.a可以被修改为2
o.a = 2;
console.log(o.a);//2

In strict mode, assigning a value to a property whose writable is false through an assignment statement will prompt a type error TypeError.

'use strict';
var o = {a:1};
Object.defineProperty(o,'a',{
    writable:false
});
//Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'
o.a = 2;

[Note]: After setting writable: false, changing the value of the property value through the Object.defineProperty() method will not be affected, because this also means that the property value of writable is reset to false (currently it is not very important to this sentence). understand)

var o = {a:1};
Object.defineProperty(o,'a',{
    writable:false
});
console.log(o.a);//1
Object.defineProperty(o,'a',{
    value:2
});
console.log(o.a);//2
Configurability (configurable): Configurability determines whether the property can be deleted using delete, and whether the properties of the property descriptor can be modified. The default value is true.

[1]: After setting configurable:false, you cannot use delete to delete the property.

var o = {a:1};
Object.defineProperty(o,'a',{
    configurable:false
});
delete o.a;//false
console.log(o.a);//1

Deleting the configurable:false property in strict mode will raise a TypeError of the wrong type.

'use strict';
var o = {a:1};
Object.defineProperty(o,'a',{
    configurable:false
});
//Uncaught TypeError: Cannot delete property 'a' of #<Object>
delete o.a;

[Note]: When using the var command to declare a variable, the variable's configurable is false.

var a = 1;
//{value: 1, writable: true, enumerable: true, configurable: false}
Object.getOwnPropertyDescriptor(this,'a');

In general, after setting configurable: false, the defineProperty() method can no longer be used to modify the property descriptor.

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

With one exception, setting Configurable:false only allows the writable's state to change from true to false.

var o = {a:1};
Object.defineProperty(o,'a',{
    configurable:false,
    writable:true
});
o.a = 2;
console.log(o.a);//2
Object.defineProperty(o,'a',{
    writable:false
});
//由于writable:false生效,对象a的o属性无法修改值,所以o.a=3的赋值语句静默失败
o.a = 3;
console.log(o.a);//2

Enumerable (enumerable): Enumerability determines whether the property appears in the enumeration properties of the object, specifically for-in循环、Object.keys()方法、JSON.stringify()方法whether the property will be retrieved.

User-defined normal properties are by default enumerable, while natively inherited properties are non-enumerable by default.

//由于原生继承的属性默认不可枚举,所以只取得自定义的属性a:1
var o = {a:1};
for(var i in o){
    console.log(o[i]);//1
}
//由于enumerable被设置为false,在for-in循环中a属性无法被枚举出来
var o = {a:1};
Object.defineProperty(o,'a',{enumerable:false});
for(var i in o){
    console.log(o[i]);//undefined
}

ropertyIsEnumerable(): Used to determine whether the properties of an object are enumerable.

var o = {a:1};
console.log(o.propertyIsEnumerable('a'));//true
Object.defineProperty(o,'a',{enumerable:false});
console.log(o.propertyIsEnumerable('a'));//false

get and set

get is a hidden function that is called when getting the property value. set is also a hidden function that is called when a value is set, and their default value is undefined. The get and set in Object.definedProperty() correspond to the get and set methods in the object literal, [note] getter and setter replace the value and writable properties in data properties. (I don't understand this sentence very well)
[1]: Assignment to an object that only sets the get method and does not set the set method will fail silently, and an error will be reported in strict mode.

var o = {
    get a(){
        return 2;
    }
}    
console.log(o.a);//2
//由于没有设置set方法,所以o.a=3的赋值语句会静默失败
o.a = 3;
console.log(o.a);//2
Object.defineProperty(o,'a',{
    get: function(){
        return 2;
    }
})
console.log(o.a);//2
//由于没有设置set方法,所以o.a=3的赋值语句会静默失败
o.a = 3;
console.log(o.a);//2

In strict mode, assigning to an accessor property without a set method will throw an error.

'use strict';
var o = {
    get a(){
        return 2;
    }
}    
console.log(o.a);//2
//由于没有设置set方法,所以o.a=3的赋值语句会报错
//Uncaught TypeError: Cannot set property a of #<Object> which has only a getter
o.a = 3;
'use strict';
Object.defineProperty(o,'a',{
    get: function(){
        return 2;
    }
})
console.log(o.a);//2
//由于没有设置set方法,所以o.a=3的赋值语句会报错
//Uncaught TypeError: Cannot set property a of #<Object> which has only a getter
o.a = 3;

[2]: If only the set method is set, but the get method is not set, the attribute value of the object is undefined.

var o = {
    set a(val){
        return 2;
    }
}    
o.a = 1;
console.log(o.a);//undefined
Object.defineProperty(o,'a',{
    set: function(){
        return 2;
    }
})
o.a = 1;
console.log(o.a);//undefined

[3]: Generally, get and set appear in pairs.

var o ={
    get a(){
        return this._a;
    },
    set a(val){
        this._a = val*2;
    }
}
o.a = 1;
console.log(o.a);//2
Object.defineProperty(o,'a',{
    get: function(){
        return this._a;
    },
    set :function(val){
        this._a = val*2;
    }
})
o.a = 1;
console.log(o.a);//2

Descriptor methods

The property descriptors were introduced earlier, and to set them, you need to use the descriptor methods. There are a total of 4 descriptor methods:

[1] Object.getOwnPropertyDescriptor(obj,name): Used to query the descriptor of a property and return it in the form of an object.

When querying the obj.a property, configurability, enumerability, and writability are all default true, and value is the property value of a.
When querying the obj.b property, because the obj.b property does not exist, this method return undefined

var obj = {a:1};
//因为是以对象字面量的形式定义的,所以未配置的属性描述符都是true.
//Object {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj,'a'));
//undefined
console.log(Object.getOwnPropertyDescriptor(obj,'b'));

[2]: Object.defineProperty(obj,name,desc): A property descriptor used to create or configure an object, and return the configured object.
When using this method to create or configure the descriptor of an object property, if the descriptor is not configured for the property, the descriptor defaults to false.

var obj = {};
//{a:1}
console.log(Object.defineProperty(obj,'a',{
        value:1,
        writable: true
    }));

//由于没有配置enumerable和configurable,所以它们的值为false
//{value: 1, writable: true, enumerable: false, configurable: false}
console.log(Object.getOwnPropertyDescriptor(obj,'a'));

[3] Object.defineProperty(o,desc): Descriptors used to create or configure multiple properties of an object, and then return the configured object.

  var obj = {
        a:1
    };

    console.log(Object.defineProperties(obj,{
        a:{writable:false},
        b:{value:2}
    })); //{a: 1, b: 2}

    console.log(Object.getOwnPropertyDescriptor(obj,"a"));
    //{value: 1, writable: false, enumerable: true, configurable: true}
   //由于这个属性是直接在程序中定义的,所以当不去配置其余属性描述符是默认为true
    console.log(Object.getOwnPropertyDescriptor(obj,"b"));
    //由于这个属性是以属性描述符的形式定义的,所以当不去人为的配置的时候,默认都是false.
    //{value: 2, writable: false, enumerable: false, configurable: false}

[4]: Object.create(proto, desc) uses the specified prototype and properties to create an object.

 var o = Object.create(Object.prototype,{
        a: {
            writable :false, value: 1, enumerable: true
        }
    });

    console.log(Object.getOwnPropertyDescriptor(o,"a"));
    //{value: 1, writable: false, enumerable: true, configurable: false}
    //由于这个属性是以属性描述符的形式定义的,所以当不去人为的配置的时候,默认都是false.

object state

Property descriptors can only be used to control the state of a property in an object. And if you want to control the state of the object, you need to use the following 6 methods.

1. Object.preventExtensions() [prohibit extension]: Make an object unable to add new properties and return the current object.
2. Object.isExtensible() [Test whether it can be extended]: Used to detect whether the object can be extended.
var o = {a:1};
console.log(Object.isExtensible(o));//true
o.b = 2;
console.log(o);//{a: 1, b: 2}
console.log(Object.preventExtensions(o));//{a: 1, b: 2}
//禁止扩展,并且返回这个对象。
//由于对象o禁止扩展,所以该赋值语句静默失败
o.c = 3;
console.log(Object.isExtensible(o));//false
console.log(o);//{a: 1, b: 2}

In strict mode, adding a property to an object whose extension is prohibited will raise a TypeError.

'use strict';
var o = {a:1};
console.log(Object.preventExtensions(o));//{a:1}
//Uncaught TypeError: Can't add property c, object is not extensible
o.c = 3;

The Object.preventExtensions() method does not change the descriptor state of the properties in the object.

var o = {a:1};
//{value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
Object.preventExtensions(o);
//{value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
3. Object.seal() [object seal]

Object sealing, also known as object sealing, makes an object non-extensible and all properties are not configurable ( configurable:false), and returns the current object.

4. Object.isSealed() [Test Seal]: Used to detect whether the object is sealed.
var o = {a:1,b:2};
console.log(Object.isSealed(o));//false
console.log(Object.seal(o));//{a:1,b:2}
console.log(Object.isSealed(o));//true
console.log(delete o.b);//false
o.c = 3;
console.log(o);//{a:1,b:2}

In strict mode, deleting old properties or adding new properties will throw an error.

'use strict';
var o = {a:1,b:2};
console.log(Object.seal(o));//{a:1,b:2}
//Uncaught TypeError: Cannot delete property 'b' of #<Object>
delete o.b;

This method actually calls the Object.preventExtensions() method on the existing object and sets the configurabledescriptors of all existing properties to false.

var o = {a:1,b:2};
//{value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
console.log(Object.seal(o));//{a:1,b:2}
//{value: 1, writable: true, enumerable: true, configurable: false}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
5. Object.freeze() [object freezing]: Make an object non-extendable, non-configurable, and non-rewriteable, become a read-only constant that can only be enumerated, and return the current object.
6. Object.isFrozen() [Monitoring whether it is frozen]
var o = {a:1,b:2};
console.log(Object.isFrozen(o));//false
console.log(Object.freeze(o));//{a:1,b:2}
console.log(Object.isFrozen(o));//true
o.a = 3;
console.log(o);//{a:1,b:2}

In strict mode, deleting old properties, adding new properties, and changing existing properties will throw an error.

'use strict';
var o = {a:1,b:2};
console.log(Object.freeze(o));//{a:1,b:2}
//Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'
o.a = 3;//更改现有属性

This method actually calls the Object.seal() method on the existing object and sets the writable descriptor of all existing properties to false.

var o = {a:1};
//{value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
console.log(Object.freeze(o));//{a:1}
//{value: 1, writable: false, enumerable: true, configurable: false}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
//不可扩展,不可配置,也不可改写。

Reprinted from: Little Match's Blue Ideal
http://www.cnblogs.com/xiaohuochai/p/5613593.html
When reading the teacher's blog, I treat it as a book, so most of my blogs come from the teacher's blog The original words and examples, plus some of my own understanding, and made appropriate annotations, and some tests on the teacher's code.

Article label: In-depth understanding of javascript functions series 6 - higher-order functions

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325764213&siteId=291194637