This page has been robot translated, sorry for typos if any. Original content here.

Using Java scripts

JavaScript is a prototyped-oriented scenario programming language. It is a dialect of the ECMAScript language.

JavaScript is commonly used as an embedded language for programmatic access to application objects. The widest application is found in browsers as a scripting language for giving interactivity to web pages. The main architectural features: dynamic typing, weak typing, automatic memory management, prototyping programming, functions as first-class objects. JavaScript has been influenced by many languages, with the development was the goal to make the language similar to Java, but at the same time easy for use by non-programmers. The language of JavaScript is not owned by any company or organization, which distinguishes it from a number of programming languages ​​used in web development. The name "JavaScript" is a registered trademark of Oracle Corporation .

Top 10 JavaScript features

Modern javascript-frameworks, of course, know all these functions. But sometimes you need to do something without the framework. For different reasons. For this, this collection of useful functions is intended.

10) addEvent ()

Undoubtedly, the most important tool in managing events! Regardless of which version you use and who it is written, it does what it says in the name: appends an event handler to the element.

  function addEvent (elem, evType, fn) {
	 if (elem.addEventListener) {
		 elem.addEventListener (evType, fn, false);
	 }
	 else if (elem.attachEvent) {
		 elem.attachEvent ('on' + evType, fn)
	 }
	 else {
		 elem ['on' + evType] = fn
	 }
 }

This code has two advantages: it is simple and cross-browser.

Its main drawback is that it does not pass this to the handler for IE. More precisely, it does not do attachEvent.

A simple work around this

To pass the correct this, you can replace the corresponding addEvent line with:

elem.attachEvent("on"+evType, function() { fn.apply(elem) })

This solves the problem with passing this, but the handler can not be removed in any way. detachEvent should call exactly the function that was passed to attachEvent.

There are two options for circumventing the problem:

1) Return the function used to assign the handler:

  function addEvent (elem, evType, fn) {
	 if (elem.addEventListener) {
		 elem.addEventListener (evType, fn, false)
  return fn
	 }

  iefn = function () {fn.call (elem)} 
  elem.attachEvent ('on' + evType, iefn)
	 return iefn
 }

 function removeEvent (elem, evType, fn) {
	 if (elem.addEventListener) {
		 elem.removeEventListener (evType, fn, false)
  return
	 }
 
  elem.detachEvent ('on' + evType, fn)
 } 

It is used like this:

  function handler () { 
  alert (this) 
 }
 var fn = addEvent (elem, "click", handler)
 ...
 removeEvent (elem, "click", fn) 

2) You can not use this in the event handler at all, but pass the element through the closure:

  function addEvent (elem, evType, fn) {
	 if (elem.addEventListener) {
		 elem.addEventListener (evType, fn, false)
  return fn
	 }

  iefn = function () {fn.call (elem)} 
  elem.attachEvent ('on' + evType, iefn)
	 return iefn
 }

 function removeEvent (elem, evType, fn) {
	 if (elem.addEventListener) {
		 elem.removeEventListener (evType, fn, false)
  return
	 }
 
  elem.detachEvent ('on' + evType, fn)
 } 

It is used like this:

  function handler () { 
  // use not this, but the variable referring to the element
  alert (elem) 
 }
 ...

9) onReady ()

To initialize the page historically, the event window.onload was used , which works after the page is fully loaded and all the objects on it: counters, images, etc.

The onDOMContentLoaded event is a much better choice in 99% of cases. This event is triggered as soon as the DOM document is ready, before loading the images and other objects that do not affect the document structure.

This is very convenient, because the images can be loaded for a long time, and the onDOMContentLoaded handler can make the necessary changes on the page and initialize the interfaces right there, without waiting for the download of everything.

To add a handler, you can use the following cross-browser code:

  function bindReady (handler) {

	 var called = false

	 function ready () {// (1)
		 if (called) return
		 called = true
		 handler ()
	 }

	 if (document.addEventListener) {// (2)
		 document.addEventListener ("DOMContentLoaded", function () {
			 ready ()
		 }, false)
	 } else if (document.attachEvent) {// (3)

		 // (3.1)
		 if (document.documentElement.doScroll && window == window.top) {
			 function tryScroll () {
				 if (called) return
				 if (! document.body) return
				 try {
					 document.documentElement.doScroll ("left")
					 ready ()
				 } catch (e) {
					 setTimeout (tryScroll, 0)
				 }
			 }
			 tryScroll ()
		 }

		 // (3.2)
		 document.attachEvent ("onreadystatechange", function () {

			 if (document.readyState === "complete") {
				 ready ()
			 }
		 })
	 }

	 // (4)
  if (window.addEventListener)
  window.addEventListener ('load', ready, false)
  else if (window.attachEvent)
  window.attachEvent ('onload', ready)
  / * else // (4.1)
  window.onload = ready
	 * /
 } 
 readyList = []
 function onReady (handler) {
	 if (! readyList.length) {
		 bindReady (function () {
			 for (var i = 0; i <readyList.length; i ++) {
				 readyList [i] ()
			 }
		 })
	 }
	 readyList.push (handler)
 }

Using:

 onReady (function () {
  // ...
 })

8) getElementsByClass ()

Initially, it is not written by anyone specifically. Many developers wrote their own versions and the draw did not prove to be better than the rest.

The following function uses the built-in getElementsByClass method, if any, and searches for the items themselves in browsers where this method does not exist.

  if (document.getElementsByClassName) {
 getElementsByClass = function (classList, node) { 
 return (node ​​|| document) .getElementsByClassName (classList)
 }
 } else {
 getElementsByClass = function (classList, node) {
 var node = node ||  document,
 list = node.getElementsByTagName ('*'), 
 length = list.length, 
 classArray = classList.split (/ \ s + /), 
 classes = classArray.length, 
 result = [], i, j
 for (i = 0; i <length; i ++) {
 for (j = 0; j <classes; j ++) {
				 if (list [i] .className.search ('\\ b' + classArray [j] + '\\ b')! = -1) {
					 result.push (list [i])
					 break
				 }
			 }
		 }
	
		 return result
	 }
 }

classList - A list of classes separated by spaces, the elements to search for.

node - The context of the search, inside which node to look for

For example:

  var div = document.getElementById ("mydiv")
 elements = getElementsByClass ('class1 class2', div) 

7) addClass () / removeClass ()

The following two functions add and remove the element's DOM class.

  function addClass (o, c) {
  var re = new RegExp ("(^ | \\ s)" + c + "(\\ s | $)", "g")
  if (re.test (o.className)) return
  o.className = (o.className + "" + c) .replace (/ \ s + / g, "") .replace (/ (^ | $) / g, "")
 }
 
 function removeClass (o, c) {
  var re = new RegExp ("(^ | \\ s)" + c + "(\\ s | $)", "g")
  o.className = o.className.replace (re, "$ 1"). replace (/ \ s + / g, "") .replace (/ (^ | $) / g, "")
 } 

6) toggle ()

To be honest, there are probably more options for this function than it would be necessary.

This option does not in any way claim to be a universal "switch" function, but it performs the basic functionality of showing and hiding.


function toggle (), folk words

  function toggle (el) {
  el.style.display = (el.style.display == 'none')?  '': 'none'
 }

Note that there is not a word about display = 'block' in the function, instead the empty value display = '' is used . A blank value means a reset of the property, i.e. the property returns to the value specified in CSS.

Thus, if the display value for this element, taken from CSS is none (the element is hidden by default), then this toggle function will not work.

This version of the toggle function is beautiful and simple, but this and some other shortcomings make it not universal enough.

5) insertAfter ()

Like getElementsByClass , this function for some reason does not exist in the DOM standard. Perhaps to avoid duplication of functionality, because insertAfter is implemented only one line.

  function insertAfter (parent, node, referenceNode) {
  parent.insertBefore (node, referenceNode.nextSibling);
 }

4) inArray ()

It is unfortunate that this is not part of the built-in functionality of the DOM. But now we have the opportunity to always insert such remarks!

For search, this function uses the === check, which searches for an exact comparison, without casting the types.

The Array.prototype.indexOf method is not supported in all browsers, so it is used if it exists.

  inArray = Array.prototype.indexOf?
  function (arr, val) {
  return arr.indexOf (val)! = -1
  }:
  function (arr, val) {
  var i = arr.length
  while (i--) {
  if (arr [i] === val) return true
  }
  return false
  }

3, 2, and 1) getCookie (), setCookie (), deleteCookie ()

In javascript, there is no way to work properly with cookies without additional functions. I do not know who designed the document.cookie , but it's done extremely poorly.

Therefore, the following functions or their analogs are simply necessary.

  // returns cookie if there is or undefined
 function getCookie (name) {
	 var matches = document.cookie.match (new RegExp (
	  "(?: ^ |;)" + name.replace (/([\.$?* | {} \ (\) \ [\] \\\ / \ + ^]) / g, '\\ $ 1' ) + "= ([^;] *)"
	 ))
	 return matches?  decodeURIComponent (matches [1]): undefined 
 }

 // sets the cookie
 function setCookie (name, value, props) {
	 props = props ||  {}
	 var exp = props.expires
	 if (typeof exp == "number" && exp) {
		 var d = new Date ()
		 d.setTime (d.getTime () + exp * 1000)
		 exp = props.expires = d
	 }
	 if (exp && exp.toUTCString) {props.expires = exp.toUTCString ()}

	 value = encodeURIComponent (value)
	 var updatedCookie = name + "=" + value
	 for (var propName in props) {
		 updatedCookie + = ";" + propName
		 var propValue = props [propName]
		 if (propValue! == true) {updatedCookie + = "=" + propValue}
	 }
	 document.cookie = updatedCookie

 }

 // delete the cookie
 function deleteCookie (name) {
	 setCookie (name, null, {expires: -1})
 }

Arguments:

  • name name of the cookie
  • value cookie value (string)
  • props Object with additional properties for setting a cookie:
    • expires Cookie expiration time. Interpreted differently, depending on the type:
      • If the number is the number of seconds before the expiration.
      • If the object of type Date is the exact expiration date.
      • If expires in the past, the cookie will be deleted.
      • If expires is absent or equal to 0, the cookie will be set as session and will disappear when the browser is closed.
    • path Path for cookie.
    • domain Domain for cookie.
    • secure Only send cookies over a secure connection.

Last but often useful: byId

It allows the function to work the same when passing a DOM node or its id.

  function byId (node) {
  return typeof node == 'string'?  document.getElementById (node): node
 }

It is used simply:

  function hide (node) {
  node = byId (node)
  node.style.display = 'none'
 }

 function animateHide (node)
  node = byId (node)
  something (node)
  hide (node)
 }

Here both functions are polymorphic, they allow both the node and its id, which is quite convenient, because allows you not to make unnecessary conversions node <-> id.