Original: http://www.2ality.com/2012/10/javascript-properties.html
There are three different types of properties in javascript: named data attributes (named Data properties), named accessor properties (named Accessor properties), and internal properties (internal property).
Named Data properties
This property is the "normal" attribute that we typically use, which is used to map a string name to a value. For example, the following object, obj, has a data property named string "prop", which has a value of 123.
var obj = {
PROP:123};
You can get (read) The value of a property:
Console.log (Obj.prop); 123console.log (obj["prop"]); 123
You can also set (write) the value of a property:
Obj.prop = "ABC";
obj["prop"] = "abc";
Named Accessor properties
Alternatively, you can use a function to get or set the value of a property. These functions are called accessor functions (accessor function). Accessor functions that control property reads are called getters. Accessor functions that control property writes are called Setters.
var obj = {
Get Prop () {
return "Getter";
},
Set Prop (value) {
Console.log ("Setter:" +value);
}
}
Let's manipulate the properties of obj :
> Obj.prop
' Getter '
> Obj.prop = 123;
Setter:123
Internal properties
Some properties are only used for specifications, called internal properties, because they are not directly accessible through JavaScript, but they do exist and affect the performance of the program. The names of the internal properties are special, and they are surrounded by two brackets. Here are two examples:
- The internal property [[[Prototype]] points to the prototype of the owning object. The value of this property can be read to by the object.getprototypeof () function . The value of this property can only be passed when a new object is created Object.create () or __proto__ to set [1].
- The internal property [[extensible]] Determines whether a new property can be added to the owning object. The value of this property can be read through object.isextensible () . You can also Object.preventextensions () Sets the value of this property to False. Once set to false, it is no longer possible to set back to true .
Attribute Properties
All States of a property, including its data and metadata, are stored in the attribute's attributes (attributes). properties have their own attributes, just as objects have their own properties. The name of the attribute is often written in the form of a similar internal property (double brackets).
Here are the attributes owned by the named Data property:
- [[Value]] stores the value of the property, which is the data of the property.
- [[writable]] stores a Boolean value that indicates whether the value of the property can be changed.
The following are the attributes owned by the named accessor property:
- [[Get]] stores the Getter, which is the function that is called when the property is read. The value returned by the function is the value of this property.
- [[Set]] stores the setter, which is the function that is called when the property is assigned a value. The function is passed to a parameter when it is called, and the value of the parameter is the new value assigned.
Here are the characteristics of both types of properties:
- [[[Enumerable]] stores a Boolean value. You can have a property that cannot be enumerated and hide itself under certain actions (explained in more detail below).
- [[Configurable]] stores a Boolean value. If False, you cannot delete this property, you cannot change most of the attributes (except [[Value]]), you cannot redefine a data property as an accessor property, or vice versa. In other words: [[ Configurable]] controls the writable nature of a property's metadata.
Default value
If you do not explicitly specify a value for an attribute, they will be assigned a default value:
Attribute name |
Default value |
[[Value]] |
Undefined |
[[Get]] |
Undefined |
[[Set]] |
Undefined |
[[Writable]] |
False |
[[Enumerable]] |
False |
[[Configurable]] |
False |
These default values are especially important for property descriptors.
Property descriptor
Property descriptor can encode all attributes of a property into an object and return it. Each property of the object corresponds to an attribute of the owning property. For example, the following is a property descriptor for a read-only property with a value of 123:
{
Value:123,
Writable:false,
Enumerable:true,
Configurable:false}
You can also use an accessor property to implement the above data property with a read-only attribute with the following property descriptor:
{ get:function () {return 123}, //no set, i.e. read -only enumerable:true, Configurable:false}
Functions that use property descriptors
The property descriptor is used when using the following function:
- Object.defineproperty (obj, propname, PropDesc)
Creates or alters the propname Propertyof the object obj, the attribute of thepropname property is given through the property descriptor Propdesc . Returns the modified Obj object. For example:var obj = Object.defineproperty ({}, "Foo", {
Value:123,
Enumerable:true //writable and configurable as default});
- Object.defineproperties (obj, propdescobj)
the batch version of Object.defineproperty () . Each property of the object Propdescobj specifies a property and corresponding property descriptor to add or modify to the original object, obj . For example:var obj = Object.definepropertys ({}, {
Foo: {value:123, enumerable:true},
Bar: {value: ' abc ', Enumerable:true}
});
- Object.create (Proto, Propdescobj?)
First, create a prototype object that is proto . Then, if an optional parameter propdescobjis provided, the property is added to the new object by object.defineproperties adding the property . Finally, returns the new object after the operation. For example, the following code creates an object that is exactly the same as the object created by the Object.definepropertys example above:var obj = object.create (Object.prototype, {
Foo: {value:123, enumerable:true},
Bar: {value: ' abc ', Enumerable:true}
});
- Object.getownpropertydescriptor (obj, propname)
Returns the property descriptor of the object obj named propname , which is not an inherited property. If you do not have this property, the undefinedis returned.> Object.getownpropertydescriptor (Object.prototype, "toString")
{value: [function:tostring],
Writable:true,
Enumerable:false,
Configurable:true}
> Object.getownpropertydescriptor ({}, "toString")
Undefined
Enumerable
This section explains what operations are affected by the enumerable nature of the property, and what does not. We first assume that we have defined objects such as proto and obj:
var proto = Object.defineproperties ({}, {
Foo: {value:1, enumerable:true},
Bar: {value:2, Enumerable:false}
});
var obj = Object.create (Proto, {
Baz: {value:1, enumerable:true},
Qux: {value:2, Enumerable:false}
});
It is important to note that all objects (including the protoabove) generally have at least one prototype object.prototype [2]:
> object.getprototypeof ({}) = = = Object.prototype
True
our commonly used built-in methods such as ToString and hasOwnPropertyis in fact defined on object.prototype .
Actions that are affected by enumerable
The enumerable affects only two operations: the for-in Loop and the Object.keys ().
The for-in loop iterates through the names of all the enumerable properties of an object, including inherited properties:
> for (var x in obj) console.log (x); No enumerable property is traversed on Object.prototype Quxbazfoo
Object.keys () returns all enumerable genera of an object Sex (Non-inherited) the name of the array that consists of :
> Object.keys (obj)
[' Baz ']
If you want to get all of your own properties, you should use object.getownpropertynames ().
Actions that are not affected by enumerable
In addition to the two actions above, the enumeration of properties is ignored by other operations. Some read operations use inherited attributes:
> "toString" in obj
True> obj.tostring
[Function:tostring]
There are also some operations that only consider their own properties:
> object.getownpropertynames (obj)
[' Baz ', ' Qux ']
> Obj.hasownproperty ("Qux")
True> obj.hasownproperty ("toString")
False> object.getownpropertydescriptor (obj, "Qux")
{Value:2,
Writable:false,
Enumerable:false,
Configurable:false}
> object.getownpropertydescriptor (obj, "toString")
Undefined
Create, delete, and define properties that affect only their properties:
Obj.propname = value
obj["propname"] = value
Delete Obj.propname
Delete obj["PropName"]
Object.defineproperty (obj, propname, desc)
Object.defineproperties (obj, descobj)
Best practices
The general rule is that the properties created by the system are not enumerable and user-created properties are enumerable:
> Object.keys ([])
[]
> object.getownpropertynames ([])
[' Length ']
> Object.keys ([' A '])
[' 0 ']
Especially for the methods on the prototype object:
> Object.keys (Object.prototype)
[]
> Object.getownpropertynames (Object.prototype)
[hasOwnProperty ',
' ValueOf ',
' Constructor ',
' toLocaleString ',
' isPrototypeOf ',
' propertyIsEnumerable ',
' ToString ']
Therefore, in your own code, you should not normally add attributes to the built-in prototype object, and if you have to do so, you should set this property to be non-enumerable to prevent other code from being affected.
As we can see, the benefit of non-enumeration is that it ensures that for-in statements in existing code are not affected by attributes inherited from the prototype. However, a non-enumerable property can only create an illusion that "for-in only iterates over an object's own properties". In your code, The use of for-in[3 should still be avoided as far as possible].
If you use an object as a string-to-value map, you should only manipulate its properties and omit the enumerable. There are many other pitfalls to consider in this case [4].
Conclusion
In this paper, we study the properties of attributes (called attributes). It is important to note that the JavaScript engine does not have to be an attribute to organize a property, They are primarily an abstract operation as defined in the ECMAScript specification. But sometimes these features are also explicitly in the language code, such as in the property descriptor.
Reference
- JavaScript: __proto__
- What object is a instance of object?
- Iterating over arrays and objects in JavaScript
- The pitfalls of using objects as maps in JavaScript
Properties of objects in JavaScript