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"]
new
keyword, how can you protect against errors? Here is how I usually work:this instanceof Function_Name
construction (I try not to use the construction of this instanceof arguments.callee
for performance reasons).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.new
. In this case, the constructor functions must be given names beginning with a capital letter.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. var Obj = function () { "use strict"; this.pew = 100; }; // Правильно let o = new Obj(); o.pew++; console.log(o.pew); //101 // Неправильно. Возникает ошибка Obj (); // TypeError: this is undefined
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; };
var Obj = function () { "use strict"; this.pew = 100; };
new
an error will occur.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); }
event.which
property instead of messing with event.button
: $('button').mousedown(function (event) { alert(['Left', 'Middle', 'Right'][event.which]); });
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. window.addEventListener("keydown", function(e) { // Коды клавиш-стрелок if([37, 38, 39, 40].indexOf(e.keyCode) > -1) { e.preventDefault(); } }, false);
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; });
mousedown
focus
(before that, another object that loses focus will trigger the blur
event)mouseup
click
focus
will not help us with this.preventDefault()
event method. The key code ESC - 27.SyntaxError
a SyntaxError
error: function () { // код }()
function foo() { // код }()
(function () { // код })()
!function () { // код }(); +function () { // код }(); [function() { // код }()]; var a = function () { // код }();
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? 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!"); }); }
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.onresize
event. This method, however, is not very accurate. 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; });
window.open()
method, open a new browser window, not a new tab?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.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');
window.open('http://www.google.com');
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); }
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);
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);
// Мелкое копирование var newObject = jQuery.extend ({}, oldObject); // Глубокое копирование var newObject = jQuery.extend (true, {}, oldObject);
var a = {z: 'z'}; var b = a; var c = a; delete az; delete a; // Мы удалили ссылку a console.log (b, c); // Объект, теперь пустой, никуда не делся
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 } }]);
primer()
function in the following example) in the smth()
function.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 ();
__parent__
property, but this feature was removed in Firefox 4.call()
and apply()
methods. // Вспомогательная функция 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}
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 это работает иначе
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
.__parent__
, но потом эту возможность убрали.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);
$('#smth').click(function onSmthClick(event) { if (smth) { // Пишем обработчик event.handlerFunction = onSmthClick; event.handlerContext = this; // Передаём объект // Теперь otherObjectSetSomeEvent может использовать event.handlerFunction и вызывать обработчик otherObjectSetSomeEvent(event); } else { // Делаем что-то ещё } });
$('#smth'). click (function handler1 (event) { if (smth) { // Передаём объект leftObjectSetSomeEvent(event, function handler2 (e) { // Делаем что-то с событием e }); } else { // Делаем что-то ещё } }); function leftObjectSetSomeEvent(event, callback) { callback (event); // Работаем с событием }
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'); });
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) });
requestAnimationFrame()
, то следует использовать именно её, а не setInterval()
или setTimeout()
. Браузеры могут оптимизировать анимации, происходящие одновременно, уменьшая число операций пересчёта геометрии и перерисовки до одной, что, в свою очередь, ведёт к повышению точности анимации. Например, на некоей странице JavaScript-анимации могут быть синхронизированы с CSS-переходами или с SVG-анимациями. Кроме того, если анимация выполняется на странице, которая открыта в невидимой вкладке браузера, браузер не будет её перерисовывать, что приведёт к снижению нагрузки на процессор, видеокарту, память. На мобильных устройствах это, кроме того, означает экономию заряда аккумулятора. // Не меняйте свойства по одному element.style.left = "150px;"; // ... element.style.color = "green"; // Меняйте свойства, которые надо модифицировать, за один раз element.setAttribute ('style', 'color: green; left: 150px');
style.display = "none"
). Это уменьшает число операций по пересчёту геометрии элементов, но неактуально для современных браузеров.Document.querySelectorAll()
и свойство firstElementChild
.document.getElementsByTagName()
возвращает живую коллекцию элементов (такая коллекция, при добавлении нового элемента в дерево DOM, обновляется автоматически).runInNewContext()
в Node.js.runInNewContext()
. Фактически, речь идёт о совершенно ненужной «обёртке», которая не пригодится в разумно спроектированном приложении. При этом на работу с этой «обёрткой» тратятся серьёзные системные ресурсы, кроме того, использование runInNewContext()
может плохо сказаться на поддержке кода приложения.Source: https://habr.com/ru/post/436454/