Как стать автором
Обновить

Комментарии 127

а ведь мне нравился JS, раньше, полчаса назад, когда я ещё не прочитал эту статью
Это у вас отношения на расстоянии что ли — ничего про язык не знали, он вам абстрактно нравился?
Эти ошибки совершают разве что только джуниоры.
НЛО прилетело и опубликовало эту надпись здесь
Третий пункт (про утечки памяти) неочевиден и мало где хорошо описан. В остальном — да, хоть и strict mode далеко не все используют.
И даже в этом примере (пункт 3) не все так однозначно с утечками памяти, оптимизаторы могут убрать из замыкания переменную если она не используется в нем, и тогда утечка памяти не возникнет. В этом случае
var theThing = null;
var replaceThing = function () {
    var priorThing = theThing;  // hold on to the prior thing
    theThing = {
        longStr: new Array(1000000).join('*'),  // создаем 1Mб объект
        someMethod: function() {console.log('xxx');}
    };
};
setInterval(replaceThing, 1000);

оптимизатор исключит из замыкания priorThing, и утечки не будет

а вот в этом случае

var theThing = null;
var replaceThing = function () {
    var priorThing = theThing;  // hold on to the prior thing
    theThing = {
        longStr: new Array(1000000).join('*'),  // создаем 1Mб объект
        someMethod: function() {console.log(eval(''));}
    };
};
setInterval(replaceThing, 1000);

возникает eval(), который понижает уровень оптимизации, так что и для не джуниоров это не всегда очевидно, поскольку действия оптимизаторов не стандартизированы, т.е. их работа остается за кадром
var theThing = null;
var replaceThing = function () {
    var priorThing = theThing;  // hold on to the prior thing
    theThing = {
        longStr: new Array(1000000).join('*'),  // создаем 1Mб объект
        someMethod: function() {console.log('xxx');}
    };
};
setInterval(replaceThing, 1000);


то что Вы описали не есть работа оптимизатора, просто так работает сборщик мусора.
в данном примере после отработки функции replaceThing, не остается ни одной «живой» области видимости с записанной переменной priorThing, поэтому сборщик и очищает память.

другими словами после отработки функции сборщик мусора пытается очистить память и руководствуется только одним — нужна ли эта переменная еще кому-то?
Согласно источнику, мною очень уважаемому при создании функции, в моем примере someMethod:function() {...} внутреннему свойству функции [[Scope]] будет присвоено значение текущего узла цепочки областей видимости в этом узле согласно стандарту уже содержится ссылка на priorThing, далее это ([[Scope]]) свойство уже не меняется никогда. А теперь цитата из источника
Как уже было сказано выше, в целях оптимизации, когда функция не использует свободные переменные, реализации могут не запоминать лексический контекст, однако в спецификации ECMA-262-3 об этом ничего не сказано; поэтому формально (и по технического алгоритму) – все функции запоминают [[Scope]] ещё при создании.

Таким образом когда вызывается функция replaceThing, в этот момент начинается разбор и интерпретация тела этой функции, будет создан theThing, его свойству someMethod будет присвоена ссылка на функцию-выражение, свойство [[Scope]] которой будет указывать на объект переменных (VO) вышестоящего контекста, которым является функция replaceThing. И в этом объекте согласно стандарту должна быть priorThing. И если ее там не будет, то только в процессе создания функции replaceThing оптимизатор проанализировав ее тело может принять решение о том включать ее в VO или нет. Т.е. еще до исполнения (активизации) функции replaceThing определяется судьба priorThing. А сборщик мусора начинает свою работу на много позже, и если оптимизатор не исключит из VO priorThing, то мы всегда сможем добраться из глобальной переменной theThing до всех созданных в предыдущих вызовах объектов, а в следствии чего сборщик не сможет удалить эти объекты.
дополню, когда оптимизатор встречает в теле функции eval, то начинает судорожно биться об стенку, ведь он не знает, что там сделает этот черт, и тогда как правило принимает решение в пользу темных сил, и в объект переменных записывает все без разбора
А вот мне интересно, если так много плюсующих ваше утверждение людей, будьте добры напишите мне кто-нибудь, пожалуйста, хоть один пример того, в чем может ошибаться профи, но или люди, которых вы считаете не джуниорами, с точки зрения знания языка, повторяю только с точки зрения языковых конструкций, а не того что можно сделать с помощью этого языка. Если вы считаете, что все остальные, кто не джуниоры понимают и знают все нюансы языка, то тогда можете и не писать, но мне кажется знать каждый все нюансы не может. А если мне это правильно кажется, то еще раз, хоть один пример, того что может не знать не джуниор, напишите пожалуйста.
Сколько будет «5 воробьёв + 12 яблок». На это вопрос я бы ответил — «Ты что, идиот?». А на вопрос «12 яблок + 5 воробьёв» я бы ответил: «отвали от меня, задрал со своими тупыми вопросами».
Вот языки, которые так себя ведут (даже «великий и ужасный» C, не говоря уже о всяких python'ах) я уважаю. А JavaScript, который «тихо» тебе «поможет» и в ответ на такие вопросы вернёт-таки какую-нибудь чушь — нет. Из распространённых есть только два языка подобной степени убогости: JavaScript и PHP. Но если PHP можно спокойно себе выкинуть на помойку и перейти на что-то поприличнее, то с JavaScript'ом этот номер не пройдёт.
За все… ну тысяч 10-15 строк на JS я точно написал.
Так вот, за все эти 10-15 тысяч строк мне ни разу не пришлось складывать массивы или объекты с другими массивами или объектами)
Написал более 50 тысяч строк кода на JS точно и ни разу не приходило на ум складывать объект с массивом. Очевидно же, что получится хрень какая-то. Полностью разделяю мнение TheShock по этому вопросу (выше в этой ветке).
А результат такой потому, что сам виноват :)
«Неджуниор» такие ошибки не совершит исключительно исходя из собственного опыта: даже за 2-3 года программирования на яваскрипте все эти неочевидные тонкости с замыканиями, ссылками, приведением типов и областями видимости встретятся не раз и их решения доведутся до автоматизма практикой. Перефразирую автора исходного комментария: «Такие ошибки могут допустить только люди без практического опыта программирования на яваскрипте» (что, в общем-то, и тождественно «джуниорам»).
Позволю себе небольшую аналогию: представьте, что у вас есть права категории «С» (грузовая категория), которые вы получили десять лет. То есть формально вы умеете управлять грузовиком, но когда вы сядете в салон, начнётся мучительное зачитывание некоего чеклиста: «так, снять с ручника, завести, прогреть, проверить давление в тормозном контуре ». И теперь представьте, что в этот же грузовик садится водитель с реальным стажем в 10 лет вождения именно этого грузовика. Все те действия, что вы пытались запомнить и осмыслить, он сделает на автомате только потому, что у него много практики.
Ну вот видите, и даже вы не привели пример того вопроса, на который может не ответить и «неджуниор», тогда утверждение «Эти ошибки совершают разве что только джуниоры» неконструктивное, в общем то пустое, его тогда можно интепретировать так, если вы что-то не знаете, то вы джуниор, а это не всегда так.
Ошибки описанные в статье совершает человек, не изучивший javascript, т.е. буквально не прочитал как язык должен работать и занимается т.н. «Voodoo programming», а не созданием инженерных решений.
Все ошибки в статье идут от реального непонимания того что происходит, а не просто вещи о которых все знают, но иногда ошибаются.
Я приведу пример что же реально случается на проектах, вызывая путаницу:
— потеря запятых (где угодно, хоть в объявлении переменных, периодически выкидывая переменные в глобальный скоуп,
— постоянно забывают какие методы изменяют объект, а какие возвращают новый объект, сохраняя старый (путаница вообще связанная с мутабельностью данных)
— события в DOM поднимаются и иногда в некоторых ситуациях мы ловим уже отработанные и отрабатываем еще раз, случайно, конечно
— вытаскивая value из элементов DOM получаем строки, а не то что положили
— «плавающий набор параметров». иногда мы думаем что сможем всегда контроллировать входящие переменные в функцию и позволять себе догадываться из типов переменных о структуре аргументов. почти всегда это провал, тем более когда речь идет о статической проверке кода.
Если что-нибудь еще вспомню — обязательно напишу. А статья бесполезная — куда умнее будет мельком пролистать спеку языка.
Джуниоры чаще всего только что прочитали Флэннагана и помнят об этих ошибках. Своими глазами видел, как senior создал переменную без var. А 'use strict' вообще мало кто использует, к сожалению.
А как же JSHint/JSLint? Неужели, их никто из вашего окружения не использует? Они же сразу потребуют от программиста поставить 'use strict'.
По моему глупая уверенность. Абсолютно любой разработчик может ошибиться, просто джуниоры это делают чаще сеньеров.
Зачем использовать чистый javascript? Сравните, ваш код на Javascript, вариант №1
Game.prototype.restart = function () {
	this.clearLocalStorage();
	var self = this;   // сохраним ссылку на 'this', пока это все еще 'this'!
	this.timer = setTimeout(function(){
		self.clearBoard();    // все в порядке
	}, 0);
};


Вариант №2:
Game.prototype.restart = function () {
	this.clearLocalStorage();
	this.timer = setTimeout((function(){
		this.clearBoard();    // все в порядке
	}).bind(this), 0);
};


И теперь почему бы не посмотреть в сторону CoffeeScript, исполненного ruby-плюшек?
Game::restart = ->
	@clearLocalStorage()
	@timer = setTimeout ( => @clearBoard() ), 0


Или еще более крутого LiveScript, движимого мощью Haskell? (это незаметно на указанном участке кода)
Game::restart = ->
	@clearLocalStorage!
	@timer = setTimeout ( ~> @clearBoard! ), 0

Непонимание глубинных процессов не нивелируешь высокоуровневыми фреймворками или диалектами. Тот, кто не знает этих основ, не нуждается в кофе, тот, кто пользуется кофе, скорее всего и так знает эти десять пунктов.
В любом случае, подход «если я не понимаю какой-то процесс, то я его прикрою абстракцией сверху» очень опасен, хотя сразу это и не очень очевидно.
Дело не в сокрытии абстракций, а в уменьшении монструозности выражения существующих. Например, ни CS, ни LS не решают за программиста, биндить ли функцию к текущему this или нет — это решает программист, но насколько компактнее же это выглядит!

Вот еще пример из статьи:
var elements = document.getElementsByTagName('input');
var n = elements.length;    // предположим, у нас есть 10 элементов
var makeHandler = function(num) {  // внешняя функция
    return function() {   // внутренняя функция
        console.log("This is element #" + num);
    };
};
for (var i = 0; i < n; i++) {
    elements[i].onclick = makeHandler(i+1);
}

И его воплощение в CoffeeScript:
for el, i in document.getElementsByTagName 'input'
    do (i) ->
        el.onclick = -> console.log "This is element ##{num}"

Никакие абстракции при этом не скрыты, но и код не превратился в %writeonly_programming_language%. Так почему же не сделать себе проще жизнь? :)
Каким бы сахаром вы не посыпали ваш код, это не спасет от ошибок, вызванных непониманием базовых основ JavaScript.
Да где же я писал, что спасет, или что понимание базовых основ JavaScript не нужно? Или, может, где-то приведенный мною пример скрывает какие-то детали реализации, и можно, не зная этого, сделать какую-то фатальную ошибку, или написать программу, которая выглядит правильно, но не работает из-за того, что автор не учел какие-то JS-специфичные тонкости?

Я лишь о том, чтобы делать точно то же самое, что и просто в JS, но при этом создавать более легко читаемый, а, значит, и более легко сопровождаемый код. Но нет, меня уже все записали в апологеты построения строк путем дописывания символов по одному, и радуются тому, какую я чушь написал.
Как ваш первый комментарий вообще относится к данной статье?
На вопрос «зачем» я могу легко ответить «затем». К примеру есть некоторая группа разработок, не позволяющая использовать фреймворки.
Сделать циклическую ссылку с последующей утечкой памяти можно и на кофескрипте, ума много не нужно. Только без знания нативного яваскрипта решение этой ситуации может стать серьёзной проблемой, потому что нужно как минимум понять причину. Ситуаций, когда при использовании абстракций приходится спускаться на уровень ниже, может быть масса. И это касается не только яваскрипта.
Впрочем, я не хочу участвовать в очередном унылом холиваре про препроцессоры, извините. Нравится этим пользоваться — пользуйтесь, бога ради. Только не нужно это советовать как универсальный способ решения проблем, вызванных недостаточным уровнем знаний яваскрипта и его рантайма (а пост ведь об этом).
В том же coffee надо хорошо понимать, во что будет скомпилирован код. Если код вашего же примера обернуть в функцию, мы получим неявный return коллекции.
Поверьте, проще на ванили и когда все прозрачно. Я куда быстрее найду ошибку или пойму что вообще происходит. Плюс ко всему неизвестен результат компиляции, может компилятор использует такой кошмар, что уж лучше без него.
Это мне напоминает тех, кто удивляется тому, что можно без jQuery и оно не фрэймворк.
TypeScrtipt — тоже ничо так.
Game.prototype.restart = function () {
    this.clearLocalStorage();
    this.timer = setTimeout((function(){
        this.clearBoard();    // все в порядке
    }).bind(this), 0);
};


Самое главное в этом примере узнать как работает
(function(){}).bind()
и по чему именно так.
Ваш коммент вообще не в тему
Про память есть интересная библиотека node-memwatch, которая облегчает слежку за памятью в модулях для ноды.
НЛО прилетело и опубликовало эту надпись здесь
По поводу пункта №8 лучше использовать метод bind,
и вместо
var whoAmI = obj.whoAmI;

написать
var whoAmI  = obj.whoAmI.bind(obj);

Для любителей jQuery, есть многофункциональный метод $.proxy.

А то что указано как «решение» в статье, выглядит, имхо, немного странно.
Пример и вправду притянут, но сама ошибка типична и по сути та же, что и первая рассмотренная в статье. Новичкам, часто сложно понять, что this определяется в момент вызова функции. И одна и та же функция может отработать по разному, из-за разных контекстов.
Все примеры здесь в основном сложные, точнее, требующие продвинутых знаний о JS, которых у большинства или нет, или они неточные и их стараются избегать или тщательно отлаживать. Ошибки же чаще совершаются в простых вещах, единственный представитель которых — п.4 (приведение типов). Поэтому больше соответствовали бы названию статьи ошибки в приведении типов или по необычному поведению примитивов JS. Много такого описано, например, в переводной статье "20 и 1 примочка Javascript, которые я никак не могу запомнить". А к сложным вещам по мере изучения, программист подходит более ответственно.

Первое, что вспоминается из простого:

4.а. '-1' < '-10' //true

Ошибки — чаще в нестандартной простоте.

Или

077 + 3 // 66.
1+'1' // 11

Когда это вуалируется в переменных — раздолье для ошибок.

Или

var о = 2; // русская буква
console.log(o); //exception на латинской, и это ещё хорошо, когда сразу exception...

Вот это — частые ошибки, а не с наследованием или неправильным его пониманием.
НЛО прилетело и опубликовало эту надпись здесь
что-то не могу припомнить ЯП который в блоке for/foreach создает изолированную область видимости (пункт 2 в посте)…
C++?
#include <cstdio>

int main(int argc, char *argv[]) {
	int i = 1000000;
	
	printf("%d\n", i); /* 1000000 */
	
	for (int i = 0; i < 10; i++) {
		printf("%d ", i); /* 0 1 2 3 4 5 6 7 8 9 */
	}
	
	printf("\n%d\n", i); /* 1000000 */
	
	return 0;
}
точно :)
pascal, modula II.
про oberon не вспомню, правда

а не, вру, в P и M2 надо сперва переменную раньше создать.
Почему-то думал C# и Java так же себя ведут, как C++, я ошибался. Ну хоть Lua подходит:
local i = 1000
io.write(i, "\n") -- 1000
for i = 0, 9 do
    io.write(i, " ") -- 0 1 2 3 4 5 6 7 8 9
end
io.write("\n", i) -- 1000
Они ведут себя похожим образом, просто не позволяют объявить в одной функции две одноименные переменные с перекрывающимися областями видимости. Но это ограничение не отменяет того факта, что объявленная в цикле переменная не будет видна за пределами цикла.
Perl
нет, перл не подходит

#!/usr/bin/perl

$i = 10;
for ($i = 0; $i <=5; $i++) { print "\n", $i; }
print "\n", $i, "\n";

результат
0 1 2 3 4 5 6
но можно сделать
for (my $i = 0; $i < 10; $i++) {}
Ну так, my и надо делать, иначе ты будешь использовать переменную из контекста выше.
В Javascript'е же даже var внутри for не делает изолированную область.

нет, перл не подходит

так что перл подходит, подходит.
В Javascript'е же даже var внутри for не делает изолированную область.

let
Вы говорите
нет, перл не подходит

и приводите пример, где в for нет my:
#!/usr/bin/perl

$i = 10;
for ($i = 0; $i <=5; $i++) { print "\n", $i; }
print "\n", $i, "\n";


Ну если я int забуду в цикле for, то он тоже будет «не подходить»
...
for (i = 0; i < 10; i++) {
   printf("%d ", i); /* 0 1 2 3 4 5 6 7 8 9 */
}
...

Результат:
1000000
0 1 2 3 4 5 6 7 8 9
10

Тем не менее про C++ вы почему-то согласились, что он подходит.
Про утечку памяти при использовании цикличиских ссылок актуальная информация? Мне кажется, это было возможно на старых js движках. Это известная проблема и все ее научились решать.

Здесь javascript.info/tutorial/memory-leaks#circular-references-collection еще нашел пример похожий на ваш, пишут что все хорошо.
Эта информация актуальна для IE. Там DOM — это все еще ActiveX, а ActiveX неподвластен сборщику мусора, у него есть только подсчет ссылок.
Это вы про «недавно» выпущенные IE >= 9 или про IE <= 8?
Неужели все-таки поправили? Как-то не верится, IE и утечки памяти — это же как Сбербанк и очереди...
Более свежая статья на эту тему: learn.javascript.ru/memory-leaks.

В английском варианте могут быть неточности, это всё же первая версия была, я сейчас только русский учебник поддерживаю.
> Почему это происходит? Всё дело в контексте. Когда вы вызываете setTimeout(), то на самом деле вызываете window.setTimeout(). В результате, анонимная функция, передаваемая в setTimeout(), определяется в контексте объекта window, который не имеет метода clearBoard().

Неверное объяснение. То, что обработчик таймаута вызывается в глобальном контексте никак не связано с тем, что setTimeout лежит в window.
а какое правильное? потому что сложенная функция определяется уже в лексическом контексте внешней функции?
Нет. Если функция вызывается просто как функция — someFunc(), то она вызывается в глобальном контексте. И не важно, где и как она была определена.
а если как метод, то будет ошибка, что this вложенной функции undefined? Непонятно, почему замыкания работает для переменной, но не для this
this никогда не бывает undefined. this — это не переменная, а ключевое слово, которое дает доступ к контексту исполнения функции. Если функция вызывается как метод некоего объект, то она будет исполняться в контексте этого объекта и this в данном случае будет ссылаться на этот объект. Судя по вопросам, который вы задается, вам интересен язык и вы планируете всерьез им заниматься. В таком случае, без тщательного изучения языка вам не обойтись. А для полного осознания замыканий я бы рекомендовал вам тщательно проработать примеры из того же Флэнагана, пусть он и занудный, но раскладывает все по полочкам. Ну и конечно практика, без нее все эти книги просто макулатура.
js мне что-то вообще не хочется заниматься. Слишком уж он зависит от реализации браузера. Учу, потому что надо. Это используется везде.

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

Вот и непонятно, почему этот this нельзя просто через замыкания протолкнуть во вложенные функции метода. Ведь извне отдельно вложенную функцию мы не можем вызвать. Даже если вернем ее, то она будет выполняться в лексической области видимости, в которой объявлялась
this никогда не бывает undefined
(function() { 'use strict'; console.log(this); })();
7. Неправильное наследование через прототипы
Странный раздел статьи. Непонятно, как его содержимое связано с названием.
var thirdObj = new BaseObject('unique');
console.log(thirdObj.name);  // -> в 'unique'

delete thirdObj.name;
console.log(thirdObj.name);  // -> в 'default'

А для этого куска кода уже вам в ответ нужна статья «10 ошибок при проектировании API».
Само по себе это не является ошибкой. И дело тут не только в производительности. Дело в том, что когда вы передаете строковую переменную первым аргументом в setTimeout или setInterval, она будет передана конструктору Function для преобразования в новую функцию. Этот процесс может быть медленным и неэффективным. Альтернативой является использование функции в качестве первого аргумента:


Странный набор текста. «Дело тут не только в производительности...» а далее описывается лишь производительность: «Этот процесс может быть медленным и неэффективным.».
Да и к тому же, лично я не разу не видел, чтобы кто так делал. Так что пункт ваще не понятно зачем
Лет 8-10 назад писать строки вместо функций было общепринятым, даже в учебниках.
Жесть, хорошо, что 10 лет назад я еще не был к этому причастен
К сожалению, я встречал передачу строки в конструктор Function в одной из JS-библиотек.
Эта операция совершенно корректна, и не приводит к снижению производительности, ведь строка парсится лишь один раз — а потом функция может сколько угодно раз использоваться. Более того, такой подход иногда еще и ускоряет выполнение программы.
Никто и не отрицает, что такая операция корректна. Я не исключаю, что в каких-то жизненных ситуациях без Function не обойтись, но в 99% его использования стоит избегать.
Если вас не затруднит, приведите пожалуйста пример, когда использование конструктора ускоряет выполнение программы по сравнению с литеральной формой записи функции.
Вот простой синтетический тест (очень синтетический), и в нем итеративное создание одной и той же функции через конструктор просто трещит по швам:
jsfiddle.net/kuv8m8na/ против jsfiddle.net/cb51fzp2/
И не мудрено, потому что конструктор Function компилирует функцию на каждой итерации, в то время как при использование функционального литерала этого не происходит.
Ваш пример некорректен (но, как будет видно дальше, доказывает ваши слова). Вы сравниваете работу разных функций. Первая функция полностью копирует объект, вторая — копируют только те свойства объекта, которые существовали на момент определения функции. Я доработал ваш тест, чтобы результат работы функций был идентичен jsfiddle.net/kuv8m8na/2/.
Вариант с использование конструктора выигрывает приблизительно в 2 раза (50мс на моей машине). Красивый пример, не поспоришь.
Но, за это вы платите абсолютно нечитаемым кодом, проблемами при отладке (тела функции как такового нет, функция записана в одну строчку, остановиться на конкретной строчке вы не можете) и сложностью в поддержке.
На мой взгляд это гораздо важнее, чем выигрыш 50мс на 100000 итераций.
Разумеется, все это важнее — до тех пор, пока создание новых объектов не становится узким местом. Разумеется, без профилирования использовать программирование на лету не стоит никогда.
Да я вобщем тоже видел в доках SmartClient'а, но чтобы так делать, увольте
А какая там в принципе может быть разница (кроме репейнта)?
Ну, теоретически, хотелось что-то выиграть не трогая живой DOM n раз.
Ну, репейнт и выиграли…
При работе с большим количеством массивных кусков DOM, выигрыш от использования DocumentFragment и соответственного сокращения количества репейнтов можно измерять секундами.
Насколько большими? Я хочу запилить тест-кейс
В моем тесте вот такой вот кусок html:

<div class="item">
    <input type="checkbox" data-time="1408354462252">
    <span class="span-text span-text__active">20</span>
    <span class="span-second" style="display: inline;">span</span>
    <input class="simple-input">
</div>

в количестве 5000 штук с использованием DocumentFragment отрисовывается за 3-4 секунды, без него — 8-9 секунд.
Можно взять более сложный html-блок и уменьшить количество.
Ну значит у меня в тестах где-то ошибка, либо Chrome как-то хитро всё оптимизирует, что результаты одинаковые получаются.

jsperf.com/dynamic-update/2
Хотел было привести простой пример, где использование DocumentFragment дает прирост, но не тут то было. Судя по всему, современные браузеры настолько все оптимизируют, что в большинстве случаев разницу не почувствуешь. В моем тесте, о котором я говорил, тестируется производительность моей библиотеки. Сам тест получился очень массивный и в нем действительно использование DocumentFragment дает выигрыш чуть ли не в 2 раза. В попытках докопаться до того, где же все-таки проседает, я остановился на месте, где в одной из функций jQuery есть обращение к свойству объекта CSSStyleDeclaration. И именно это обращение просаживает производительность в варианте без DocumentFragment.
Если мне удастся вычленить эту проблему и сделать под нее наглядный пример, я об этом обязательно напишу.
Ну я для себя решил всё-таки через DocumentFragment рендерить коллекции, теоретически тут есть ещё куда оптимизировать, хотя сейчас разница только в FF на синтетике.
Ну он вообще-то помечен как перевод.
Простите меня за мою невнимательность. =)
Здравствуйте. У Вас есть в моём мире косяк такого плана:

При добавлении в моём мире домена в зоне.сайт.онлайн, бяда…

Баг номер 1
Добавляем в статус:
Добавление проходит, сайт виден, например — объявлений.сайт
Кликаем попадаем в никуда, т.к. ссылка битая… на странице в кодировке UTF-8, а редиректит на
расшифровываем 7-bit ASCII → CP866 + CP1251 → KOI8-R… вообщем в никуда редиректит.

Баг номер 2
Добавляем сайт в punycode… и итоге видим на своей странице:
вместо xn--90acjmfjpd3i2b.xn--80aswg — обрезает до xn--90acjmfjpd3i2b.xn

Проблема видимо от того, что ваш сайт был недавно в кодировке CP1251, а теперь UTF-8
И где-то в далёких закромах… остались конфликты. Пожалуйста, поправляйте.

А какую книгу лучше читать начинающему?
Посмотрел курс от специалиста (про прототипы вообще толком ничего не было), потом head first последний прочитал. Сейчас подробное руководство читаю, но она нереальная нудотина со сплошной теорией.

Знакомый говорит, чтобы я забил на js и учил jquery. Сам он хорошо зарабатывает, но чистого js не знает.

П.с. Переучиваюсь с дизайнера.
Ну по хорошему надо начинать с чего-то общего, но вобще Подробное руководство Фленагана
Я с него и начал. А после 200 страницы начал читать Head First на английском. Фленагана сейчас продолжаю читать, но очень он занудно и сложно пишет. Практических занятий нет. Куча воды про Java, C++ и заумных слов.
Ну можно посмотреть в сторону learn.javascript.ru тогда, ну и практика, конечно

На этом же сайте есть ещё курсы за деньги, но они мне не особо понравились, если честно.
спасибо за советы. Думаю уже быстро и без зубрежки добить подробное руководство и перескочить на jquery.
спасибо, но что-то мне не хочется больше читать новые книги по js. Тут столько нюансов из-за кроссбраузерности. Лучше потом про библиотеке. Там хоть голова за это особо болеть не будет.
Прототипное наследование я понял. Перечитал в нескольких книгах пока не понял.

А вот идея модулей мне непонятна. Присваивают глобальной переменной результат вызова безымянной функции, в которой только декларации функций. Как потом эти внутренние функции вызывают, не знаю
Я где-то читал, что «в js большая часть времени уходит на изучение паттернов», без их понимания код лучше точно не станет, а разобраться с jQ можно за 2 дня, что бы овладеть им на достаточном на первое время уровне.

Если будете разбираться с jQ гуглите паралельно «jquery best practices» и пр. всё что найдете поможет быстрее въехать. И посмотрите как в jQ UI используется Widget Factory, достаточно занимательно.
Спасибо.

Я, наверное, дочитаю руководство и перескочу на пхп. Хочется попробовать уже что-то наподобии сайта сделать и то, что не зависит от браузеров. Потом вернусь на js с его паттернами, если понадобится.

Пока мне js напоминает конкретный гемморой. В основном из-за модели реализации ИЕ. Мне такое не нравится. Хочется единый стандарт, а то больше усилий уходит на запоминание костылей )
PHP не избавит вас от мук клиентского программирования. И вы не думайте, что на серверной стороне все так просто)
А зачем вы запоминаете костыли? Большую часть проблем кроссбраузерности решает тот самый jQuery.
Спасибо. Наверное, действительно слишком много внимания костылями в книге уделяют, а не базовым основам языка. )
Лучше всего модули понимаешь когда начинаешь использовать RequireJS (+ получаешь бесплатно сборщик).
Эти «внутренние функции» находятся внутри литерала объекта, который возвращается — и попадает в глобальную переменную.
то есть они просто становятся методами 1 объекта как Math.random()? Тогда зачем все так сложно делать, когда можно создать просто объект со всеми методами?
Для того, чтобы у модуля были приватные переменные и функции, которые не видны снаружи.

var Module = (function() {
  var foo = 5; // Приватная переменная, не видна снаружи
  function bar() { } // Приватная функция, не видна снаружи

  return {
    baz: "Hello, world!", // Публичное поле
    do_something: function() {}, // Публичный метод
  };
})();

Обратите внимание — литерал объекта, который идет после return — попадает в переменную Module, поэтому к baz и do_something можно добраться как Module.baz и Module.do_something. А вот foo и bar снаружи замыкания не видны.
Позволю себе не согласиться, в JS ООП не эмулируется. JS — самый что ни на есть объектно-ориентированный язык. Наверное вы имели в виду эмулирование классического наследования?! Знать об этом не помешает, но лично я бы не советовал углубляться в эту область.
Я бы посоветовал еще вот эту книгу
shop.oreilly.com/product/9780596806767.do
А что касается jQuery-программирования, то это тупиковая ветвь. jQuery — потрясающий инструмент, но без знаний самого языка вам будет крайне сложно развиваться.
Ну да, классического
Начинайте с того, что прикрепляйте к html JQuery-сниппеты. Но постоянно пытайтесь углубляться. Впринципе, это неплохой способ.
а HTML&CSS программисту не обязательно же отлично знать? Там столько нюансов из-за IE8 и подобных
Можно поучить исключительно IE9+. IE8 поддерживают уже только совсем закостенелые разработчики.
Спасибо за ответы.

я прочитал по CSS3 большую книгу.

П.С, Вообще больше хотелось бы дизайном заниматься (наверное, потому что знаю как все сделать), но на программистов спрос больше + зп выше :)
Попробуйте какой-нибудь юнити?
Вам понадобится представление о DOM модели, скорей всего
7. Неправильное наследование через прототипы


Вы рекомендуете в этом разделе паттерн, которые негативно скажется на производительности, если эти объекты используются в горячих методах, поскольку он приводит к полифорфизму формы («скрытого класса») объекта в зависимотси от того имеет ли свойство значение по умолчанию или нет.
Одним из преимуществ JavaScript является то, что он автоматически преобразует любое значение к булевому значению, если оно используется в булевом контексте

Неправда ведь
Вообще правда. Было бы лучше, если бы автор статьи обобщил (я не стал менять, хотя и очень хотелось) — если значение одного типа используется в контексте, требующем значение некоего другого типа, интерпретатор JavaScript автоматически пытается преобразовать это значение.
Операторы равенства имеют свою логику при сравнении. Т.е. нельзя сказать, что операнды оператора равенства используются в том или ином контексте.
7. Неправильное наследование через прототипы

Вы предлагаете вариант, который сам может содержать грубейшую ошибку. Только immutable данные могут быть прописаны в прототипе. Например примитивы или строки. Иначе изменение значений внутри объекта данных, прописанного в прототипе приведет к их изменению для всех объектов созданных из данного класса.
Только immutable данные могут быть прописаны в прототипе.

Вы слишком категоричны. Т.е. функции в прототип класть нельзя?
Да и в объектах, находящихся в прототипе, я вижу ничего страшного, если это сделано осознанно.
А что функции уже стали данными? И если да, то они стали mutable?
Если целью ставится shared object, то использование возможно, хотя я бы использовал другой метод, поскольку присвоение нового объекта мгновенно обрезает связь.
Не надо тащить в JS терминологию из других языков (КЛАССических) и пытаться сделать JS похожим на эти языки. В JS всё является объектами и функции тоже. В прототипе вы можете хранить все что вам вздумается. Прототип — это объект и не более того. Не надо к нему относиться как к чему-то особенному и накладывать на него ограничения. Хранить в нем объект — отличный способ получить к этому объекту доступ из всех экземпляров.
а null — это тоже объект? Или просто значение, что данному значению не присвоена ссылка на объект?

с undefined тоже не очень понятно. Это просто значение, что нет значения?
Методов и свойств у обоих этих типов данных нет. Это и путает.
поскольку присвоение нового объекта мгновенно обрезает связь.

Если я правильно понял, то вы имеете в виду присвоение нового объекта экземпляру?!
В таком случае собственное свойство экземпляра скрывает свойство прототипа (если по-простому). Если это вам кажется странным и неуместным, то значит вы мало знакомы с наследованием на базе прототипов и пытаетесь превратить его в наследование на базе классов.
Спрошу здесь, а все знакомые программисты «я пишу js только на jquery». А мне эти вопросы не дают покоя, пока книгу читаю.

Замыкания переменных. Что это?
1. Это значения в виде ссылок на свойства объекта вмещающего функцию, которые присваиваются переменным вложенной функции, которые не определены в этой функции. Вроде такие переменные неразрешенными или как-то так называют. Этот объект существует в памяти пока на него есть хоть 1 ссылка. Иначе чистильщик его удаляет.

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

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

Области видимости лично для себя представляю как мыльные пузыри, которые впадают другие вложенные :-)
Про замыкания очень много статей на просторах рунета. Каждый человек пытается объяснить их по-своему. Чем больше подобных материалов вы прочитаете, тем выше вероятность, что вы найдете подходящий именно вам вариант и разберетесь в этом страшном звере по имени «замыкание». Кому-то хватает объяснения Флэнагана, кому-то нужны картинки и объяснение на пальцах.
У вас в обоих объяснениях есть слово «копируются». Это вредное слово, надо от него избавиться. Родительская область видимости не копируется в дочернюю, она доступна из нее по ссылке.

Пример, на котором это хорошо видно.
function foo() {
  var a;
  return {
    get: function() { return a;},
    set : function(v) { a = v; },
  };
}
var f = foo();
f.set(5);
console.log(f.get()); // 5

Если бы переменные копировались в замыкания, то f.get() вернуло бы undefined

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

PS Я считаю, самое понятное объяснение — в стандарте языка.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий