📜 ⬆️ ⬇️

JavaScript: questions and answers

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:

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 является наследником Father var u = new Grandfather (); // Экземпляр класса Grandfather var f = new Father (); // Экземпляр класса Father var 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 the new keyword, 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 this instanceof Function_Name construction (I try not to use the construction of this instanceof arguments.callee for performance reasons).
  3. This approach is similar to the previous one, but the comparison is made with the window , since I don’t like to hard-code the entity names 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 on this in constructors. If the constructor is called without new and 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 invoked without the new keyword. 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 better not to use the new 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 (! (this instanceof Obj)) {        return new 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, if you call it without new an 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


When you click on the mouse button, mousedown and mouseup events are generated. In this case, the click event generates only the left mouse button. In the event handler, you need to check the code found in the event.button property 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 event.which property instead 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 mouse wheel scroll the page, right-click on the page to form.submit() context menu, when you click on the submit button, the form.submit() function is form.submit() , when you click on the input field, it receives input focus, when you click on the link, the browser loads page to which she 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. Call the preventDefault() 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 a mousedown event:

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

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 the blur event)
  3. mouseup
  4. click

If we try to prevent an element from receiving an input focus, then using event handlers for this purpose, beginning with the event handler focus will not help us with this.

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, we, as before, come in handy for the preventDefault() event method. 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 we use two brackets as shown below, we will SyntaxError a SyntaxError error:

 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:

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

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 the client a string alert ('Boom !!!'); . The client accepts the response and executes this code using the eval() function. 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. I'm not talking about code reuse.

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:

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

The timedProcessArray() function 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 the onresize event. 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 с function onresizeend () {   console.log('onresizeend'); }; function resizeWatcher () {   if (+new Date - time >= TIME_ADMISSION) {       onresizeend();       if (timerId) {           window.clearInterval(timerId);           timerId = null;       }   } }; $(window).resize(function () {   if (!timerId) {       timerId = window.setInterval(resizeWatcher, 25);   }   time = +new Date; }); 

Question number 10. Opening new windows and browser tabs


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

▍ Answer


How exactly the window.open() method behaves 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 an additional parameter (window position window.open() passed to the window.open() method, 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 you call window.open() , opens a new window. But if you click on the link, while pressing the Ctrl + Shift/Meta + Shift keys, a new tab will open (regardless of the settings). In the following example, we will simulate a click event that is triggered when the Ctrl + Shift/Meta + Shift keys are pressed:

 function safariOpenWindowInNewTab (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 it through its prototype (this is done very quickly):

 function object(o) {   function F() {}   F.prototype = o;   return new 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 instanceof Array) {           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) {       return this._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 az; delete a; // Мы удалили ссылку a console.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 of StructType (this is the same thing that is represented in C ++ with a composite type of this 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 primer() function in the following example) in the smth() function.
  2. You can pass a function created in the context of the primer() function to the smth() function.

     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 __parent__ property, 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 call() and apply() methods.

Using call () to set up an object constructor


 // Вспомогательная функция function extend (newObj, oldObj) {   function F () {};   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 arguments object of traditional 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


Эта методика применения call() и apply() позволяет создавать объекты-обёртки. Предположим, нам нужно создать функцию-обёртку foo() , которая вызывает функцию bar() в специфическом контексте с произвольным числом аргументов.

При использовании традиционного подхода это будет выглядеть так:

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

То же самое с применением конструкции Function.call.apply() можно переписать гораздо короче:

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

Здесь, благодаря использованию Function.call.apply() , аргументы, переданные foo() , передаются bar .

Вопрос №16. Передача контекста выполнения функции


Как передать контекст, в котором выполняется одна функция, другой функции?

▍Ответ


Это невозможно. Раньше, в версиях Firefox до 3.6, контекст можно было получить через свойство __parent__ , но потом эту возможность убрали.

Вопрос №17. Работа с глобальным объектом


Расскажите о том, как работать с глобальным объектом в том случае, если он не передаётся напрямую, если не используется eval() и применяется строгий режим?

▍Ответ


Если соблюдены все три этих условия, то доступ к глобальному объекту получить нельзя. Если же от них отступить, то можно рассмотреть следующие варианты:

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

Вопрос №18. Перезапуск событий


Можно ли, средствами JavaScript, перезапустить событие после того, как оно было перехвачено?

▍Ответ


Объект события в JavaScript не несёт какой-либо «полезной нагрузки». Он лишь содержит дескриптор события. Но соответствующую ссылку на подобный объект можно передать обработчику события. Например, это может выглядеть так:

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

Но это — не самое удачное решение, так как код получается запутанным. Лучше переписать этот пример следующим образом, разделив обработчик на 2 части:

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

Вопрос №19. Универсальный обработчик событий мыши


Как в JavaScript перехватывать щелчки мышью по любым элементам страницы? Например — для того, чтобы написать универсальный обработчик событий.

▍Ответ


Нужно прикрепить обработчик события click к самому «нижнему» объекту в дереве DOM. В результате все подобные события достигнут этого объекта (правда, так будет только в том случае, если их никто не перехватит).

 // 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'); }); 

Вопрос №20. XHR-запросы


Как выполнять XHR-запросы без использования jQuery?

▍Ответ


Вот решение, которое не отличается кросс-браузерными возможностями:

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

Вот кросс-браузерный вариант:

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

Вот как этим пользоваться:

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

Вопрос №21. Оптимизация вывода веб-страниц


Как минимизировать число операций пересчёта геометрии элементов (reflow) и перерисовки (repaint) при работе с веб-страницами?

▍Ответ


  1. Если браузер поддерживает функцию requestAnimationFrame() , то следует использовать именно её, а не setInterval() или setTimeout() . Браузеры могут оптимизировать анимации, происходящие одновременно, уменьшая число операций пересчёта геометрии и перерисовки до одной, что, в свою очередь, ведёт к повышению точности анимации. Например, на некоей странице JavaScript-анимации могут быть синхронизированы с CSS-переходами или с SVG-анимациями. Кроме того, если анимация выполняется на странице, которая открыта в невидимой вкладке браузера, браузер не будет её перерисовывать, что приведёт к снижению нагрузки на процессор, видеокарту, память. На мобильных устройствах это, кроме того, означает экономию заряда аккумулятора.
  2. Избегайте использования на страницах большого количества float-элементов (для уменьшения операций по пересчёту геометрии элементов).
  3. Как можно реже модифицируйте дерево DOM. Формируйте то, что вам нужно, в памяти, после чего обновляйте DOM лишь один раз (это тоже приведёт к снижению числа операций по пересчёту геометрии).
  4. Если нужно изменить несколько свойств объектов — меняйте их все за один раз. Это минимизирует число операций пересчёта геометрии объектов и число операций перерисовки (для современных браузеров, правда, это неактуально). Here is an example:

     // Не меняйте свойства по одному element.style.left = "150px;"; // ... element.style.color = "green"; // Меняйте свойства, которые надо модифицировать, за один раз element.setAttribute ('style', 'color: green; left: 150px'); 
  5. Выполняйте анимацию перетаскивания объектов только для элементов с абсолютным позиционированием (это ведёт к снижению числа операций по пересчёту геометрии).
  6. Прежде чем изменить группу элементов — скройте их ( style.display = "none" ). Это уменьшает число операций по пересчёту геометрии элементов, но неактуально для современных браузеров.

Вот ещё несколько рекомендаций, касающихся оптимизации веб-страниц, которые не относятся к пересчёту геометрии элементов и к перерисовке. Надо отметить, что они, в современных браузерах, могут и не дать особенно заметного эффекта, так как эти браузеры хорошо оптимизированы.

  1. Используйте делегирование событий.
  2. Кэшируйте ссылки на DOM-элементы (выбор элемента — наиболее ресурсозатратная операция).
  3. Используйте для быстрого поиска элементов функцию Document.querySelectorAll() и свойство firstElementChild .
  4. Помните о том, что функция document.getElementsByTagName() возвращает живую коллекцию элементов (такая коллекция, при добавлении нового элемента в дерево DOM, обновляется автоматически).

Вопрос №22. Работа с процессами в Node.js


Следует ли в среде Node.js, в высоконагруженных проектах, создавать новые процессы для обработки каждого нового запроса?

▍Ответ


Поступать так категорически не рекомендуется, так как при таком подходе мы создадим слишком большую дополнительную нагрузку на систему (это будет похоже на работу PHP и Apache). Речь идёт о необходимости выделения памяти для нового процесса, о затратах времени на создание форка процесса, на инициализацию процесса и так далее. Платформа Node.js очень хорошо умеет распределять нагрузку и загружает одно процессорное ядро в своём цикле обработки событий — в главном потоке приложения. Лучше всего, когда на одно ядро приходится один форк процесса, причём управлять процессами лучше всего с помощью стандартного модуля cluster . При использовании этого модуля используется концепция главного процесса (master) и процессов-воркеров (worker). При этом надо отметить, что вполне оправдано использование дополнительных процессов для обработки тяжёлых запросов.

Вопрос №23. Метод runInNewContext() в Node.js


Расскажите об использовании метода runInNewContext() в Node.js.

▍Ответ


Я вижу лишь один вариант применения этой технологии. Он заключается в выполнение чужого, потенциально небезопасного кода (именно так поступает Node.js-хостинг Nodester). Если в чём-то подобном сильной нужды нет, то я категорически не рекомендую пользоваться runInNewContext() . Фактически, речь идёт о совершенно ненужной «обёртке», которая не пригодится в разумно спроектированном приложении. При этом на работу с этой «обёрткой» тратятся серьёзные системные ресурсы, кроме того, использование runInNewContext() может плохо сказаться на поддержке кода приложения.

Итоги


В этом материале мы рассмотрели некоторые вопросы о JavaScript и ответы на них. Надеемся, вы нашли здесь что-то такое, что вам пригодится.

Уважаемые читатели! Какие вопросы, по-настоящему вас беспокоящие, вы задали бы тому, кто очень хорошо разбирается в JavaScript и в технологиях, имеющих отношение к этому языку?

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