JavaScript: questions and answers

Original author: Alex Maison
  • Transfer
Recently, the company SmartSpate decided to collect questions related to JavaScript , and answer them. The material, the translation of which we publish, contains a little more than two dozen questions about JavaScript and answers to them. The range of topics covered here is quite wide. In particular, these are features of the language, problems encountered by programmers when writing JS code, work in the browser and in the Node.js environment.



Question number 1. Prototype Inheritance


I was used to the "classic" classes, but decided to learn JavaScript. I had a problem with understanding the prototype model. If possible, explain, in the form of templates, the possibilities for creating "classes" in JavaScript, tell us about the closed and open methods and properties of classes. I understand that a lot has been written about this already, and the fact that JavaScript methods and properties of objects, by default, are publicly available, but I would like to understand all this. How does prototype inheritance work in JavaScript?

▍ Answer


Classical inheritance is very similar to how people inherit the genes of their ancestors. People have some common basic capabilities, like walking and talking. In addition, each person has some peculiarities. People cannot change what can be called their "class", but they can, within certain limits, change their own "properties". At the same time, grandmothers, grandfathers, mothers and fathers cannot influence the genes of children or grandchildren in the course of their life. So everything is arranged on Earth, but let's imagine another planet on which the mechanisms of inheritance work in a special way. For example, some organisms capable of mutations use the mechanisms of "telepathic inheritance" there. This is reflected in the fact that they can change the genetic information of their own descendants in the process of their life.

Consider the example of inheritance on this strange planet. The Father object inherits the genes from the Grandfather object, and the Son object inherits the genetic information from the Father. Every inhabitant of this planet can freely mutate and change the genes of descendants. For example, the “Grandpa” skin has a green color. This sign is inherited by "Father" and "Son". Suddenly, "Grandpa" decides that he is tired of green. Now he wants to be blue and changes his skin color (in terms of JS, he changes the prototype of his class), telepathically transmitting this mutation to Father and Son. After that, “Father”, believing that “Grandfather” was out of his mind, decides to change his genes so that he becomes green again (that is, he changes his own prototype). These changes are "telepathically" transmitted to the "Son". As a result, both the “Father” and the “Son” have green skin again. In this case, "Grandfather" still remains blue. Now, whatever he does with his color, it will not affect anyone else. And all this is due to the fact that the “Father” explicitly asked the color of his skin in his “prototype”, and the “Son” inherits this color. Then “Son” thinks like this: “I’ll become black. And let my descendants inherit color from my father. ” To do this, it changes its own property (and not its prototype property) in such a way that its property would affect its color, but not affect its descendants. Express all this in the form of code: To do this, it changes its own property (and not its prototype property) in such a way that its property would affect its color, but not affect its descendants. Express all this in the form of code: To do this, it changes its own property (and not its prototype property) in such a way that its property would affect its color, but not affect its descendants. Express all this in the form of code:

var Grandfather = function () {}; // Конструктор Grandfather
Grandfather.prototype.color = 'green';
var Father = function () {}; // Конструктор Father
Father.prototype = new Grandfather (); // Это - простой, но не самый лучший пример прототипного наследованияvar Son = function () {}; // Конструктор Son
Son.prototype = new Father (); // Son является наследником Fathervar u = new Grandfather (); // Экземпляр класса Grandfathervar f = new Father (); // Экземпляр класса Fathervar s = new Son (); // Экземпляр класса Son// Изначально все зелёного цветаconsole.log ([u.color, f.color, s.color]); // ["green", "green", "green"]// Объект Grandfather решает перекраситься и поменять цвет своих потомков
Grandfather.prototype.color = 'blue';
console.log ([u.color, f.color, s.color]); // ["blue", "blue", "blue"]// Объект Father решает вернуть всё как было - и для себя, и для своих потомков
Father.prototype.color = 'green';
// Хотя он может поступить и так:// Grandfather.prototype.color = 'green';console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"]// Теперь, что бы ни делалось с прототипом объекта Grandfather в плане изменения свойства color, на потомках это не отразится
Grandfather.prototype.color = 'blue';
console.log ([u.color, f.color, s.color]); // ["blue", "green", "green"]// Объект Son, решив перекраситься, но не брать пример с объекта Grandfather, меняет собственное свойство
s.color = 'black'; // Изменение собственного свойства не затрагивает цепочку прототиповconsole.log ([u.color, f.color, s.color]); // ["blue", "green", "black"]var SonsSon = function () {}; // Конструктор SonsSon - потомка класса Son
SonsSon.prototype = new Son (); // Наследованиеvar ss = new SonsSon (); // Экземпляр класса SonsSon// Сын сына наследует цвет от отца своего отцаconsole.log ([u.color, f.color, s.color, ss.color]); // ["blue", "green", "black", "green"]

Question number 2. Creating objects


If you create new instances of objects using a keyword new, how can you protect against errors? Here is how I usually work:

  1. I always compose the names of the constructor functions so that they begin with a capital letter.
  2. I check the correctness of the operation performed with the help of the construction this instanceof Function_Name (I try not to use the construction of the view this instanceof arguments.calleefor performance reasons).
  3. This approach is similar to the previous one, but the comparison is made with window, since I don’t like to hard-code the names of entities in the code and don’t need to write code for environments other than the browser.

What is the most convenient model for creating objects?

▍ Answer


It is best, both ideologically and based on the familiarity of this method, to create objects using the keyword new. In this case, the constructor functions must be given names beginning with a capital letter.

I prefer to stick to the rules and not perform additional checks thison the constructors. If the constructor is called without newand work begins in the global scope, this can be compared with "self-deception". In this case, I in no way recommend to handle situations in constructors in which they are called without a keyword new. For example, it might look like this: if the constructor is called without new, then, all the same, a new object is created and returned. This approach is ideologically incorrect and leads to errors.
Here is an example of working with the designer.

var Obj = function () {
    "use strict";
    this.pew = 100;
};
// Правильноlet o = new Obj();
o.pew++;
console.log(o.pew); //101// Неправильно. Возникает ошибка
Obj (); // TypeError: this is undefined

It is newbetter not to use the keyword for factory methods and for cases when there is no need for a constructor, when it is more convenient to create an object using an object literal. Say, the constructor code shown in the following example is clearly redundant:

// Не очень хороший подход.var Obj = function () {
     if (! (thisinstanceof Obj)) {
         returnnew Obj ();
     }
     this.pew = 100;
};

If, even for creating a small object, a constructor is still needed, it is better to do this:

var Obj = function () {
     "use strict";
     this.pew = 100;
};

Here, as was shown above, due to the fact that the constructor is working in strict mode, calling it without newan error will occur.

Question number 3. Interception of mouse clicks


How do I use JavaScript tools to find out which mouse button is pressed?

▍ Answer


Pressing the mouse button generates events mousedownand mouseup. In this case, the event clickgenerates only the left mouse button. In the event handler, you need to check the code that is in the property event.buttonin order to find out exactly which button is pressed (0 - left, 1 - middle, 2 - right). However, in IE, everything looks different. Consider an example:

var button = document.getElementById ('button'),
               // 0 1 2
     buttonMap = ['Left', 'Middle', 'Right'],
     handler = function (event) {
         event = event || window.event;
         alert (buttonMap [event.button] + 'id:' + event.button);
     };
if (button.addEventListener) {
      button.addEventListener ('mousedown', handler, false);
} else {
      // IE 0 1 2 3 4
      buttonMap = ['???', 'Left', 'Right', '???', 'Middle'];
      button.attachEvent ('onmousedown', handler);
}

The jQuery library takes this feature of IE into account, so when using it in any browser, it is enough to check the value of the property event.whichinstead of messing with event.button:

$('button').mousedown(function (event) {
    alert(['Left', 'Middle', 'Right'][event.which]);
});

Question number 4. Intercept keystrokes


Is it possible to intercept, by means of JavaScript, pressing the arrow keys (in particular, pressing the Down and Up keys), making it so that, after clicking on them, the browser does not scroll through the page? If this is possible - what are the features of implementing this in different browsers? Suppose a page is displayed on a page that does not fit entirely on the screen. Navigation through the cells of this table must be organized using the arrow keys, and it is required that the browser does not scroll the page when pressing such keys.

▍ Answer


In order to implement something similar, first of all, you need to disable the standard response of the system to control actions. For example, the arrow keys and the mouse wheel scroll the page, right-clicking on the page brings up the context menu, when the button submitis clicked, the function is called form.submit(), when it is clicked on the input field, it receives input focus, when the link is clicked, the browser loads the page to which it leads .

This can be done in different ways . For example - so:

window.addEventListener("keydown", function(e) {
    // Коды клавиш-стрелок
    if([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
        e.preventDefault();
    }
}, false);

The page after this will not normally respond to key presses.
There is one important thing to note. preventDefault()You need to call the method before the default action is executed. For example, if, when clicking on a field, it is required that it would not receive the input focus, you need to hang the corresponding handler on the event that is in the chain of events before the default action. In our case, this is an event mousedown:

$('input').bind ('mousedown', function (event) {
    event.preventDefault();
    // или
    returnfalse;
});

When you click on the input field, the following events occur - in the sequence in which they are shown here:

  1. mousedown
  2. focus(before that, another object that loses focus will trigger an event blur)
  3. mouseup
  4. click

If you try to prevent the element from getting the input focus, using event handlers for this, starting from the event handler, focuswill not help us.

Question number 5. Stop GIF animation and ESC key


How to deal with the problem of stopping GIF-animation when you press the ESC key?

▍ Answer


Here you can use the same approach that we considered above. In some browsers, pressing the ESC key stops GIF animation and page loading. This is their standard behavior, and in order for them not to behave this way, the event method is useful to us, as before preventDefault(). The key code ESC - 27.

Question number 6. Parentheses in IIFE


How does the construction in the form of two parentheses, used to declare an immediately called functional expression (IIFE, Immediately Invoked Function Expression)?

▍ Answer


The brackets in this situation allow the parser to understand that there is a function in front of them that needs to be executed. But he also needs to understand what these brackets are - a grouping operator, or a construct indicating the need to call a function. For example, if you use two brackets as shown below, we will encounter an error SyntaxError:

function () {
  // код
}()

This happens due to the fact that the function does not have a name (in function declarations, you need to specify their names).

Let's try to rewrite this code, giving the function a name:

functionfoo() {
  // код
}()

Now that the function has a name, this construction, theoretically, should look quite normal from the point of view of the system. But the error does not disappear, though now it relates to the grouping operator, within which there is no expression. Notice that in this case, the function declaration is followed by a grouping operator, and not a sequence of parentheses, indicating to the system that it is necessary to call the prefixing function.

Often IIFE make out so:

(function () {
    // код
  })()

But there are other ways, the essence of which is to somehow indicate to the parser that what is in front of it is the functional expression that needs to be executed:

!function () {
  // код
}();
+function () {
  // код
}();
[function() {
  // код
}()];
var a = function () {
  // код
}();

IIFE are widely used in JavaScript programming. For example, this construct is used in jQuery. With its help, you can create a circuit. In fact, we are talking about the fact that, using IIFE, the programmer can execute some code in the local scope. This helps to protect the global scope from pollution, allows you to optimize access to global variables. Such designs are well minified.

Question number 7. Pass code in response to requests


The server, in the process of AJAX interaction with the client, in the response body, sends a string to the client alert (‘Boom !!!’);. The client accepts the response and executes this code using the function eval(). How it's called? After all, what is contained in the response of the server is not JSON, not XML and not HTML. What can you say about the execution on the client of the code that comes from the server as the body of an answer to a certain request?

▍ Answer


In fact, there is no special name for such a scheme of interaction between the client and the server. And this is a system interaction scheme, which is strongly discouraged. This is as bad as storing PHP code in a database and then executing it using the appropriate language methods. Even if one does not take into account ideological considerations, one can say that such an architecture turns out to be extremely inflexible, therefore, if the project where it is used needs to be changed as it evolves, it will not be easy to do. Here we see an example of a bad system architecture, when data is mixed with code and interface elements. In order to change something in such a system, you first need to understand the intricacies of its intricate architecture, and then, after completing the changes, again “confuse” everything.

To simplify the support of the code, it is necessary to strive for the separation of system parts as much as possible and to reduce the number of interdependencies of these parts. In order to provide weak connectivity of parts of the system, that is, to make it so that a fragment of the application can be extracted from it, or replaced with another, with the least complexity, event mechanisms or special architectural solutions, such as MVC, can be applied.

Question number 8. Performing heavy operations in the main thread


How to organize the execution of some resource-intensive commands in JavaScript and not hang the whole script?

▍ Answer


JavaScript is a single-threaded language. In the same thread, the code of the web pages is executed and the DOM tree is converted. Timers work there too. Every time you perform some resource-intensive operations (cycles, calls to "heavy" functions), this leads to a slowdown of the user interface or even its complete blocking. If the operations performed do not have a particularly large load on the system, then their effect on the interface will be so insignificant that users simply will not notice. In order to make heavy calculations out of the main thread, JavaScript introduced the concept of web workers.

If the use of workers is not possible, then it is necessary to optimize cycles and "heavy" functions. In the book "JavaScript. Performance Optimization ”Nicholas Zakas says that the user will not notice anything if the UI thread is blocked for 100 ms or less.

From this idea, we can conclude that resource-intensive calculations can be divided into fragments, the execution of which takes a maximum of 100 ms, after which the main stream must be freed.

Here is a sample code from the above book:

functiontimedProcessArray(items, process, callback) {
    var todo = items.concat();   //создаём клон
    setTimeout(function () {
        var start = +newDate();
        do {
            process(todo.shift());
        } while (todo.length > 0 && (+newDate() - start < 50));
        if (todo.length > 0){
            setTimeout(arguments.callee, 25);
        } else {
            callback(items);
        }
    }, 25);
}
functionsaveDocument(id) {
    var tasks = [openDocument, writeText, closeDocument, updateUI];
    timedProcessArray(tasks, [id], function(){
        alert("Save completed!");
    });
}

The function timedProcessArray()blocks the main thread for 25 ms, performs a sequence of actions, then releases it for 25 ms, after which this process is repeated.

Question number 9. Browser resizing information


Can I somehow find out that the user has completed resizing the browser window?

▍ Answer


There is no special event that allows you to find out. But you can find out if the user is resizing the window using an event onresize. This method, however, is not very accurate.

Here is an outline of the code aimed at solving this problem.

var time = 0,
    timerId,
    TIME_ADMISSION = 100; // 0.1 сfunctiononresizeend () {
    console.log('onresizeend');
};
functionresizeWatcher () {
    if (+newDate - time >= TIME_ADMISSION) {
        onresizeend();
        if (timerId) {
            window.clearInterval(timerId);
            timerId = null;
        }
    }
};
$(window).resize(function () {
    if (!timerId) {
        timerId = window.setInterval(resizeWatcher, 25);
    }
    time = +newDate;
});

Question number 10. Opening new windows and browser tabs


How, using the method window.open(), open a new browser window, and not a new tab?

▍ Answer


How exactly the method behaves window.open()depends on the browser. Opera always opens new tabs (although they look like windows), Safari always opens windows (although this behavior can be changed). The behavior of Chrome, Firefox and Internet Explorer can be controlled.

So, if window.open()an additional parameter is passed to the method (window position), a new window will be opened:

window.open('http://www.google.com', '_blank', 'toolbar=0,location=0,menubar=0');

If only a link is passed to this method, then a new browser tab will open:

window.open('http://www.google.com');

Often you need to open a new browser tab. This can cause problems in the Safari browser. By default (it depends on the settings) the browser, when called window.open(), opens a new window. But if you click on the link, pressing the keys Ctrl + Shift/Meta + Shift, the new tab will open (regardless of the settings). In the following example, we will simulate an event clickraised when the keys are pressed Ctrl + Shift/Meta + Shift:

functionsafariOpenWindowInNewTab (href) {
     var event = document.createEvent ('MouseEvents'),
         mac = (navigator.userAgent.indexOf ('Macintosh')> = 0);
// выполнить Ctrl + Shift + LeftClick / Meta + Shift + LeftClick (фокус)
     // создаём собственное событие
     event.initMouseEvent (
         / * type * /"click",
         / * canBubble * / true
         / * cancelable * / true,
         / * view * / window,
         / * detail * / 0,
         / * screenX, screenY, clientX, clientY * / 0, 0, 0, 0,
         / * ctrlKey * /! mac,
         / * altKey * / false,
         / * shiftKey * / true
         / * metaKey * / mac,
         / * button * / 0,
         / * relatedTarget * / null
     );
// создаём ссылку в памяти и, используя наше событие, открываем её в новой вкладке
     $ ('<a/>', {'href': href, 'target': '_blank'}) [0] .dispatchEvent (event);
}

Question number 11. Deep copying of objects


How to effectively organize deep copying of objects?

▍ Answer


If the object that you want to create a copy of (let's call it oldObject) does not change, then it will be most effective to do this through its prototype (this is done very quickly):

functionobject(o) {
    functionF() {}
    F.prototype = o;
    returnnew F();
}
var newObject = object(oldObject);

If you really need to perform an object cloning operation, then the fastest will be recursively, having optimized this process, to go over its properties. This is probably the fastest algorithm for creating deep copies of objects:

var cloner = {
    _clone: function_clone(obj) {
        if (obj instanceofArray) {
            var out = [];
            for (var i = 0, len = obj.length; i < len; i++) {
                var value = obj[i];
                out[i] = (value !== null && typeof value === "object") ? _clone(value) : value;
            }
        } else {
            var out = {};
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    var value = obj[key];
                    out[key] = (value !== null && typeof value === "object") ? _clone(value) : value;
                }
            }
        }
        return out;
    },
clone: function(it) {
        returnthis._clone({
        it: it
        }).it;
    }
};
var newObject = cloner.clone(oldObject);

If you use jQuery, then you can resort to the following constructions:

// Мелкое копированиеvar newObject = jQuery.extend ({}, oldObject);
// Глубокое копированиеvar newObject = jQuery.extend (true, {}, oldObject);

Question number 12. Destructors in javascript


How to create something like destructor in JavaScript? How to manage the life cycle of objects?

▍ Answer


In JavaScript, the object will be removed from memory after the last link to it disappears:

var a = {z: 'z'};
var b = a;
var c = a;
delete a.z;
delete a; // Мы удалили ссылку aconsole.log (b, c); // Объект, теперь пустой, никуда не делся

Using something like “destructor” in JavaScript leads only to clearing the contents of an object, but not to deleting it from memory.

Question number 13. Binary data processing


Is it possible to handle binary data in JavaScript? And if so, how?

▍ Answer


If you need to work with binary data in a JavaScript application, you can try using the Binary Parser library . But its code is real hell. In ES6 + there is a sentence regarding the type StructType(this is the same thing that is represented in C ++ with a composite data type struct). This data type is needed to simplify working with binary data. Working with him might look something like this:

const Point2D = new StructType({ x: uint32, y: uint32 });
const Color = new StructType({ r: uint8, g: uint8, b: uint8 });
const Pixel = new StructType({ point: Point2D, color: Color });
const Triangle = new ArrayType(Pixel, 3);
let t = new Triangle([{ point: { x:  0, y: 0 }, color: { r: 255, g: 255, b: 255 } },
                      { point: { x:  5, y: 5 }, color: { r: 128, g: 0,   b: 0   } },
                      { point: { x: 10, y: 0 }, color: { r: 0,   g: 0,   b: 128 } }]);

Question number 14. Change variables in one function from another function


How to change variables in one function from another function?

▍ Answer


Here you can apply several approaches:

  1. You can use the reference to the context of the function of interest (the function primer()in the following example) in the function smth().
  2. You can pass a function created in the context of a function primer(), a function smth().

    var primer = function () {
         var a, b, c, d, e = {};
    smth (function () {
             a = 1;
             b = 2;
             c = 3;
             d = 4;
         }, e);
    alert ([a, b, c, d, e.pewpew]);
    },
    smth = function (callback, e) {
         callback ();
         e.pewpew = "pewpew";
    };
    primer ();
  3. Previously (to Firefox 3.6), the context could be reached using the property __parent__, but this feature was removed in Firefox 4.

Question number 15. Work with functions


Tell us how you can call functions in JavaScript.

▍ Answer


I suppose there is no need to talk about how to call functions, methods, and constructors during normal work with them. Let's talk about how to use the methods call()and apply().

Using call () to set up an object constructor


// Вспомогательная функцияfunctionextend (newObj, oldObj) {
    functionF () {}; 
    F.prototype = oldObj.prototype; 
    newObj.prototype = new F (); 
    return newObj
};
var Obj = function () {
    this.obj_var = 100;
};
Obj.prototype.obj_proto_var = 101;
var NewObj = function () {
    Obj.call (this); // Вызываем конструктор Obj и получаем собственное свойство obj_var
    this.new_obj_var = 102;
};
extend (NewObj, Obj)
NewObj.prototype.new_obj_proto_var = 103;
new NewObj (); // {new_obj_proto_var: 103, new_obj_var: 102, obj_proto_var: 101, obj_var: 100}

Converting mass-like objects into arrays


Massive objects are similar to JavaScript arrays, but they are not. In particular, this is expressed in the fact that such objects do not have methods of ordinary arrays. Among such objects, for example, the object of argumentstraditional functions and the results of the getElementsByTagName () method can be noted .

// document.getElementsByTagName ("div") возвращает нечто, похожее на массив, но им не являющееся, что, в частности, не даёт нам возможность пользоваться методами массивовdocument.getElementsByTagName ("div"). forEach (function (elem) {
     // ...
}); // TypeError: document.getElementsByTagName ("div"). forEach is not a function// Переходим к массивуArray.prototype.slice.call(document.getElementsByTagName("div")).forEach (function (elem) {
    // OK
});
// Похожие вещи можно делать и со строкамиconsole.log(Array.prototype.slice.call ('pewpew')) // ["p", "e", "w", "p", "e", "w"]// В IE8 это работает иначе

Creating wrapper objects


This method of application call()and apply()allows you to create wrappers. Suppose we need to create a wrapper function foo()that calls the function bar()in a specific context with an arbitrary number of arguments.

When using the traditional approach, it will look like this:

functionbar () {console.log(arguments)}
// foo (context, arg1, arg2, ...)functionfoo () {
     var context = arguments [0];
     var args = Array.prototype.slice.call (arguments, 1); // массив с аргументами для bar
     bar.apply (context, args);
}

The same with the use of the design Function.call.apply()can be rewritten much shorter:

functionfoo() { 
    Function.call.apply(bar, arguments);
}

Here, thanks to use Function.call.apply(), the arguments passed foo()are passed bar.

Question number 16. Passing function execution context


How to transfer the context in which one function is executed to another function?

▍ Answer


It's impossible. Previously, in versions of Firefox up to 3.6, the context could be obtained through the property __parent__, but then this feature was removed.

Question number 17. Work with global object


Tell us how to work with a global object if it is not transmitted directly, if it is not used eval()and strict mode is used?

▍ Answer


If all three of these conditions are met, then access to the global object cannot be obtained. If we deviate from them, then we can consider the following options:

// 1: Использование eval()
(function () {
     "use strict";
     var globalObject = (0, eval) ("this"); // Волшебство :)
     return globalObject;
} ());
// 2: Передача глобального объекта
(function (global) {
     // ...
} (window));
// 3: Работа без использования строгого режима
(function () {
     returnthis;
} ());
// 4: Выполняя этот код в глобальном контексте мы получим ссылку на глобальный объект, в противном случае это работать не будет.// Это - наиболее адекватный вариант"use strict";
(function (global) {
     // global
}) (this);

Question number 18. Event restart


Can JavaScript restart an event after it was intercepted?

▍ Answer


The event object in JavaScript does not carry any “payload”. It only contains the event descriptor. But the corresponding link to such an object can be passed to the event handler. For example, it might look like this:

$('#smth').click(functiononSmthClick(event) {
    if (smth) {
        // Пишем обработчик
        event.handlerFunction = onSmthClick;
        event.handlerContext = this;
        // Передаём объект
        // Теперь otherObjectSetSomeEvent может использовать event.handlerFunction и вызывать обработчик
        otherObjectSetSomeEvent(event);
    } else {
        // Делаем что-то ещё
    }
});

But this is not the most successful solution, since the code turns out to be confusing. It is better to rewrite this example as follows, dividing the handler into 2 parts:

$('#smth'). click (functionhandler1 (event) {
    if (smth) {
        // Передаём объект
        leftObjectSetSomeEvent(event, functionhandler2 (e) {
            // Делаем что-то с событием e
        });
    } else {
        // Делаем что-то ещё
    }
});
functionleftObjectSetSomeEvent(event, callback) {
    callback (event);
    // Работаем с событием
}

Question number 19. Universal Mouse Event Handler


How in JavaScript to intercept mouse clicks on any page element? For example, in order to write a universal event handler.

▍ Answer


You need to attach an event handler clickto the “lowest” object in the DOM tree. As a result, all such events will reach this object (although it will be so only if no one intercepts them).

// jQuery
$(window).bind ('click', function (e) {
    console.log ('Clicked on', e.target);
});
// Можно ввести ограничения с использованием делегирования
$('#pewpew').delegate ('*', 'click', function(e) {
    console.log('Clicked on', e.target);
});
// Можно ограничить целевые объекты
$('#pewpew').delegate('.pewpew', 'click', function (e) {
    console.log ('Clicked on element with .pewpew class name');
});

Question number 20. XHR requests


How to perform XHR requests without using jQuery?

▍ Answer


Here is a solution that does not differ in cross-browser capabilities:

functionxhr(m, u, c, x) {
  with(new XMLHttpRequest) onreadystatechange = function (x) {
    readyState ^ 4 || c(x.target)
  }, open(m, u), send(с)
}

Here is the cross-browser version:

functionxhr(m, u, c, x) {
  with(new(this.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")) onreadystatechange = function (x) {
    readyState ^ 4 || c(x)
  }, open(m, u), send(с)
}

Here's how to use it:

xhr('get', '//google.com/favicon.ico', function (xhr) {
  console.dir(xhr)
});

Question number 21. Optimize the output of web pages


How to minimize the number of operations of recalculating the geometry of elements (reflow) and redrawing (repaint) when working with web pages?

▍ Answer


  1. If the browser supports the function requestAnimationFrame(), then you should use it, and not setInterval()or setTimeout(). Browsers can optimize the animations that occur simultaneously, reducing the number of operations to recalculate geometry and redrawing to one, which, in turn, leads to an increase in the accuracy of animation. For example, on a certain page, JavaScript animations can be synchronized with CSS transitions or with SVG animations. In addition, if the animation is performed on a page that is open in the invisible browser tab, the browser will not redraw it, which will reduce the load on the processor, video card, memory. On mobile devices, it also means saving battery power.
  2. Avoid using on the pages of a large number of float-elements (to reduce operations for recalculating the geometry of elements).
  3. Modify the DOM tree as rarely as possible. Build what you need in memory, and then update the DOM only once (this will also lead to a decrease in the number of operations on geometry recalculation).
  4. If you need to change several properties of objects, change them all at once. This minimizes the number of operations to recalculate the geometry of objects and the number of redraw operations (for modern browsers, however, this is irrelevant). Here is an example:

    // Не меняйте свойства по одному
    element.style.left = "150px;";
    // ...
    element.style.color = "green";
    // Меняйте свойства, которые надо модифицировать, за один раз
    element.setAttribute ('style', 'color: green; left: 150px');
  5. Animate dragging objects only for elements with absolute positioning (this leads to a reduction in the number of operations on geometry recalculation).
  6. Before you change the group of elements - hide them ( style.display = "none"). This reduces the number of operations to recalculate the geometry of elements, but is irrelevant for modern browsers.

Here are some more recommendations on optimizing web pages that are not related to recalculating the geometry of elements and to redrawing. It should be noted that they, in modern browsers, may not have a particularly noticeable effect, since these browsers are well optimized.

  1. Use event delegation.
  2. Cache references to DOM elements (element selection is the most resource intensive operation).
  3. Use the function Document.querySelectorAll()and property to quickly find items firstElementChild.
  4. Remember that the function document.getElementsByTagName()returns a live collection of elements (such a collection, when adding a new element to the DOM tree, is automatically updated).

Question number 22. Work with processes in Node.js


Should the Node.js environment, in high-load projects, create new processes for processing each new request?

▍ Answer


It is not recommended to do so categorically, as with this approach we will create too much additional load on the system (this will be similar to the work of PHP and Apache). We are talking about the need to allocate memory for the new process, about the time spent on creating the fork of the process, on initializing the process, and so on. Node.js is very well able to distribute the load and loads a single processor core in its event-processing cycle — in the main application thread. It is best when there is one fork of the process per kernel, and it is best to manage the processes using the standard cluster module. When using this module, the concept of the main process (master) and worker processes (worker) is used. It should be noted that the use of additional processes for handling heavy requests is fully justified.

Question number 23. The runInNewContext () method in Node.js


Tell us about using the method runInNewContext()in Node.js.

▍ Answer


I see only one application of this technology. It consists in the execution of someone else's, potentially unsafe code (this is exactly what Node.js hosting Nodester does). If there is no strong need for something like this, then I categorically do not recommend using it runInNewContext(). In fact, we are talking about a completely unnecessary "wrapper", which is not useful in a reasonably designed application. At the same time, serious system resources are spent on working with this “wrapper”, in addition, the use runInNewContext()may have a bad effect on the support of the application code.

Results


In this article, we looked at some of the questions about JavaScript and the answers to them. We hope you found something here that is useful to you.

Dear readers! What questions, really bothering you, would you ask to someone who is very well versed in JavaScript and in technologies related to this language?


Also popular now: