📜 ⬆️ ⬇️

ECMAscript 5: Objects and Properties

ECMAScript 5 is on its way. Resurrected from the ashes ECMAScript 4, which was pressed back to ECMAScript 3.1, which was later re-named ECMAScript 5 ( more ) - it comes with a new layer of functionality built on the basis of our favorite ECMAScript 3.

Announced several new APIs included in the specification, but the most interesting functionality lies in the code of objects and properties. This new code makes it possible to significantly influence how users can interact with objects, allowing them to provide getters and setters, prevent enumeration, manipulation, or deletion, and even prevent the addition of new properties. In short: you will be able to replicate and extend the existing set of APIs for JavaScript (for example, DOM) using JavaScript (without using anything else).

Very good news: These features should appear in all major browsers. All major browser vendors have worked on this specification, and have agreed to implement it in their products. The exact dates are not yet clear, but it is likely that they will be implemented soon.
')
Apparently, there is no full implementation of ES5 today, but several projects are already in the process of implementation. At the same time, you can read the ECMAScript 5 specification (PDF - in this article I discuss pages 107-109), or watch the latest discussions of the ECMAScript team on Google.
Note: I show some simple, exemplary implementations of these methods to illustrate how they could function. Almost all of them require other, new methods for correct operation - and they are not implemented in accordance with the 100% specification (for example, there are no error checks).

Objects


A new feature of ECMAScript 5 - the extensibility of objects can now be switched. Turning off extensibility can prevent new properties from being added to an object.

ES5 provides two ways to manipulate and verify the extensibility of objects:

Object.preventExtensions (obj), Object.isExtensible (obj)

preventExtensions blocks the object and prevents the creation of any new properties of the object in the future. isExtensible - the ability to determine whether the object is currently expanding or not.

Example of use:
var obj = {};
obj.name = "John" ;
print( obj.name );
// John

print( Object.isExtensible( obj ) );
// true

Object.preventExtensions( obj );

obj.url = "http://ejohn.org/" ; // Exception in strict mode

print( Object.isExtensible( obj ) );
// false


* This source code was highlighted with Source Code Highlighter .

Properties and Handles


Properties have been completely revised. They are now not simple values ​​associated with an object - now you have full control over how they can act. Great strength is nevertheless associated with increased complexity.

Properties of objects are divided into two parts.

The content of a property can be defined in two ways: value (property-data are traditional properties that we know and love in ECMAScript 3) or getter and setter (properties are “accessors” —we know them in some modern browsers, such as WebKit and gecko.

In addition, properties can be ...

In total, these various attributes make up a property descriptor. For example, a simple descriptor might look something like the following:
{
value: "test" ,
writable: true ,
enumerable: true ,
configurable: true
}


* This source code was highlighted with Source Code Highlighter .

Three attributes (writable, enumerable and configurable) are optional and all defaults to true. Thus, for a property, you definitely need to provide only either a value, or a getter and setter.

You can use the new Object.getOwnPropertyDescriptor method to get this information for an already existing Object.getOwnPropertyDescriptor property.

Object.getOwnPropertyDescriptor (obj, prop)

This method allows access to the property descriptor. It is the only way to get this information (in other words, the descriptors are not at the user's disposal - they do not exist as visible attributes of the property, they are stored inside in the ECMAScript engine).

Example of use:
var obj = { foo: "test" };
print(JSON.stringify(
Object.getOwnPropertyDescriptor( obj, "foo" )
));
// {"value": "test", "writable": true,
// "enumerable": true, "configurable":true}

* This source code was highlighted with Source Code Highlighter .


Object.defineProperty method (obj, prop, desc)

This method allows you to define a new property for an object (or change the descriptor of an existing property). This method takes a property descriptor and uses it to initialize (or update) the property.

Example of use:
var obj = {};
Object.defineProperty( obj, "value" , {
value: true ,
writable: false ,
enumerable: true ,
configurable: true
});

( function (){
var name = "John" ;

Object.defineProperty( obj, "name" , {
get: function (){ return name; },
set: function (value){ name = value; }
});
})();

print( obj.value )
// true

print( obj.name );
// John

obj.name = "Ted" ;
print( obj.name );
// Ted

for ( var prop in obj ) {
print( prop );
}
// value
// name

obj.value = false ; // Exception if in strict mode

Object.defineProperty( obj, "value" , {
writable: true ,
configurable: false
});

obj.value = false ;
print( obj.value );
// false

delete obj.value; // Exception


* This source code was highlighted with Source Code Highlighter .


Object.defineProperty is the base method of the new version of ECMAScript. In fact, all other important possibilities depend on the existence of this method.

Object.defineProperties (obj, props)

Defines several properties for an object at a time (instead of defining each one individually).

Sample implementation:
Object.defineProperties = function ( obj, props ) {
for ( var prop in props ) {
Object.defineProperty( obj, prop, props[prop] );
}
};


* This source code was highlighted with Source Code Highlighter .


Example of use:
var obj = {};
Object.defineProperties(obj, {
"value" : {
value: true ,
writable: false
},
"name" : {
value: "John" ,
writable: false
}
});


* This source code was highlighted with Source Code Highlighter .

Property descriptors (and their associated methods) are perhaps the most important new feature of ECMAScript 5. This gives developers the ability to control their objects very clearly, prevent unwanted modifications, and also support a single web-compatible API.

New opportunities



Some interesting new features have been introduced into the language using the extensions described above.

The following two methods are very useful for collecting arrays of all object properties.

Object.keys (obj)

Returns an array of strings representing the names of all enumerated properties of an object. Its behavior coincides with the behavior of the method from the library Prototype.js.

Sample implementation:
Object.keys = function ( obj ) {
var array = new Array();
for ( var prop in obj ) {
array.push( prop );
}
return array;
};


* This source code was highlighted with Source Code Highlighter .


Example of use:
var obj = { name: "John" , url: "http://ejohn.org/" };
print( Object.keys(obj).join( ", " ) );
// name, url


* This source code was highlighted with Source Code Highlighter .


Object.getOwnPropertyNames (obj)

Almost identical to Object.keys, but returns the names of all the properties of the object (and not just the enumerated ones).

An example implementation is not possible in ECMAScript 3, since non-enumerable properties cannot be listed. The return value and use is identical to Object.keys.

Object.create (proto, props)

Creates a new object that proto is a prototype of, and whose properties are set using Object.defineProperties (props).

A simple implementation would look like this (requires the new Object.defineProperties method):
Object.create = function ( proto, props ) {
var obj = new Object();
obj.__proto__ = proto;
if ( typeof props !== "undefined" ) {
Object.defineProperties( obj, props );
}

return obj;
};


* This source code was highlighted with Source Code Highlighter .


Note: The above code uses the Mozilla-specific _proto_ property. This property gives you access to the internal prototype of the object - and also allows you to set its value. In ES5, the Object.getPrototypeOf method allows access to this property, but does not allow it to be set — hence, the method above cannot be implemented in a general, ES-compatible manner.

I discussed Object.getPrototypeOf earlier , so I will not discuss it here again.

Example of use:
function User(){}
User.prototype.name = "Anonymous" ;
User.prototype.url = "http://google.com/" ;
var john = Object.create( new User(), {
name: { value: "John" , writable: false },
url: { value: "http://google.com/" }
});

print( john.name );
// John

john.name = "Ted" ; // Exception if in strict mode


* This source code was highlighted with Source Code Highlighter .


Object.seal (obj), Object.isSealed (obj)

Sealing the object prevents the code from deleting or changing the descriptors of any properties on the object, and prohibits adding new properties.

Example of implementation:
Object.seal = function ( obj ) {
var props = Object.getOwnPropertyNames( obj );

for ( var i = 0; i < props.length; i++ ) {
var desc = Object.getOwnPropertyDescriptor( obj, props[i] );

desc.configurable = false ;
Object.defineProperty( obj, props[i], desc );
}

return Object.preventExtensions( obj );
};


* This source code was highlighted with Source Code Highlighter .


You would prefer to seal an object if you want its set of existing properties to remain intact, without providing new additions, but at the same time allowing the user to edit their values.

Object.freeze (obj), Object.isFrozen (obj)

Freezing an object is almost identical to sealing, but with the addition that the properties become unchangeable.

Example of implementation:
Object.freeze = function ( obj ) {
var props = Object.getOwnPropertyNames( obj );

for ( var i = 0; i < props.length; i++ ) {
var desc = Object.getOwnPropertyDescriptor( obj, props[i] );

if ( "value" in desc ) {
desc.writable = false ;
}

desc.configurable = false ;
Object.defineProperty( obj, props[i], desc );
}

return Object.preventExtensions( obj );
};


* This source code was highlighted with Source Code Highlighter .


Freezing an object is the ultimate form of blocking. After an object has been frozen, it cannot be unfrozen — it cannot be changed in any form. This is the best way to make sure that your objects will remain exactly as you left them - indefinitely.

Together, these changes are very interesting, they give you an unprecedented level of control over the objects you create. The remarkable aspect is that you can use these features to create larger and more complex functions in pure ECMAScript (such as building new DOM modules, or moving most of the browser API to pure JavaScript). And since all browsers have JavaScript on board, this is absolutely what we look forward to.

- translator's note: descriptor is translated as a descriptor, although it can be translated as a descriptor. getter and setter do not have the same short and capacious definitions in Russian (the recipient of the value and the setter of the value), so the getter and setter slang are used.

Source: https://habr.com/ru/post/60234/


All Articles