Later Ctrl + ↑

С кодом будь строг. Интерпретатор

Строгий контроль написания кода уменьшает количество потенциальных ошибок. javascript допускает многие вольности, при том такие, которые могут породить трудно обнаруживаемые ошибки. Тут на помощь приходят редакторы и интерпретаторы. На уровне редакторов есть несколько инструментов, статического анализа кода, а со стороны браузеров доступен строгий режим выполнения javascrip кода.

Use strict

Ниже — примеры того, где строгий режим генерирует ошибки (полное описание отличий строгого режима). Надо отметить, что генерация ошибок происходит на этапе чтения исходного файла. Это значит, что функции, объявленные в нестрогой области видимости будут без проблем вызваны из «строгих функций». Так же не рекомендуется использовать строгий режим глобально, потому что вероятнее всего он сломает 3-d party код.

Нельзя присвоить значение необъявленной переменной. Код ниже в строгом режиме вместо создания глобальной переменной выдаст ошибку.
// Нестрогое поведение
function f () {
	a = 10;
}
f();
// Неожиданная глобальная переменная
console.log(a); // 10


// Строгое поведение
function f () {
	'use strict';
	a = 10;
}
f(); // ошибка

Запрещено дублирование имен свойств объекта.
(function () {
	var obj = {
		prop : true,
		prop : false
	}

	console.warn(obj); // {prop:false}
}());

(function () {
	'use strict';

	var obj = {
		prop : true,
		prop : false
	}

	console.warn(obj); // error
}());

Объект arguments — неизменяемый. Проблема заключается, в том, что изменяя arguments, изменение коснутся и аргументов, связанных с переменными, и самое неприкольное то, что примитивные значения тоже изменятся.
function f (a, b) {
	arguments[0] = 10;
	console.log(a, b);
}

f(1, 99); // 10, 99

Запрещено использование arguments.callee, и arguments.callee.caller. Говорят, что из-за наличия такого кода, интерпретатор не может оптимизировать код. Вместо этих конструкций рекоммендуется использовать named function expression.
(function waiter () {
	if (condition()) {
		action();
	} else {
		setTimeout(waiter, 50); // используем имя вместо arguments.callee
	}
}());

Ленивые вычисления в javascript

Ленивые, отложенные вычисления — такой подоход, когда значения вычисляются только тогда, когда в них возникает потребность, при этом есть возможность не вычислять это значение повторно при последующих вызовах функции. В javascript этот подход можно реализовать с помощью замыканий и переопределения функции изнутри самой себя.
function func_name () {
	var variable_foo,
		variable_bar;

	variable_foo = get_foo();
	variable_bar = get_bar();
	func_name = function () {
		return variable_foo + variable_bar;
	};
	return func_name.apply(this, arguments);
}
Фишка заключается в том, что значения variable_foo и variable_bar будут вычислены только при первом вызове функции. При этом-же вызове функция переопределит себя, захватывая scope с вычисленными переменными и себя-же родимую вызовет (при этом корректно сохраняя this, возвращаемое значение, а так же переданные аргументы).

Этот подход сработает и для методов:
var obj;

obj = {};
obj.method = function () {
	var variable_foo,
		variable_bar;

	variable_foo = get_foo();
	variable_bar = get_bar();
	this.method = function () {
		return variable_foo + variable_bar;
	};
	return this.method.apply(this, arguments);
}
Такие манипуляции дадут выгоду по производительности в случае, если метод или функция может быть не вызвана. В этом случае выигрыш составляет время вычисления кешируемых переменных. Или же случаи, когда функция вызывается два и более раз. В этом случае выигрыш составит время вычислений переменных помноженное на количество вызовов.

Из минусов: зависимость от имени функции или метода. Слишком просто будет допустить ошибку. Во избежание залепил сниппет для sublimetext2, который расскрывается в следующее
// srv
function_name = function () {

};
return function_name.apply(this, arguments);
(этот сниппет можно найти на gihub).

Что почитать

«Апгрейд обезьяны» А. Никонов

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

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

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

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

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

«Вы, конечно, шутите, мистер Фейнман» Ричард Ф.Фейнман

Автобиография чертовски интересного человека: мастера по починке радиоприемников и компьютеров, барабанщика, художника, взломщика сейфов и замков, физика-теоретика, нобелевского лауреата, человека, приложившего руку к созданию атомной бомбы. Эту книгу стоит прочитать только для того, чтобы оценить то, с какой искренностью Фейнман описывает свои переживания в той или иной ситуации. С одной стороны. И с другой с каким образом он подходит к решению проблем. Этот подход здравого разума и разностороннего рассмотрения задачи.
Как снять девушку в баре, получить доллар за патент атомной подводной лодки, выступить на мировом уровне с балетом: все это расскажет профессор Ричард Ф.Фейнман. А пока он расскажет почему поезда не сходят с рельс.
Кстати на ютубе есть несколько роликов, переведенных (спасибо большое) http://freetonik.com/

Javascript и common lisp синонимы

Мой второй подход к снаряду (practical common lisp). Синонимические конструкции из javascript и common lisp для самоободрения.
var o = (function () {
    var count = 0;

    return [function () {
        return count += 1;
    }, function () {
        return count -= 1;
    }, function () {
        return count;
    }];
}());
(defparameter *o* (let ((count 0))
					(list 
					 #'(lambda () (incf count))
					 #'(lambda () (decf count))
					 #'(lambda () count))))

Асинхронный итератор

При работе с googlemaps столкнулся с проблемой, когда большое количество маршрутов (более 20) при одновременной отрисовке принеприятно тормозило интерфейс. При это последний firefox тормозил сильнее, чем internet explorer. Для обхода проблемы решил, что если единовременно надо отрисовать больше, чем 15 маршрутов, я буду рисовать их с периодичностью в 50 мс. То есть между вызовами функций отрисовки будет проходит не менее 50мс (gist).
function iterate_async (arr, callback, timeout) {
	var index;

	index = 0;
	(function run () {
		if (index < arr.length) {
			setTimeout(function () {
				callback.call(arr, arr[index], index, arr);
				index += 1;
				run();
			}, timeout || 50);
		}
	}());
}
Из нюансов:
  • первый вызов синхронный
  • this в обработчике ссылается на обрабатываемый массив
  • обработчик получает аргументами элемент массива, индекс обрабатываемого элемента, сам обрабатываемый массив
  • если не указано явное время между вызовами обработчиков, то оно устанавливается в 50мс
И пример вывода элементов списка с вызовом обработчика через каждые 99мс:
var arr = ['masha','nadya', 'elena'];
iterate_async(arr, function (el, index, arr) {
    console.log(el + ' is #' + (index + 1));
}, 500);

javascript сниппеты для sublimetext2

Дошли руки оформить коллекцию javascript сниппетов для sublimetext2. Как человеку, работающему с кодом, мне хочется как можно меньше набирать текст, меньше тратить телодвижений на превращение мысли в код.

Установка вручную

  1. скачать архив с github
  2. распаковать в папку с package-ами (в редакторе: Preferences – Browse Packages...)

Установка через package control

  1. В sublimetext2 выполнить в консоли “Package Control: Add Repository”
  2. В поле ввода вставить урл https://github.com/podgorniy/js-snippets-st2
  3. Теперь сниппеты можно устанавливать как любой другой плагин из Package Control (в консоли Package Control: Install Package – js-snippets-st2)
Преимущество последнего: обновление сниппетов, автоматически при обновлении репозитория.

Субъективные переживания

Свойства сниппетов для sublimetext2, что меня порадовали:
  • сниппет появляется в автокомплите
  • сниппет доступен их командной строки (где его можно искать по описанию)
  • сниппет не статический, доступно нечто вроде ветвления (об это ниже)
Про “ветвление” (уверен, что этому явлению есть научное название). Стандартный сниппет get разворачивается в нечто следующее: getElementsByTagName(‘‘) при этом символ “T” выделен. Если начать набирать I, то развертка сниппета превратится в getElementById(‘‘). Это революция: зачем делать два отдельных сниппета для таких схожих методов, если можно обойтись одним? Попробуйте, с таким подходом код становится набирать на 55% приятнее и на 50% быстрее. Я дал себе обещание научиться писать подобные сниппеты и сдержал его. Позже расширил коллекцию частоупотребляемыми методами.

Tabstops указаны символом | (последовательность не указана, определяйте ее экспериментальным путем)
Однословные
  • a – arguments
  • de – debugger
  • d – document
  • l – location
  • p – prototype
  • w – window
  • q – querySelectorAll(‘‘)
Логгирование
  • cl – console.log();
  • cw – console.warn();
  • ci – console.info();
  • ct – console.timeStamp(‘‘);
Анонимщина
// sif
;(function () {
	|
}());

//sifs
;(function () {
	'use strict';

	|
}());

Теперь хитрые (с ветвлением, текстом по умолчанию и кучей tabstops)
Хитрые
  • set – setTimeout(function () {}, 50); по умолчанию стоит setTimeut, но достаточно начать набирать I, как сниппет превратится в setInerval (при этом есть возможность изменить время таймаута, вместо анонимной функции указать именованную. Последняя остановка внутри анонимной функции)
  • clr – clearTimeout(); так же позволяет очищать интервалы
//for
for (i = 0; i < arr.length; i += 1) {
	arr[i]
}
Цикл (стандартные ужасны) можно подменять имя массива, имя счетчика. Подразумевается, что счетчик уже объявлен (да, я объявляю переменные в начале функции)
  • ’ – ’ + + ’ крайне удобная вещь для быстрой вставки значений в строки.

Трюк с очисткой всех интервалов и таймаутов

Перечитывал JavaScript-Garden, в секции таймеров есть следующий код:
// удаляем "все" таймауты
for(var i = 1; i < 1000; i++) {
    clearTimeout(i);
}
Авторы утверждают, что не все таймауты могут быть завершены этим циклом, и это утверждение не вызывает сомнений. Но способ остановить все таймауты (и интервалы) все-же есть. Фишка в том, что функции setTimeout и setInterval возвращают id таймера, который при каждом вызове увеличивается на 1 (и для интервалоц и таймаутов). Таким образом, если создать интервал прямо перед очисткой всех интервалов, то его id будет наибольшим. Все, кто имеет меньший id будут очищены:
// удаляем все таймауты
var max_id;

max_id = setTimeout(function () {});
while (max_id--) {
    clearTimeout(max_id);
}
Earlier Ctrl + ↓