In this case, the Menu function is used as a constructor. When you call it with the new : new Menu(menu) operator, inside it, this points to the new object being created.
Inside the click handler, this will already point to the element that was clicked and to call the methods of the Menu object being created inside the handler, the link to this object is stored in the self variable, which is used inside the handler.
More information about the loss of context can be found in the question: Loss of call context
To refer to the fields of the object in javascript there are two notations
Dot-notation - access to the field through the point
var o = { prop: 1; }; o.prop;// 1
This notation is widespread, but has restrictions on the names of fields to which it can be applied. So, to use this notation, the field name must be a valid identifier.
Bracket-notation - reference to the field using brackets []
var o = { prop: 1; }; o["prop"];// 1
This notation is widely used in cases where the name of the field to be addressed is not known in advance, as well as when the field name is not a valid identifier, but is for example a number or contains a space.
In this case, the property name is determined at the moment of the click, and the corresponding function is executed.
You can do without an intermediate variable if you use the arrow functions
function Menu(elem) { this.save = function() { console.log('сохраняю'); }; this.load = function() { console.log('загружаю'); }; this.search = function() { console.log('ищу'); }; elem.onclick = (e) => { var target = e.target; var action = target.getAttribute('data-action'); if (action) { this[action](); } }; } new Menu(menu);
<div id="menu"> <button data-action="save">Сохранить</button> <button data-action="load">Загрузить</button> <button data-action="search">Поиск</button> </div>