Use Object.defineProperty () define property accessor behavior

Foreword

Object.defineProperty () is an API that can define the characteristics of the object property specified in ES standard, the reason will think this is because in the previous API instanceof explore the details of the article, the right of the function you want to Symbol.hasInstance properties redefined, but no matter how definitions are not entered into force. Specific code as follows:

var A = function() {};
var a = new A();

console.log('Symbol.hasInstance修改之前', a instanceof A)

A[Symbol.hasInstance] = function() {
    return false;
};

console.log('Symbol.hasInstance修改之后', a instanceof A)
复制代码

Code Portal

Not sure print the results of the students, if A is a set of Symbol.hasInstance can change detection result instanceof keyword doubt I can make reference to another article instanceof use may have missed a little detail , if only for the second print questionable results can continue to read on.

First answer the above questions

Here you can define two results foreword code printing are the same, are true. Understand the students know when we define Symbol.hasInstance properties of an object, we can customize the instanceof returns the result of the function. In the above code I set the direct return false, that is to say as long as the function of my property to take effect, the results of the second printing should be false fishes.

console.log(Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance));   
// {
//   configurable: false,
//   enumerable: false,
//   value: function [Symbol.hasInstance]() { [native code] },
//   writable: false
// }

var a = function() {}
console.log(Object.getOwnPropertyDescriptor(a, Symbol.hasInstance)) // undefined

a[Symbol.hasInstance] = function() {
    return false;
};
console.log(Object.getOwnPropertyDescriptor(a, Symbol.hasInstance)) // undefined
复制代码

Code Portal

I was a little hard to understand at the beginning, then realized that was set writable Symbol.hasInstance property is false on the prototype object function object, the results are well above the code to verify this. But property values ​​set on feature prototypes Why inherited prototype object objects can not set this property does, the good look Object.defineProperty () of the specific characteristics.

Characteristic property values ​​may be used

Here are the characteristics attribute may be used:

  1. configurable: characterize this attribute value may be changed if the default is false
  2. enumerable: Describes whether the attribute can be enumerated, i.e. use for ... in, for ... of whether the attribute may traverse the default is false
  3. value: Description Value returned if the attribute value is acquired, defaults to undefined
  4. writable: whether the value of the property described by re-assignment = default is false
  5. get: description for the function called when the property value, and returns the result of the function, the default is undefined
  6. set: description of the function called when the property is assigned, the default is undefined

Properties of the object can be divided into two categories, one is a direct property set value is called data descriptor, are most of the time we use data descriptor; the other is the access descriptor is setter- property getter function described. Actually it generates these two types of properties, because of the different property values ​​of its characteristic use.

General eigenvalues

1 and 2 above characteristic value characteristic value types of object properties may be used

configurable

The main effect of the feature value is described characteristic value of this attribute is set to N may be modified, default is false, that is, this value is not set true, the characteristic value of the property can no longer be defined, then defined words being given, the following specific reference codes and the results.

var a = {};
Object.defineProperty(a, 'confName', {
    configurable: true,
    value: 3
});
console.log('a.confName的特征描述值', Object.getOwnPropertyDescriptor(a, 'confName'));
Object.defineProperty(a, 'confName', {
    value: 5
})
console.log('a.confName的值', a.confName);  // 5

Object.defineProperty(a, 'name', {
    value: 3
});
console.log('a.name的特征描述值', Object.getOwnPropertyDescriptor(a, 'name'));

Object.defineProperty(a, 'name', {
    value: 5
}); // 不出意外这句会报错

复制代码

Code Portal

Tips: this code on a writable small details will be explained in the descriptor data section.

enumerable

The eigenvalues ​​do not have much to say, it is to define whether the property is enumerable. Rough point, is that when we use for ... of, for ... in other means to traverse the object properties if you can get to the property. If it is true that when enumerable enumeration is not false.

Data Descriptor

If the object feature value using the attribute value or writable, then the object attribute data descriptor belongs.

value

This value describes what property value, which value can be any data type specified in JS.

writable

This is a more interesting feature value, whether the data which can be described as a descriptor value may be used. Assignment modified true to be modified, can not be amended to false, data descriptor in the default value is false.

The interesting point here is that when you set writable is false is not guaranteed and the value of the property will not be modified, but must cooperate fully configurable is false can not be modified to ensure that property. The above highlighted whether value can be used. Modify the assignment , except in this way we can also use the configurable sample code in a way to modify the value of a property. Specific reference to the following codes:

var b = {};
Object.defineProperty(b, 'name', {
    configurable: true,
    value: 3
});
b.name = 9;
console.log('使用 = 重新赋值b.name', b.name);   // 3 对象属性不可 . 赋值修改时,不会报错,只是值不会发生改变 

Object.defineProperty(b, 'name', {
    value: 9
});
console.log('使用definePeoperty重新赋值b.name', b.name);    // 9 赋值成功
复制代码

Code Portal

Access Descriptor

If the features of the object attribute values ​​use the get or set, then access to the object descriptor attribute belongs.

get and set in this

It is worth noting that when we use this in and get set in, this is bound to use the property of the current object. Not necessarily set the value of the object, which is a property of an object a name and get set up set, this object is the prototype of b by another object, when you set the name attribute on b, set in the function call this is bound to it, instead of setting the characteristic value of a. On the following codes:

var c = {};
Object.defineProperty(c, 'name', {
	get: function() {
		return this.test
	},
	set: function(value) {
		this.test = value;
	}
});
var b = {};
Object.setPrototypeOf(b, c);
b.name = 'b';   // 此处会调用name属性的set函数
                // 会将'b'赋值给this.test,而this绑定的是b
                // 所以相当于在b上设置了test属性并赋值为'b'

console.log('b.name', b.name);  // b 出现这个结果是因为调用了name属性设置的get函数
                                //get函数返回结果是this.test而this绑定的是b
console.log('b.test', b.test);  // b 这个test属性是设置在b对象上的
console.log('c.name', c.name);  // undefined
console.log('c.test', c.test);  // undefined

var s = 's';
var d = {};
Object.defineProperty(d, 'name', {
	get: function() {
		return s
	},
	set: function(value) {
		s = value
	}
});
var e = {};
Object.setPrototypeOf(e, d);
e.name = 'e';   // 此处会调用set函数,set函数将s赋值为'e'

console.log('s的值', s);    // 'e' 变量s的值因为set函数的调用,而被设置为'e'
console.log('e.name', e.name);  // 'e' 此处的name属性不是在对象e上的
                                //而是通过委托查询到的其原型对象d上的那么属性调用get函数返回的值
console.log('d.name', d.name);  // 'e' 此处name属性是在对象d上真实存在的
复制代码

Code Portal

Chestnuts can be seen above, the function will be called upon to set or get the prototype object when the object is the get or set a property set function of the object and then use the property, which is similar to the effect of calling set.call (b, value), specifies this is the current object, but the function call or set of functions that property on an object prototype.

You can not use

If a descriptor does not have value, writable, get and set any keyword, then it will be considered a data descriptor. If a descriptor while (value or Writable) and (get or set) key, an exception will be generated.

Inherited characteristic values

Eigenvalues ​​properties of the object set is likely to be its prototype object inheritance, whether in an assignment or in acquiring value, they are likely to have an impact.

value and writable inheritance

Inherited here refers to an object to set a property, set the property will be affected characteristic value of the property on its prototype object settings.

When writable set to false, in order to set the property of an object as the prototype of an object will not be set when setting the value of the property, which does not produce an error, but the property has been set invalid.

var f = {};
Object.defineProperty(f, 'name', {
	value: 'f'
});
var g = {};
Object.setPrototypeOf(g, f);

console.log('g.name', g.name);  // 'f'
g.name = 'g';
console.log('g.name', g.name); // 'g'
复制代码

Code Portal

Only writable is set to false, writable exhibit inheritance, and is true there is no impact on its prototype object. We usually set directly writable object attribute is true, recall the usual use is really no case can not set the object properties.

var a = {
	name: 'a'
}
a.id = 'a';
console.log(Object.getOwnPropertyDescriptor(a, 'name'))
//configurable: true
//enumerable: true
//value: "a"
//writable: true
console.log(Object.getOwnPropertyDescriptor(a, 'id'))
//configurable: true
//enumerable: true
//value: "a"
//writable: true
var b = {};
Object.setPrototypeOf(b, a);
console.log(b.name);    // 'a'
b.name = 'b';
console.log(b.name);    // 'b'
console.log(a.name);    // 'a'

复制代码

inheritance value mainly in the prototype chain of inheritance (prototypal inheritance is, I can refer to one another to understand the prototype is actually understanding the prototype chain ).

set and get inheritance

set the value of the property and get the same features is a succession, and inheritance and writable different conditions, get set and will always be inherited, as long as the object is to set the properties of the eigenvalues ​​of the prototype object, the object set or would call the get and set functions on the prototype getting value of the property.

var hValue;
var h = {};
Object.defineProperty(h, 'name', {
	set: function(value) {
	    console.log('h set调用');
	    hValue = value;
	},
	get: function() {
	    console.log('h get调用')
	    return hValue;
	}
});

var i = {};
Object.setPrototypeOf(i, h);
i.name = 'i';   // 会调用h上的set打印'h set调用'
i.test = 'testi';   
console.log('hValue', hValue);  // 'i'
console.log('i.name', i.name);  // 'i' 会调用h上的get打印'h get调用'
console.log('h.name', h.name);  // 'i' 会调用h上的get打印'h get调用'

var jValue;
var j = {};
Object.defineProperty(j, 'name', {
	get: function() {
	    console.log('j get调用')
	    return jValue;
	}
});

var k = {};
Object.setPrototypeOf(k, j);
k.name = 'k';   // 会调用h上的set打印'h set调用'
k.test = 'testk';   
console.log('jValue', jValue);  // 'k'
console.log('k.name', k.name);  // 'k' 会调用h上的get打印'j get调用'
console.log('j.name', j.name);  // 'k' 会调用h上的get打印'j get调用'

复制代码

Code Portal

h is the prototype object i, h the name attribute of get and set functions, i make this setting on an object is no longer available. The name attribute is assigned, it will only look for the prototype commissioned by getting to the name attribute value h the name. If Object.defineProperty on i () so to define a property, then this attribute can be defined on the object of i.

var hValue;
var h = {};
Object.defineProperty(h, 'name', {
	set: function(value) {
	    console.log('h set调用');
	    hValue = value;
	},
	get: function() {
	    console.log('h get调用')
	    return hValue;
	}
});

var i = {};
Object.setPrototypeOf(i, h);
var iValue;
Object.defineProperty(i, 'name', {
	set: function(value) {
	    console.log('i set调用');
	    iValue = value;
	},
	get: function() {
	    console.log('i get调用')
	    return iValue;
	}
});   
i.name = 'i';   // 会调用i上的set函数,打印'i set调用'
console.log('iValue', iValue);  // 'i'
console.log('i.name', i.name);  // 'i' 会调用i上的get打印'i get调用'
console.log('h.name', h.name);  // 'i' 会调用h上的get打印'h get调用'
复制代码

Code Portal

Through Object.defineProperty () is still set object properties comply with the rules of the prototype inheritance, property values ​​will start to find the object itself to find properties, if not look through the prototype chain look up, look up to the top of the prototype chain, and setting object properties It can only be set to the object itself. But this prototype inheritance is based on the property of the child object is also defined by Object.defineProperty attributes ().

in conclusion

Object.defineProperty () defined attributes to some extent to the program can provide an interface to define property accessor behavior.

value may be defined when the value of the acquired property access obtains object properties, writable property can define whether to use the value of the attribute set access is allowed; get may be defined to do some additional property access operation obtains object properties, set can when carried out using the property accessor to assign object properties define additional operations, such as the use of two-way binding mechanism VUE2 in.

In fact, inheritance features of attribute values ​​manifested in getting the property value is consistent with the prototype inheritance, inheritance and prototype prototype difference is that in using the property accessor to the object property assignment when, writable a property of the prototype object to false will be their child objects inherit the lead to child objects can not be used to re-assign the property accessor properties can not set properties on child objects; set a property on the prototype will be inherited by child objects, the child objects using the property accessor to set the property of an object It calls on the prototype function when set to complete the assignment. Finally, when the property of the object and its child objects prototype is () defined by Object.defineProperty, characterized in that the value does not exhibit the property of inheritance.

Guess you like

Origin blog.csdn.net/weixin_33736048/article/details/91365431