Home  >  Article  >  Web Front-end  >  A brief discussion on the characteristics of JavaScript object properties and the defineProperty method

A brief discussion on the characteristics of JavaScript object properties and the defineProperty method

青灯夜游
青灯夜游forward
2019-11-30 16:51:032226browse

A brief discussion on the characteristics of JavaScript object properties and the defineProperty method

Object is a collection of unordered attributes, and these attributes are created with some characteristic values ​​(which can be understood as attributes of attributes, born with them). These characteristic values ​​are It is used by the JavaScript engine for implementation and therefore cannot be accessed directly by JavaScript.

JavaScript uses these characteristic values ​​to define the behavior of the attribute (whether the attribute is deleted, enumerated, modified, etc.).

For example, properties defined globally will be mounted on the window. When you want to delete this attribute on the window, it is not possible. In other words, the properties on the window are not configurable. delete window.obj //false

Function.prototype When you modify it to another value, its original value does not change. It is not writable.

For example, our for in can enumerate the properties on the prototype chain, but the top of all prototypes is Object.prototype. But for in does not enumerate it. So Object.prototype is not enumerable.

Attributes are divided into two types: 1 data attributes 2 accessor attributes. For example: Generally, the properties we set on objects are data properties by default, while the properties on Window are accessor properties.

How to know whether this property is a data property or an accessor property?

Use the Object.getOwnPropertyDescriptor (object where the property is located, property) method. Return an object. When the accessor attribute is used, the object attributes include enumerable, configurable, get, and set. At that time, the data attributes, the attributes returned by the object include value, writable, enumerable, configurable.

var obj  = {name:'zwq',age:18};
console.log(Object.getOwnPropertyDescriptor(obj,'name'));  //name属性属性
//{value: "zwq", writable: true, enumerable: true, configurable: true}

console.log(Object.getOwnPropertyDescriptor(window,'name'));  //window上的name属性时访问器属性
//enumerable: true, configurable: true, get: ?, set: ?}

Data attributes

●The upper row of data contains a data value Positions can read and write values. Data attributes have four attributes that describe their behavior. Since these values ​​cannot be accessed directly and are internal values, the specification puts them in two pairs of brackets.

● Whether the attribute is configurable: [[Configurable]]: Whether the table can delete the attribute through delete, modify the characteristics of the attribute, and whether the attribute can be modified as an accessor attribute

● Whether the attribute Enumerable: [[Enumerable]]: Can the table return attributes through a for-in loop?

● Whether the attributes can be modified: [[Writable]]

● Data value of the attribute: [ [value]] When reading attributes, read from this location. When writing attributes, save the new value to this location.

Generally defined attributes, the first three default values ​​are all true, and the last one is undefined.

When we want to modify the default characteristics of a property, use the Object.defineProperty (object where the property is located, the name of the property, descriptor object) method.

When the name of the second parameter property of the Object.defineProperty method does not exist, this method will create this property, and the default values ​​of the properties of this property except value are all false. That is to say, if you want the property created with the Object.defineProperty method to be enumerable, configurable, and writable like a normal property, you must change the properties of this property value to true. Otherwise it is false.

var obj  = {name:'zwq',age:18};

        Object.defineProperty(obj,'name',{ 修改name属性的特性,值为haha,并且name属性不能修改值
            value:'haha',
            writable:false  //默认值是true,改为false,不可写。
        })

        Object.defineProperty(obj,'sex',{创建一个sex属性,这个属性不可枚举
            value:'woman',
            writable:true,
            configurable:true,
        })

Accessor property

The accessor property does not contain writable and value, it contains a pair of getter and setter functions , when reading the accessor property, the getter function will be called and a valid value will be returned. When writing the accessor property (modifying the property), the setter function will be called and the new value will be passed in. The accessor contains 4 characteristics

● Whether the attribute is configurable: [[Configurable]]: whether the table can delete the attribute through delete, can modify the characteristics of the attribute, and can the attribute be modified as an accessor attribute

● Whether the attribute is enumerable: [[Enumerable]]: Whether the table can return the attribute through a for-in loop

● [[Get]]: The function called when reading the attribute. The default value is undefined.

●[[Set]]: Function called when writing (or modifying) attributes. The default value is undefined.

To define accessor properties, you must also use Object.defineProperty().

function Person(){
            this._name = 'zwq',
            this.age =  18
        }
        var person = new Person();
        
        
        Object.defineProperty(person,'name',{
            set(newValue){
                console.log('set');
                this._name = newValue   //设置或修改属性时,会调用set函数,把设置的值通过参数传进去后,用一个变量或属性保存。并且当调用get,return就是返回的这个值
            },
            get(){
                return this._name;   //当读取属性时 返回return的值
            }
            
        })

It is not necessary to specify both getter and setter. Specifying only getter means that the property cannot be written.

The principle of vue's two-way data hijacking binding (mainly used in forms) is to use Object.defineProperty to detect data changes.

When two-way hijack binding occurs, when the view (an element of the page) changes, the data changes accordingly. When the data changes, the view also changes. For example, when the content in the input box below changes, the data (object or array) changes. Detect data changes. The p text below changes according to the change of data.

As we introduced above, the set method will be triggered when the data changes. From this we can detect changes in the data.

//检测对象的变化。
     var input = document.getElementById('Oinput');
        var view = document.getElementById('view');

        var data = {
            valueObj :{
                value:'zwq'
            }
        }
        //当输入框数据发生改变时,数据跟着改变
        input.oninput = function(){
            data.valueObj.value = this.value;
        }
        
        // 更新视图
        function upData(){   
            view.innerText = data.valueObj.value;
        }
        
        upData(data);
        obServe(data);

        // 监控某个对象是否发生改变
        function obServe(data){
           //判断当前传的是否是对象,如果不是,直接return
            if(!data || !(data instanceof Object)){return data}
       //获取所有属性名。使用keys方法可以获取所有属性名(包括原型上的)并保存带数组中
            var arrProperty = Object.keys(data);
       //遍历数组,调用defindRective检测每一个属性值的改变 
            arrProperty.forEach(function(key){
          defindRective(data,key,data[key]); //传入3个参数,当前对象,当前属性,当前属性值
            })
        }

        function defindRective(obj,key,val){
           obServe(val);   //使用递归,当想上面的数组,对象套对象的形式,由于里面的对象是一个引用值,无法检测里面的数据变化,所以使用递归。
            Object.defineProperty(obj,key,{  //核心:使用Object,definPropert的set检测数据的改变。
                set(newValue){
                    console.log(5);
                    if(newValue == val) return val;
                    val = newValue;
                    upData();   //当数据变化,跟新视图
                },
                get(){
                    return  val;
                }
            })
        }
// 监测数组,将数组原型重写
// 当操作数组的arr push pop unshift slice...才会检测
        let {push} = Array.prototype;
        var arr = [1,2,3];
        function upData(){
            console.log('更新');
        }
        Object.defineProperty(Array.prototype,'push',{
            value:(function(){
                return (...arg) => {
                    upData();
                    push.apply(arr,arg);
                }
            })()
        })
 arr.push(8,9);

Due to the use of Object.defineProperty to detect changes in arrays and objects, they must be implemented separately. Moreover, when adding data, it will not be detected.

So Proxy was added to ES6 to achieve this.

Proxy&reflect简介:植入代理的模式,以简洁易懂的方式控制对外部对象的访问,利用set,get方法控制属性的读写功能,还有其余的has,desProperty。。等方法。但proxy兼容性不好,使用时要注意。

proxy是一个构造函数,通过代理的方式将你想到代理的对象传给构造函数,并且需要传入参数对象对读和写进行控制。使用new方法实例化代理的对象,

此后,当修改,或添加属性都使用代理的对象。

let data = {
    value:'zwq',
}
// let data = [1,2];
let oProxyData = new Proxy(data,{
    set(target,key,value,receiver){  //传入4个参数 对象 属性 属性值 代理的对象
        // target[key] = value;
        Reflect.set(target,key,value); //等同于上一步
        upData();
  },
    get(target,key,receiver){
        // console.log(target,key);
        Reflect.get(target, key);
    },
    has(target,key){ //当使用in时触发当前函数。
        return key in target;   //in --检测对象能否访问该属性,能访问返回true,不能false,无论是在实例还是原型中。
    }
});

console.log('valu' in oProxyData);

function upData(){
    console.log("更新啦");
}

oProxyData.value = 20;

本文来自 js教程 栏目,欢迎学习!

The above is the detailed content of A brief discussion on the characteristics of JavaScript object properties and the defineProperty method. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete