Objects as associative arrays

Lecture




  1. Associative arrays
  2. Creating objects
  3. Object operations
    1. Access through square brackets
    2. Properties ad
      1. Nested objects in the ad
  4. Enumerate properties and values
    1. The number of properties in the object
    2. The order of the properties
  5. Transfer by reference
  6. Compact representation of objects
  7. Total

Objects in javascript are two-faced. They combine two important functional.

The first is an associative array: a structure suitable for storing any data. In this chapter, we will look at using objects as arrays.

The second is language capabilities for object-oriented programming. We will study these possibilities in the subsequent sections of the textbook.

Associative arrays

An associative array is a data structure in which you can store any data in key-value format.

It can be easily represented as a cabinet with signed drawers. All data is stored in boxes. By name, you can easily find the box and take the value that lies in it.

Unlike real cabinets, you can add new named “boxes” to an associative array at any time or delete existing ones. Next we will see examples of how this is done.

By the way, in other programming languages ​​such data structure is also called “dictionary” and “hash” .

Creating objects

An empty object ( “empty cabinet” ) can be created with one of two syntaxes:

1. o = new Object();
2. o = {}; // пустые фигурные скобки

Usually everyone uses the syntax (2) , because he is shorter.

Object operations

An object can hold any values ​​that are called object properties . Properties are accessed by property name (sometimes referred to as “by key” ).

For example, create a person object to store information about a person:

var person = {}; // пока пустой

Basic operations with objects are:

  1. Assigning properties by key.
  2. Reading properties by key.
  3. Deleting property by key.

To access the properties, use the “through point” entry, of the объект.свойство type:

01 var person = {};
02
03 // 1. присвоение
04 // при присвоении свойства в объекте автоматически создаётся "ящик"
05 // с именем "name" и в него записывается содержимое 'Вася'
06 person.name = 'Вася' ;
07
08 person.age = 25; // запишем ещё одно свойство: с именем 'age' и значением 25
09
10 // 2. чтение
11 alert(person.name + ': ' + person.age); // вывести значения
12
13 // 3. удаление
14 delete person.name; // удалить "ящик" с именем "name" вместе со значением в нём

Next operation:

  1. Check for the existence of a property with a specific key.

For example, there is a person object, and you need to check if the age property exists in it.

To check for existence, there is an in operator. Its syntax is "prop" in obj , and the name of the property is in the form of a string, for example:

1 var person = { };
2
3 if ( "age" in person ) {
4    alert( "Свойство age существует!" );
5 }

However, another way is often used - comparing the value with undefined .

The fact is that in JavaScript you can refer to any property of the object, even if it does not exist . There will be no error.

But if the property does not exist, then the special value undefined will be returned:

1 var person = {};
2
3 alert(person.lalala); // undefined, нет свойства с ключом lalala

Thus, we can easily check the existence of a property — by getting it and comparing it with undefined :

1 var person = { name: "Василий" };
2
3 alert(person.lalala === undefined ); // true, свойства нет
4 alert(person.name === undefined ); // false, свойство есть.

Difference between in and checks === undefined

There are two means for checking the presence of a property in an object: the first is the in operator, the second is to get it and compare it with undefined .

They are almost identical, but there is one small difference.

The fact is that it is technically possible that the property is and equals undefined :

1 var obj = {};
2 obj.test = undefined ; // добавили свойство со значением undefined
3
4 // проверим наличие свойств test и заведомо отсутствующего blabla
5 alert(obj.test === undefined ); // true
6 alert(obj.blabla === undefined ); // true

... At the same time, as can be seen from the code, with a simple comparison, the presence of such a property will be indistinguishable from its absence.

But the in operator guarantees the correct result:

1 var obj = {};
2 obj.test = undefined ;
3
4 alert( "test" in obj ); // true
5 alert( "blabla" in obj ); // false

As a rule, in the code we will not assign undefined , so that both checks work correctly. And as a value denoting uncertainty and uncertainty, we will use null .

Access through square brackets

There is an alternative syntax for working with properties, using the brackets объект['свойство'] :

1 var person = {};
2
3 person[ 'name' ] = 'Вася' ; // то же что и person.name
4
5 alert(person[ 'name' ]);
6
7 delete person[ 'name' ];

In square brackets you can pass a variable:
obj[key] uses the value of the key variable as the property name:

1 var person = { age: 25 };
2 var key = 'age' ;
3
4 alert(person[key]); // выведет person['age']

The person['age'] and person.age identical. On the other hand, if the name of a property is stored in a variable ( var key = "age" ), then the only way to access it is with square brackets person[key] .

Appeal through a dot is used if we already know the name of the property at the stage of writing the program. And if it is determined in the course of execution, for example, entered by a visitor and written into a variable, then the only choice is square brackets.

Property Name Restrictions
  • The name of the property when accessing "through the point" imposed syntactical restrictions - about the same as the variable name. It cannot begin with a number, contain spaces, etc.
  • When accessed through square brackets, you can use any string.

For example:

person[ 'день рождения!' ] = '18.04.1982' ;
// запись через точку "person.день рождения! = ..." невозможна

In both cases, the property name must be a string . If a value of another type is used, JavaScript will automatically string it.

Properties ad

An object can be filled with values ​​when created by specifying them in curly braces: { ключ1: значение1, ключ2: значение2, ... } .

This syntax is called literal (the original is literal ), for example:

  Objects as associative arrays

The following two code fragments create the same object:

01 var menuSetup = {
02      width: 300,
03      height: 200,
04      title: "Menu"
05 };
06
07 // то же самое, что:
08
09 var menuSetup = {};
10 menuSetup.width = 300;
11 menuSetup.height = 200;
12 menuSetup.title = 'Menu' ;

Property names can be listed in quotes or without quotes if they satisfy the constraints for variable names.

For example:

1 var menuSetup = {
2      width: 300,
3      'height' : 200,
4      "мама мыла раму" : true
5 };

Importance: 3

Mini-task on the syntax of objects. Write a code line by line for each action.

  1. Create an empty user object.
  2. Add the name property with the value of Вася .
  3. Add the surname property with the value Петров .
  4. Change the name value to Сергей .
  5. Remove the name property from the object.
Decision

1 var user = {};
2 user.name = "Вася" ;
3 user.surname = "Петров" ;
4 user.name = "Сергей" ;
5 delete user.name;

[Open task in new window]

Nested objects in the ad

The property value can be an object:

01 var user = {
02    name: "Таня" ,
03    age: 25,
04    size: {
05      top: 90,
06      middle: 60,
07      bottom: 90
08    }
09 }
10
11 alert( user.name ) // "Таня"
12
13 alert( user.size.top ) // 90

Here, the value of the size property is the {top: 90, middle: 60, bottom: 90 } object.

Object Output, Firefox

For debugging purposes, sometimes you want to display the entire object. Firefox has a non-standard toSource method for this.

1 var user = {
2    name: "Таня" ,
3    size: {
4      top: 90,
5      middle: 60
6    }
7 }
8
9 alert( user.toSource() ); // работает только в Firefox

In other browsers it is not, but the object can be viewed through the developer tools: debugger or console.log .

Enumerate properties and values

To iterate over all properties from an object, the loop is used for the properties for..in .. This is a special syntactic construct that does not work like a regular for (i=0;i<n;i++) loop for (i=0;i<n;i++) .

Syntax:

for (key in obj) {
   /* ... делать что-то с obj[key] ... */
}

In this case, the property names will be sequentially written in the key .

Variable declaration in a for (var key in obj) loop for (var key in obj)

Variables can be declared directly in the loop:

for ( var key   in menu) {
   // ...
}
So sometimes they write for short code.

For example:

01 var menu = {
02      width: 300,
03      height: 200,
04      title: "Menu"
05 };
06
07 for ( var key in menu) {
08      // этот код будет вызван для каждого свойства объекта
09      // ..и выведет имя свойства и его значение
10
11      alert( "Ключ: " + key + " значение:" + menu[key]);
12 }

Of course, instead of key can be any other variable name.

The number of properties in the object

There is no one method that would return the number of properties. Cross-browser method is to loop through the properties and count:

1 function getKeysCount(obj) {
2    var counter = 0;
3    for ( var key in obj) {
4      counter++;
5    }
6    return counter;
7 }

And this is how the function of checking for “emptiness” looks like:

1 function isEmpty(obj) {
2    for ( var key in obj) {
3      return false ; // если цикл хоть раз сработал, то объект не пустой => false
4    }
5    // дошли до этой строки - значит цикл не нашёл ни одного свойства => true
6    return true ;
7 }

The order of the properties

Are the properties ordered in objects? In theory, i.e. according to the specification - no. In practice, everything is more complicated.

Browsers adhere to an important agreement on how to iterate through properties. It, though not spelled out in the standard, but rather reliably, because a lot of existing code depends on it.

  • IE <9 browsers, Firefox, Safari scroll through the keys in the same order in which the properties were assigned.
  • Opera, modern IE, Chrome guarantee order preservation only for string keys. Numeric keys are sorted and go to string.

That is, if the properties in the object are string, then such an object is ordered. Properties will be sorted in the order of their assignment:

1 var user = {
2    name: "Вася" ,
3    surname: "Петров"
4 };
5 user.age = 25;
6
7 for ( var prop in user) {
8    alert(prop); // name, surname, age
9 }

Consider now the case when the keys are “numerical”. As we know, objects in JavaScript can have keys only as strings, but if the string is in integer form, some interpreters recognize this and process such keys differently.

For example, consider an object that specifies a list of options for selecting a country:

1 var codes = {
2    // телефонные коды в формате "код страны": "название"
3    "255" : "Танзания"
4    "7" : "Россия" ,
5    "38" : "Украина" ,
6    // ..,
7    "1" : "США"
8 };

We want to bring these options to the visitor in the same order, that is, "Tanzania" at the beginning, and "USA" - at the end (this is if our office is located in Zanzibar, then this order will be most relevant).

However, when browsing them through for..in some browsers (IE9 +, Chrome, Opera) will display the keys not in the order in which they are specified, but in a sorted order :

01 var codes = {
02    "255" : "Танзания" ,
03    "7" : "Россия" ,
04    "38" : "Украина" ,
05    "1" : "США"
06 };
07
08 for ( var key in codes) {
09    alert(key + ": " +codes[key]); // 1, 7, 38, 255 в IE9+, Chrome, Opera
10 }

Breaking the order arose because the keys are numerical. To bypass it, you can use a small hack, which is that all keys are artificially made lowercase. For example, add them the first additional character '+' .

In this case, the browser will consider the keys as string and preserve the brute force order:

01 var codes = {
02    "+255" : "Танзания" , // передаём 255 в виде строки, чтобы браузер сохранил порядок
03    "+7" : "Россия" ,
04    "+38" : "Украина" ,
05    "+1" : "США"
06 };
07
08 for ( var key in codes ) {
09    var value = codes[key];
10    var id = +key; // ..если нам нужно именно число, преобразуем: "+255" -> 255
11  
12    alert( id + ": " + value ); // 255, 7, 38, 1 во всех браузерах
13 }

Transfer by reference

Common values: strings, numbers, booleans, null/undefined copied "by value" .

This means that if the message variable stores the value "Привет" and it is copied with the phrase = message , then the value is copied, and we will have two variables, each of which stores the value: "Привет" . "Привет"

Objects are assigned and transmitted "by reference . "

The variable does not store the object itself, but a link to its place in memory. To better understand this - comparable to ordinary variables.

For example:

var message = "Привет" ; // значение в переменной

  Objects as associative arrays

And this is what the user = { name: "Вася" } variable looks like.

Attention: the object is outside the variable . In a variable, there is only a reference (“the address of the place in memory where the object lies”).

  Objects as associative arrays

When copying a variable with an object, this link is copied, and the object still remains in a single copy.

It turns out that several variables refer to the same object:

var user = { name: "Вася" }; // в переменной - ссылка
var admin = user; // скопировали ссылку

  Objects as associative arrays

Since the object is only one, in whatever variable it is not changed - this is reflected in the others:

1 var user = { name: 'Вася' };
2
3 var admin = user;
4
5 admin.name = 'Петя' ; // поменяли данные через admin
6
7 alert( user.name ); // 'Петя', изменения видны в user

Variable with an object as a “code” to a data safe

Another analogy: the variable to which the object is assigned, in fact, does not store the data itself, but the code to the safe where it is stored.

When passing it to a function, this code is copied to local variables, so that the variable can make changes to these data.

"Real" copying object

So, when transferring an object somewhere, only the link to it is copied.

To copy the data itself, you need to get it from the object and copy it at the primitive level.

Like that:

01 function clone(obj) {
02    var obj2 = {};
03
04    // если свойства могут быть объектами, то нужно перебирать и их
05    for ( var key in obj) obj2[key] = obj[key];
06
07    return obj2;
08 }
09
10 var user = { name: 'Вася' }; // user - ссылка на объект
11
12 var admin = clone(user);
13
14 admin.name = 'Петя' ; // поменяли данные в admin
15 alert(user.name); // 'Вася'

Importance: 5

Create a multiplyNumeric function that takes an object and multiplies all numerical properties by 2. For example:

01 // до вызова
02 var menu = {
03      width: 200,
04      height: 300,
05      title: "My menu"
06 };
07
08 multiplyNumeric(menu);
09
10 // после вызова
11 menu = {
12      width: 400,
13      height: 600,
14      title: "My menu"
15 };

PS To check the number, use the function:

function isNumeric(n) {
   return !isNaN(parseFloat(n)) && isFinite(n)
}

Decision

01 var menu = {
02    width: 200,
03    height: 300,
04    title: "My menu"
05 };
06
07 function isNumeric(n) {
08    return !isNaN(parseFloat(n)) && isFinite(n);
09 }
10
11 function multiplyNumeric(obj) {
12    for ( var key in obj) {
13      if (isNumeric( obj[key] )) {
14        obj[key] *= 2;
15      }
16    }
17 }
18
19 multiplyNumeric(menu);
20
21 alert( "menu width=" +menu.width+ " height=" +menu.height+ " title=" +menu.title);

[Open task in new window]

Compact representation of objects

Hardcore coders only

This section refers to the internal structure of the data structure and requires special knowledge. It is not required to read.

An object, as described, takes a lot of memory space, for example:

1 var user = {
2    name: "Vasya" ,
3    age: 25
4 };
It contains information about the name property and its string value, as well as the age property and its numerical value. Imagine that there are many such objects.

It turns out that the information on the names of the properties name and age duplicated in each object.

To avoid this, browsers use a special "compact representation of objects."

When creating a set of objects of the same type (with the same fields), the interpreter remembers how many fields it has and what they are, and stores this data in a separate structure. And the object itself is in the form of a continuous data array.

For example, for objects of the form {name: "Вася", age: 25} a structure will be created that describes this kind of objects: "the name string, then the age ", and the objects themselves will be represented in the data: Вася25 . And instead of a string, there will usually be a pointer to it.

The browser for accessing the property will know from the structure where it lies and will go to the desired position in the data. It is very fast, and saves memory, when there are many similar objects in a single structure description.

What happens if a new field is added to the object? For example:

user.admin = true ;

In this case, the browser looks to see if there is already a structure under which such an object fits (“string name , integer age , logical admin ”). If not, it is created. The changed object data is bound to it.

Details of the application and implementation of this storage method vary from browser to browser. Apply additional optimizations.

You can learn more about the internal structure of types, for example, from the presentation Know Your Engines (Velocity 2011).

Total

Objects are associative arrays with additional features:

  • Access to the elements is provided:
    • Directly by key obj.prop = 5
    • Through the variable in which the key is stored:
      var key = "prop" ;
      obj[key] = 5
  • Deleting keys: delete obj.name .
  • Loop by keys: for (key in obj) , the search order corresponds to the order of declarations for string keys, and for numeric keys it depends on the browser.
  • The existence of a property can be checked by the in : if ("prop" in obj) operator, as a rule, it works and a simple if (obj.prop !== undefined) comparison if (obj.prop !== undefined) .
  • The variable does not store the object itself, but a link to it. Copying such a variable and passing it to a function duplicate the link, but the object remains alone.

Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Scripting client side JavaScript, jqvery, BackBone

Terms: Scripting client side JavaScript, jqvery, BackBone