Pull to refresh

Comments 78

не похоже на «вполне практичный код»
<code>
(function f(){
      function f(){ return 1; }
      return f();
      function f(){ return 2; }
})();
</code>
(function(foo){
return typeof foo.bar;
})({ foo: { bar: 1 } });

Я обожаю этих людей, пишущих такой код в живых проектах, просто милые и пушистый.

10 из 14. Причем довольно неожиданные вопросы профакапил
За что именно? За вызов анонимой функции, передачи анонимного объекта или путаницу с именами?
Парсер — точно лох.

Первую ссылку «Пост» выдает как
habrahabr.ru/blogs/javas&# 99;ript/84311/
Никак не перейти.
Если на ваш пост кто-нибудь будет ссылаться, будет таже история.
Спасибо, поправил. С внешними ссылками понятно, но не думал, что парсер даже во внутренних «script» ненавидит.
UFO just landed and posted this here
You've got 4 answers wrong (#2, #3, #9, #13).
Very good, but not quite there yet.
Отличный результат — кристален с точки зрения статистики по данному тесту! =)

во 2 и 13 ошибаются чаще всего (я тоже)
3 ответ очевиден менее всего (единственный, который я не могу объяснить)
9 ответ — странность автора скрипта, могу спорить вы ответили «1function» (как и я)
Ответ на 9 зависит от того в каком браузере автор проверял его.
chrome, ie8: 1function
ff, opera: 1undefined
Это интересно с точки зрения баловства, но на практике такие вещи применять я бы не стал. А то прямо перл какой-то получается.
Это лишь иллюстрации к пониманию языка. К примеру, #6 и #7 на знание того, когда можно использовать this. #12 — на знание особенностей определения функций. Прямо в таком виде в жизни, может, и не увидишь, но те же особенности могут всплыть и в реальных ситуациях, когда код будет длиннее и незнание тонкостей может привести к часам дебага.
You've got 7 answers wrong (#1, #2, #3, #6, #7, #9, #14).
Very good, but not quite there yet.

Да… пора браться за учебники :-)
You've got all 14 answers wrong (#1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14).
Ouch.
))
You've got 6 answers wrong (#1, #3, #6, #9, #10, #14).
Very good, but not quite there yet.

Фленегана не читал и не собираюсь :)
Кстати, кто правильно ответит, какой результат будет у этого выражения?)

'the content here'.replace('content', '$$y $ $$ $$$');
Спасибо! Странно, что ваш коммент минусуют. Первые 2 справочных ресурса по запросу 'javascript reference' в гугле не упоминают об интерполяциях $$, $&, $`, $' и $n в строке замены. Всю жизнь считал, что в Javascript replace вставляет замены «как есть».
Лично я был сперва шокирован, так как полагал, что интерполяции имеют место быть, только если первый параметр — Regexp :)

В общем, пришлось использовать вот такое:
str.replace(what, function() { return replaceWith; });

:)
Ах да, чуть не забыл — в Internet Explorer 8 интерполяции не происходит :)
О как. Тогда понятно, почему в доках эти особенности replace не упомянуты. Мозилловский справочник по Javascript Jscript`у не указ. %)
Ну вообще-то это стандарт ECMAscript определяет такое поведение :)

В Google Chrome, например, реализация правильная.

Просто Microsoft этот момент пропустила (одна из многих недоработок).
мда 2 правильных ответа, *посыпал_голову_пеплом_и_пошёл_учить_JS*
Ну, кстати сказать, Флэнэган абсолютно здесь не при чём (особенно в тегах к посту) ;) Тест придумал kangax (русский парень, кстати), он же — один из core-dev-ов Prototype.js.
UFO just landed and posted this here
UFO just landed and posted this here
Спасибо за приглашение! А я вот только пытался понять кто же это мог инвайт прислать :)

Насчет непрактичности теста, я в какой то мере согласен. Делал в основном «for fun», но тем не менее, многие вопросы проверяют знание базовых, и довольно важных аспектов — function expressions vs. function declarations, hoisting, scoping, deletion, references, etc.

Если не понимать эти вещи, то в какой то момент скорее всего столкнёшся с проблемами.
Пожалуйста =) Вам спасибо за интересный тест. Неожиданно для себя узнал много нового и появилось желание узнать еще больше )
Привет, Юра, вэлкам ту русские IT-просторы ;)
Надо бы объединить все тесты вместе, вышла бы неплохая подборка. :)
Ну и добро пожаловать на Хабр
Главное, что мне в нем нравится — почти все задания представляют собой нормальный, вполне практичный код

А вы не могли бы перечислить номера вопросов, код в которых вы считаете «нормальным и вполне практичным»?
Т.е. таким, который действительно можно встретить в реальной жизни, и которые выполняет более-менее реальные задачи.
Я например могу назвать 2 и 7, и то лишь с некоторой натяжкой.
Хотите сказать, что в реальной жизни не нужно понимать разницу между undefined и null, между объявлениями и определениями, между глобальными и локальными объявлениями, между формальными параметрами и локальными переменными функции, между самой функцией и её вызовом,
между вызовом функции как метода и вызовом как подпрограммы?
Я что хотел сказать — то и сказал, смысл комментария вполне понятен.

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

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

Во всяком случае, в процессе отладки, часто натыкался на код из примеров. Естественно, он был разбавлен другим кодом, из-за чего не выглядел точно, как в примерах, но, по крайней мере, это не были извраты вроде ( i++ + ++i, i++ + ++i, i ), которые вряд ли когда-нибудь увидишь.
Вот как раз про #2 я бы так не сказал, там же ошибка ) А остальные решают вполне реальные задачи, что там такого фантастического? Точно такой код вы навряд ли встретите, а вот подобный или построенный по тому же принципу — вполне.
Вот как раз про #2 я бы так не сказал, там же ошибка

Да, но это как раз такая ошибка, которая может возникнуть в реальной жизни (по невнимательности например, или при копипасте).

var x = [typeof x, typeof y][1];
typeof typeof x;

(function(x){
delete x;
return x;
})(1);

А вот кому и для чего может понадобиться городить подобные конструкции — для меня загадка :)
8 ошибок. Но плевать и никаких книг читать не буду.
Читая свой код… я никогда не вижу никаких неоднозначностей — этого мне достаточно. Такие примеры дают основания полагать язык ущербным, но это не так.
Вы уверены, что другие люди не увидят в вашем коде неоднозначностей?
Чужой код Вы не читаете приципиально?
Чужой код читаю. Но, если он будет кишеть подобными конструкциями — я постараюсь как-нибудь отделаться от этого чтения. Ну а уж если он мне достанется «в наследство» — полюбому отрефакторю. Не получается у меня спокойно жить на проекте, когда там такое.
гм… подобные вещи в простых проектах не появляются, а рефакторить сложную систему не понимая как она работает Вас не пугает?

хотя некоторые «специалисты» и без подобных ухищрений умудряются такое наворотить в простом проекте, что диву даешься
Если мне достается в наследство что-то такое(было один раз :) правда не сказать что прям супер-сложное) — я поднимаю вопрос о рефакторинге.
Насчет понимания конструкций: захочешь — поймешь. Либо прочитаешь где, либо поиграешься — понять можно. Но заставлять другого человека думать над этими конструкциями… свинство. Такое можно простить когда сильно нужна оптимизация и это был один из методов.
(блин, как отключить в настройках этот гребанный Ctrt-Enter?)

1. What will 1..z provide:

a) SyntaxError
b) New Range object (equivalent to new Range(1, 'z')) including all numbers and letters
c) undefined
d) Error of Range object (incompatible types for range: number and string)
e) ReferenceError 'z' is not defined

2. What the result of 100['toString']['length']:

a) 100
b) 3
c) 1
d) 8
d) SyntaxError

3. What the result of:

function foo() {
  return this;
}
 
alert(foo === foo.prototype.constructor); // true
alert(foo() === foo.prototype.constructor()); // ?

a) true
b) false
c) depends on implementation
1. Напрашивается a) Syntax Error но, мне пришло в голову, правильный ответ 1..z = (1.).z = undefined (убивать надо за такие особенности языка)
2. c) 1 — число аргументов метода toString()
3. Я путаюсь, что такое prototype и тем более constructor, но ответ — очевидно true.

Или ответы не надо было в комменты писать?
Очень хороший ход мысли. Чтобы сразу не раскрывать ответы (может, кто-нибудь ещё захочет попытать «удачу»), скажу: на некоторые вопросы Вы дали совершенно правильные ответы, на некоторые — совершенно неправильные.
Уверен лишь в третьем — b (false).
foo() вернёт window, foo.prototype.constructor() вернёт foo.prototype, который не равен window.
> foo() вернёт window, foo.prototype.constructor() вернёт foo.prototype, который не равен window.

А почему именно так?
Я для себя запомнил так: this внутри функции имеет то значение, чему равно выражение перед точкой при вызове функции. Если точки нет или используется какое-то хитрое выражение типа (x=«q».toString)(), то он равен глобальному объекту, window. И это если не учитывать всяких new f() и f.call()/apply().
> Если точки нет или используется какое-то хитрое выражение типа (x=«q».toString)(), то он равен глобальному объекту

Ага ;) Самое сбиваеющее с толку, если не знать, как точно это работает, может быть:

foo.prototype.constructor(); // foo.prototype
(foo.prototype.constructor)(); // тоже foo.prototype

// но
(foo.prototype.constructor = foo.prototype.constructor)(); // global


Так же, не всегда при вызове, как функции (т.е. «нет» слева от точки «ничего»), this будет global (например, при использовании with):

with ({foo: function () {alert(this);}}) {
  foo(); // объект with, добавленный к scope chain, но не global
}
В принципе, можно рассуждать так: если вызов можно эквивалентно представить в виде выражения

( 1 ) [ 2 ] (аргументы);

где 1 — выражение, результат вычисления которого равен какому-то объекту, а 2 — выражение, результат вычисления которого равен какой-то строчке (имя свойства) или числу (индекс), то this будет равен выражению 1.
Если так представить нельзя, то this будет равен window.
Причём код

with ({foo: function () {alert(this);}}) {
  foo();
}

(теоретически) можно представить как

( {foo: function () {alert(this);}} ) ["foo"] ();

что соответствует первому случаю :)

Аналогично:

foo.prototype.constructor(); // эквивалентно ( foo.prototype ) ["constructor"] ();
(foo.prototype.constructor)(); // эквивалентно ( foo.prototype ) ["constructor"] ();
(foo.prototype.constructor = foo.prototype.constructor)(); // нельзя представить в таком виде
Почти (но ход мысли хороший).

На самом деле правило одно:

Определяется, что стоит слева от выражения вызова (грубо, от скобок — ( )). Главное, что интересует — это тип вычисленного промежуточного значения, который может быть либо Reference type, либо не Reference type.

Первый случай (Reference type) возможен, когда слева стоит либо идентификатор (identifier), либо выражение доступа к свойству (property accessor). Второй случай (не Reference type) — всё остальное.

Далее, у этого значения Reference type берется базовый объект (base), и именно он будет использован в качестве значения this (Если нужно пояснить про Reference type, скажите).

В случае же, когда значение — не Reference type, this получает значение null. Но, т.к. null особого смысла для this не несёт, автоматом подставляется глобальный объект.

Поэтому:

var foo = {bar: function () {}};

foo.bar(); // Reference type (accessor), база - foo
(foo.bar)(); // тоже, Reference type, база - foo, используется оператор группировки

function test() {}

test(); // тоже Reference type (identifier), база - global
this.test(); // равносильно предыдущему, база видна явно

А вот здесь, оператор присваивания (в отличие от оператора группировки в примере выше), вызовет GetValue, и в итоге будет уже не Reference type, а Function:

(foo.bar = foo.bar)(); // не Reference type, this = null => global

Аналогично другие выражения (всё тоже — не Reference type, поэтому this в итоге будет global):

(foo.bar || foo.bar)();
(foo.bra, foo.bra)();
(function () {})();

По поводу with: будет Reference type с базой — объект with добавленный к scope chain; поэтому не global.

Есть одно исключение, когда будет получен Reference type (и даже база будет не global, как выше в случае с test), но всё же this будет global. Это в том случае, когда базой будет является объект активации (activation object). Если упрощенно, это объект контекста функции, в котором хранятся вложенные функции, переменные и параметры:

function foo() {
  function bar() { alert(this); }
  bar(); // global
}

При вызове bar будет определено значение Reference type (т.к. это идентификатор), но с базой — объект активации контекста функции foo. Т.е. эта запись образно равносильна:

AO.bar();

где АO — объект активации контекста foo.

Так вот для этого случае в стандарте тоже прописано — использовать в качестве this не объект активации (базу), а null, и, как следствие, global.
You've got 4 answers wrong (#3, #8, #9, #14).
Very good, but not quite there yet.

… обожаю Javascript )
All 14 answers wrong… Как меня на работу-то взяли ;-) Видимо, надо почитать-таки Флэнагана.
Самое странное, что это не мешает мне писать в т. ч. довольно сложные гуишки. Хотя, наверное, мешает, т. к. сказывается на качестве кода и упомянутых уже «часах дебаггинга»…
Что стесняться-то? «You've got 4 answers wrong (#3, #12, #13, #14).» Я удивлен, думал вообще все неправильно будет )
Кому интересно, здесь ещё дополнительные вопросы есть: groups.google.ru/group/comp.lang.javascript/browse_thread/thread/2e6e542c9e02965c?hl=en

Некоторые с небольшими дополнениями:

1. Каков результат?

var a = 1, b = 3;
a
++
b;

a) a = 2, b = 3
b) a = 1, b = 4
c) Syntax error

2. Каков результат?

var x;
foreach (x in {})
{
  // ...
}

1) ReferenceError
2) SyntaxError
3) Iterate over all values of object properties.
4) Possibly no error

var x;
foreach (x in {}) {
  // ...
}

1) TypeError
2) SyntaxError
3) Iterate over all values of object properties.
4) Possibly no error
Правильный ответ:

javascript:(function(O,K){for(;O
javascript:(function(O,K){for(;O<K.length;)document.getElementById(«answer-»+ ++O+"-"+K[O-1]).checked=!0;})(0,[1,4,1,4,1,1,1,2,3,2,1,2,1,2])

© WebReflection

hbr порезал предыдущий коммент:(
You've got 7 answers wrong (#6, #8, #9, #10, #11, #13, #14).
Very good, but not quite there yet.
У него включена премодерация комментов, он публикует только слащавые комменты, которые ему нравятся, в которых говорится, «какой этот чел крутой, ой, какой хороший тест придумал». А то, «что по уровню сложности этот quiz на слабую троечку, в отличии от теста kangax-а, который, объективно, сложнее — на 4» — это надо игнорить и не показывать в комментах". Дешёвый PR на «хороших» комментах — признак дилетантизма (не важно, сколько у него на счет книг и т.д.).

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

Примерно (с переводом): «Объективно, этот quiz легче, чем те, которые упоминаются (в целом, эти quiz-ы не требуют каких-то глубоких анализов); уровень сложности — 3, у kangax-a был на 4, но в любом случае — спасибо.»
Да, и мне, собственно, по барабану, прошел мой коммент модерацию или нет, я правил не нарушал, не троллил, не был rude (как у него написано в Note: к комментам), говорил по делу. Но понял, что для этого человека в первую очередь важен PR, а не реальное положение дел, «наука» (ECMAscript) и объективные оценки.
Ваш комментарии вполне адекватный. Может еще и не проходил модерацию…
Как-то я тоже «ждал» появления нейтрального комментария достаточно долго.
Мой коммент был 5-ый, перед комментом kangax-a, который уже опубликован ;) Ладно, проехали, мне от этого ни тепло, ни холодно. Это PR и не больше. Вернее, боязнь анти-PR-а.
Вижу Ваши комментарии в блоге и последний пост Николаса. Не все так плохо, как казалось ;)
Zakas-у, вероятно, просто сообщили об этом. В любом случае, повторю, мне эта позиция («этот красивый комментарий публикую сейчас, а этот нет, а этого — вообще не публикую») не близка. Удалять спам и троллинг — это, конечно, совершенно, другое, хотя, я с этим не сталкивался в своих статьях. А Ваш ответ звучит так, как будто, Zakas «сделал одолжение и соизволил», что ещё больше является забавным пафосом, который меня всегда «умиляет» в людях.

Насчёт последнего комментария, этот человек (Asen Bozhilov) тоже говорил, что Zakas модерирует полезные, но не/мало/лицеприятные комментарии: groups.google.ru/group/comp.lang.javascript/browse_thread/thread/2b9dcc0b88ff8ffa?hl=en#9255f32d6271e3bd
В 6-м я, вроде, понял в чем ошибка. А где в #3?
100.toString.length — синтаксическая ошибка, должно быть 100..toString.length: первая точка определяется, как отделение дробной части, вторая — уже доступ к свойству.
Зря ты так. Я его ловил, указывал на ошибки, премодерация меня не удавила.
В принципе, здесь поля для беседы не было, я просто отметил, что тест — слабее, тех которые он упоминает в описании теста, в любом случае, поблагодарил за работу. Возможно, он счел это не нужным, ни о чем. Мне без разницы. Я ни один (ни один.) коммент никогда не скрывал. Объективная оценка — это главное. Я не опускал тест (а он подумал, скорей всего, именно это), ни говорил, что он плохой, что он тупой, что он не нужный, еще что-то. Я просто отметил, что он по уровню проверки знаний — слабее, чем те, которые он сам же и упоминает.

Мне подход важен. Меня «умиляют» персоны, которые свысока там что-то о себе возомнили, и выбирают — этого публикую, этого нет. При этом, говоря о «свысока», меня меньше всего волнует статус, наличие книг, написанных библиотек и т.д., как аргумент к этому «свысока», типа, «имею право, потому что я такой-то».

> Я его ловил, указывал на ошибки, премодерация меня не удавила

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

Ладно, хрен ты с ним.
Мало того, что тест слабее. Мне сразу хочется застрелить автора (или застрелиться самому в случае невозможности первого), когда я вижу конструкции типа «a+++b» (это еще в лучшем случае, обычно — "--(a++(b--+++c)++)", что-то в этом роде). Этим автор как бы хочет сказать «я знаю о существовании левосторонних и правосторонних грамматик, а ты?». А я не собираюсь использовать такие конструкции.
You've got 6 answers wrong (#2, #3, #6, #9, #12, #13).
Very good, but not quite there yet.

Хотя по идее я сделал 5 ошибок так как в 9 вопросе браузеры выдают «1function» и почему создатель теста посчитал его неверным я не знаю. Практически все ошибки совершил по невнимательности, кроме пожалуй 3 вопроса.

Пошел перечитывать Флэнагана дальше ))). Уже на 215 странице пятого издания…
Sign up to leave a comment.

Articles