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

Using Java Scripts

JavaScript is a prototype-oriented scripting programming language. It is a dialect of ECMAScript.

JavaScript is usually used as an embedded language for programmatically accessing application objects. The most widely used in browsers as a scripting language to make interactivity to web pages. The main architectural features: dynamic typing, weak typing, automatic memory management, prototype programming, functions as first-class objects. JavaScript was influenced by many languages, and when developing, the goal was to make the language look like Java, but easy to use by non-programmers. JavaScript does not own 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, can do all these functions. But sometimes you need to do something without a framework. For different reasons. For this purpose this collection of useful functions is intended.

10) addEvent ()

Undoubtedly, the most important tool in managing events! Regardless of which version you use and by whom it is written, it does what is written in its name: it attaches 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 disadvantage is that it does not pass this to the handler for IE. More precisely, this does not attachEvent.

Simple workaround for this

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

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

This will solve the problem with the transfer of this, but the handler can not be removed in any way, since detachEvent must call exactly the function that was passed to attachEvent.

There are two ways to work around this 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)
 } 

Used as follows:

  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 a 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)
 } 

Used as follows:

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

9) onReady ()

For the initialization of the page, the window.onload event was historically used, which is triggered after the page and all objects on it are fully loaded: counters, pictures, 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 pictures and other objects that do not affect the document structure.

This is very convenient, because 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 entire load.

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 ()
			 }
		 })
	 }

	 // (four)
  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 ()

Originally not written by anyone specifically. Many developers wrote their own versions and the draw did not perform better than the rest.

The following function uses the built-in getElementsByClass method, if it exists, and searches for elements independently in those 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, with which to search for items.

node - search context, within which node to search

For example:

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

7) addClass () / removeClass ()

The following two functions add and remove an 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 different options for this feature than would be necessary.

This option in no way claims to be the universal function of the “switch”, 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'
 }

Please note that there is not a word about display = 'block' in the function; instead, the empty value is display = '' . An empty value means reset the property, i.e. the property returns to the value specified in the CSS.

Thus, if the display value for this element taken from CSS is none (the element is hidden by default), 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 , for some reason this function is not in the DOM standard. It is possible to avoid duplication of functionality, since insertAfter is implemented in just 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 DOM functionality. But now we have the opportunity to insert such comments all the time!

For the search, this function uses the === check, which searches by exact comparison, without type conversion.

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 with cookies without additional features. I do not know who designed the document.cookie , but it was done extremely poorly.

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

  // returns cookie if it 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 cookie
 function deleteCookie (name) {
	 setCookie (name, null, {expires: -1})
 }

Arguments:

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

Last but often useful: byId function

It allows functions to work in the same way when transmitting a DOM node or its id.

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

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, since allows not to do unnecessary transformations of node <-> id.