special

Использование Java скриптов

JavaScript — прототипно-ориентированный сценарный язык программирования. Является диалектом языка ECMAScript.

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

10 лучших функций на JavaScript

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

10) addEvent()

Несомненно, важнейший инструмент в управлении событиями! Вне зависимости от того, какой версией вы пользуетесь и кем она написана, она делает то, что написано у неё в названии: присоединяет к элементу обработчик события.

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 в обработчик для IE. Точнее, этого не делает attachEvent.

Простой обход проблемы this

Для передачи правильного this можно заменить соответствующую строку addEvent на:

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

Это решит проблему с передачей this, но обработчик никак нельзя будет снять, т.к. detachEvent должен вызывать в точности ту функцию, которая была передана attachEvent.

Существует два варианта обхода проблемы:

1) Возвращать функцию, использованную для назначения обработчика:

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

Используется так:

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

2) Можно не использовать this в обработчике события вообще, а передавать элемент через замыкание:

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

Используется так:

function handler() { 
 // используем не this, а переменную, ссылающуюся на элемент
 alert(elem) 
}
...

9) onReady()

Для инициализации страницы исторически использовалось событие window.onload, которое срабатывает после полной загрузки страницы и всех объектов на ней: счетчиков, картинок и т.п.

Событие onDOMContentLoaded - гораздо лучший выбор в 99% случаев. Это событие срабатывает, как только готов DOM документ, до загрузки картинок и других не влияющих на структуру документа объектов.

Это очень удобно, т.к. картинки могут загружаться долго, а обработчик onDOMContentLoaded может произвести необходимые изменения на странице и инициализацию интерфейсов тут же, не дожидаясь загрузки всего.

Для добавления обработчика можно использовать следующий кроссбраузерный код:

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

Использование:

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

8) getElementsByClass()

Изначально не написана никем конкретно. Многие разработчики писали свои собственные версии и ничья не показала себя лучше остальных.

Следующая функция использует встроенный метод getElementsByClass, если он есть, и ищет элементы самостоятельно в тех браузерах, где этого метода нет.

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 - Список классов, разделенный пробелами, элементы с которыми нужно искать.

node - Контекст поиска, внутри какого узла искать

Например:

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

7) addClass() / removeClass()

Следующие две функции добавляют и удаляют класс DOM элемента.

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

Если быть честным, наверное для этой функции существует больше различных вариантов, чем было бы нужно.

Этот вариант никоим образом он не претендует на звание универсальной функции-"переключателя", но он выполняет основную функциональность показывания и спрятывания.

функция toggle(), слова народные

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

Обратите внимание, в функции нет ни слова про display='block', вместо этого используется пустое значение display=''. Пустое значение означает сброс свойства, т.е. свойство возвращается к значению, указанному в CSS.

Таким образом, если значение display для данного элемента, взятое из CSS - none (элемент спрятан по умолчанию), то эта функция toggle не будет работать.

Этот вариант функции toggle красив и прост, однако этот и некоторые другие недостатки делают его недостаточно универсальным.

5) insertAfter()

Как и getElementsByClass, этой функции почему-то нет в стандарте DOM. Возможно, чтобы избежать дублирования функционала, т.к. insertAfter реализуется всего одной строчкой.

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

4) inArray()

Очень жаль, что это не часть встроенной функциональности DOM. Зато теперь у нас есть возможность всё время вставлять такие вот замечания!

Для поиска эта функция использует проверку ===, которая осуществляет поиск по точному сравнению, без приведения типов.

Метод Array.prototype.indexOf поддерживается не во всех браузерах, поэтому используется, если существует.

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 и 1) getCookie(), setCookie(), deleteCookie()

В javascript нет способа нормально работать с cookie без дополнительных функций. Не знаю, кто проектировал document.cookie, но сделано на редкость убого.

Поэтому следующие функции или их аналоги просто необходимы.

// возвращает cookie если есть или undefined
function getCookie(name) {
	var matches = document.cookie.match(new RegExp(
	 "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
	))
	return matches ? decodeURIComponent(matches[1]) : undefined 
}

// уcтанавливает 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

}

// удаляет cookie
function deleteCookie(name) {
	setCookie(name, null, { expires: -1 })
}

Аргументы:

  • name название cookie
  • value значение cookie (строка)
  • props Объект с дополнительными свойствами для установки cookie:
    • expires Время истечения cookie. Интерпретируется по-разному, в зависимости от типа:
      • Если число - количество секунд до истечения.
      • Если объект типа Date - точная дата истечения.
      • Если expires в прошлом, то cookie будет удалено.
      • Если expires отсутствует или равно 0, то cookie будет установлено как сессионное и исчезнет при закрытии браузера.
    • path Путь для cookie.
    • domain Домен для cookie.
    • secure Пересылать cookie только по защищенному соединению.

Последняя, но зачастую полезная: функция byId

Она позволяет функции работать одинаково при передаче DOM-узла или его id.

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

Используется просто:

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

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

Здесь обе функции полиморфны, допускают и узел и его id, что довольно удобно, т.к. позволяет не делать лишних преобразований node <-> id.


Created/Updated: 25.05.2018