Object attributes in js-configurable, writable, etc. (data attributes and accessor attributes)

Other related notes include the following:

1. Attribute type

After using object literals or constructors to instantiate objects and add properties and methods to them, these properties have some characteristic values ​​when they are created, and JavaScript defines the behavior of these properties through these characteristic values . The attributes in the object can actually be divided into two categories, namely data attributes and accessor attributes . The characteristics of these two types of attributes are somewhat different.

Data attributes

The data attribute contains the location of a data value. Values ​​can be read and written in this position. This type of attribute has 4 characteristics that describe its behavior .

  • [[ Value ]]: Contains the data value of this attribute. When reading an attribute, read from this location; when writing an attribute, save the new value in this location . The value of this feature is undefined by default.
  • [[ Writable ]]: Indicates whether the value of the attribute can be modified, that is, whether the value is writable or read-only .
  • [[ Enumaerable ]]: Whether the target attribute can be enumerated (traversed) .
  • [[ Configurable ]]: Indicates whether the attribute can be deleted through delete , the characteristics of the attribute can be modified , or the attribute can be modified as an accessor attribute.

Whether it is new plus constructor to instantiate an object or an object literally creates an object and adds properties to it, the [[Value]] characteristics of these properties are set to the value of the property, and changes to its value will reflect all This feature. And the values ​​of the other three properties of the attribute will be true by default .

If you need to modify the default properties of a property, you must use ES5's Object.defineProperty() method. It can define new attributes and set their characteristics or change the original characteristics of the attributes . Usage is as follows

// 三个参数均为必需参数 
Object.defineProperty(obj, prop, attributeDesc);
  • obj: the object where the attribute is located (target object)
  • prop: the name of the new or modified property defined
  • attributeDesc: attribute description object

There are two main points to note when using this method to create or modify object properties:

  1. If the configurable, enumerable, and writable attributes of the attribute are not specified when creating an attribute, the default values ​​are all false.
  2. Once the configurable attribute of an attribute is defined as false, it is not configurable, and the attribute cannot be changed back to configurable. After that, calling the Object.defineProperty() method to modify features other than the writable feature will cause an error. (JavaScript advanced programming)
    // uname 属性的可配置性、可枚举性、可写性默认都为 true
    var obj = {
    
    
        uname: '扬尘'
    };
    // 更改 value 和 writable 特性
    Object.defineProperty(obj, 'uname', {
    
    
        value: 'TKOP_',
        writable: false
    });
    console.log(obj.uname); // ->'TKOP_'
    obj.uname = '试试你能改不?';
    console.log(obj.uname); // ->'TKOP_'
    // 测试uname的可枚举性
    console.log(Object.keys(obj)); // ->['uname']
    Object.defineProperty(obj, 'uname', {
    
    
        enumerable: false
    });
    console.log(Object.keys(obj)); // ->[]

    // age 属性的可枚举性、可写性默认都是 false 。可配置性为true
    Object.defineProperty(obj, 'age', {
    
    
        value: 23,
        configurable: true
    });
    console.log(Object.keys(obj)); // ->[]
    obj.age = 18;
    console.log(obj.age); // ->23 回不去的18岁

The above is the code demonstration of the first point, and then the second point. It may be a little complicated, the demonstration process is complicated, and the general code is copied. Personal summary of the characteristics when using this method to configure these four characteristics again after the properties are set to non-configurable is as follows :

  • The writable feature can only be changed from true to false again, but not from false to true , which is different from the statement of "JavaScript Advanced Programming".
  • The configurable and enumerable features can be set to a constant value again without reporting an error, which has no practical meaning . But if you want to change these two features, you will get an error.
  • Whether an error is reported when the value property changes again depends on the writable property . If writable is true, no error will be reported when the value attribute is changed to any value. If writable is false, then the same value feature can only set the unchanged value again without reporting an error, which has no practical meaning . But if you want to change its value, an error will be reported.

If the summary is wrong, please leave a message in the comment area.

      var obj = {
    
    
        status: '1'
    };
    Object.defineProperty(obj, 'status', {
    
    
        value: '2',
        configurable: false,
        // enumerable: false,
    });
    obj.status = '2__';
    console.log(obj.status); // ->'2__'
    console.log(Object.keys(obj)); // ->['status']

    Object.defineProperty(obj, 'status', {
    
    
        value: '3',
        // enumerable: true,
        // enumerable: false,
        // configurable: false,
        // configurable: true,
        writable: false
    });
    obj.status = '3__';
    console.log(obj.status); // ->'3'
    console.log(Object.keys(obj)); // ->['status']

    Object.defineProperty(obj, 'status', {
    
    
        // writable: true
    })

Accessor properties

Accessor properties do not contain data values, they contain two functions, getter and setter (none of them are required). When reading an accessor property, a getter function is called, which is responsible for returning a valid value; when writing an accessor property, a setter function is called and a new value is passed in. This function determines how to process the data . This type of attribute also has the following four characteristics:

  • [[ Configurable ]]: Indicates whether the attribute can be deleted through delete , the characteristic of the attribute can be modified , or the attribute can be modified as a data attribute.
  • [[ Enumaerable ]]: Whether the target attribute can be enumerated (traversed) .
  • [[Get]]: The function to be called when reading attributes. The default value is undefined.
  • [[Set]]: A function called when writing attributes. The default value is undefined.
    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        get: function() {
    
    
            return this._year;
        },
        set: function(newValue) {
    
    

            if (newValue > 2004) {
    
    
                this._year = newValue;
                this.edition += newValue - 2004;
            }
        }

    });
    book.year = 2010; // 写入属性
    console.log(book.edition, book.year); // -> 7  2010

The above is the sample code in the book. The book object in the code has two default attributes edition (version) and _year attribute. The underscore in front of the _year attribute is a commonly used mark, which means that the attribute is only used for internal method access of the object . The other year attribute is an accessor attribute, and the set and get features of this attribute will be called respectively when writing and reading. The return value of calling get when reading is the value of the accessor attribute, calling set when writing makes the _year and edition change accordingly, this is also a common way to use accessor attributes, that is, setting a value will cause other attributes to change .

To better understand these two characteristics of accessor properties, I made some changes to the example. As follows, _year represents the year of publication and will not change. Assuming that a new version will be released every year in the future, that is, the edition attribute will change every year. Add an accessor property year to the book object. The return value of this property is the current year, and the edition is updated accordingly .

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        get: function() {
    
    
            return (new Date()).getFullYear();
        },
        set: function() {
    
    
            this.edition += this.year - this._year;
        }

    });
    book.year = 2010;
    console.log(book.edition, book.year); // -> 18 2021

There is another feature of the accessor attribute that is not reflected, that is, "the accessor attribute does not contain a data value " in the book . Does the year attribute above include the year? After having this idea, the following sample code appeared.

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        set: function() {
    
    
            this.edition += (new Date()).getFullYear() - this._year;
        }
    });
    book.year = 2010;
    console.log(book.edition, book.year); // -> 18 udefined

In the above code, only the [[Set]] feature of the year property is set, and undefined is returned when the year property is accessed. Only specify the properties of the setter function can not be read, otherwise it will return undefined (the book says that it will report an error in strict mode, but after trying it with your own hands, it seems that it still returns undefined). If only the [[Getter]] feature is specified, it means that the property is read-only and cannot be written, and will be ignored when trying to write, and an error will be reported in strict mode .

    "use strict";
    /*
    * 其他代码
    */
    book.year = 2010; // Uncaught TypeError: Cannot set property year of #<Object> which has only a getter

Not all browsers support the Object.defineProperty() method, so before that, two non-standard methods were used to add accessor properties. __defineGetter__() and __defineSetter__() can be used to create accessor properties and set [[Get]] and [[Set]] properties, but if the browser does not support the Object.defineProperty() method, the other two properties cannot be changed .

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    book.__defineGetter__('year', function() {
    
    
        return this._year;
    });

    book.__defineSetter__('year', function(newValue) {
    
    

        if (newValue > 2004) {
    
    
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    })
    book.year = 2010; // 写入属性
    console.log(book.edition, book.year); // -> 7  2010

2. Define multiple properties at the same time (defineProperties())

    var book = {
    
    };
    Object.defineProperties(book, {
    
    
        // 数据属性的定义
        _year: {
    
    
            writable: false,
            value: 2004
        },
        edition: {
    
    
            writable: true,
            value: 1
        },
        // 访问器属性
        year: {
    
    
            get: function() {
    
    
                return (new Date()).getFullYear();
            },
            set: function() {
    
    
                this.edition += (new Date()).getFullYear() - this._year;
            }
        }
    })

This method has the same compatibility with Object.defineProperty().

3. Object.getOwnPropertyDescriptor()

This method is used to read the four characteristics of a certain attribute of the object. Receive two parameters, the first parameter is the object where the attribute is located, and the second parameter is the name of the attribute that needs to be read. The return value is an object containing the four characteristics of the attribute.

    var attributes = Object.getOwnPropertyDescriptor(book, 'year');
    console.log(attributes.set); 
    var attributes = Object.getOwnPropertyDescriptor(book, '_year');
    console.log(attributes);

Insert picture description here

Guess you like

Origin blog.csdn.net/TKOP_/article/details/115018189