Pull to refresh

Comments 112

typeof age !== "undefined" плохой вариант. Лучше использовать сравнение непосредственно с undefined
age !== undefined

Но надо учитывать, что, теоретически, кто-то где-то в коде может определить глобальную переменную undefined и всё сломается.
На такой случай (ну и вообще) удобно использовать «хак» с инкапсуляцией:
(function(window, $, undefined){
// ваш код
// window и jQuery – просто для примера
// главное, чтоб на вход всегда ничего не передавалось для переменной undefined
}(window, jQuery))
Мне кажется стоит тогда уж с void 0 сравнивать.

age !== void 0
UFO landed and left these words here
Удивительно что заминусовали толковый комментарий. Действительно, проверка на неравенство null гарантирует, что программа не выпадет с исключением при попытке получить какое-нибудь свойство переменной. Это очень удобное сравнение.
UFO landed and left these words here
В статье кстати сказано про undefined и создание одноименной переменной — как вариант, предлагается использовать void 0.
typeof age !== «undefined» плохой вариант. Лучше использовать сравнение непосредственно с undefined
age !== undefined


А не наоборот?

(function() {
    var undefined = 1;
    console.log(undefined); // 1
    console.log(typeof undefined); // number
    console.log(typeof a); // undefined
})();
И словить ошибку, если переменная age не определена ни в одной из областей видимости. Отлично решение! Вам надо писать больше статей для новичков!
Способов выстрелить себе в ногу в JS огромное количество. Для защиты от необъявленных переменных я бы посоветовал, в статье для новичков, использовать линтер.
Почему минусуют человека? Все правильно сказано же — дереференс необъявленной переменной, в коде типа age !== undefined, выбьет ReferenceError: age is not defined же. typeof age !== "undefined" лишен этого недостатка.

При проверке же свойств имеет смысл проверять напрямую — foo.bar != null, потому что свойства ReferenceError не выбрасывают.
Я бы сказал, что это не недостаток, а преимущество. Т.к. если переменная не определена, то ваш кусок кода ничего не делает и его нужно убрать.
А вы можете себе представить человека в здравом уме, который переопределил undefined, и требует чтобы код продолжал работать?

Кстати, в глобале ещё полно глобальных переменных, почему от их переопределения никто не огораживается? Развлечения ради можете вбить в REPL node.js «Math = 0» и посмотреть, как его раскосячит.

Совсем другое дело — оптимизация на скорость. Вроде как, используя void 0, можно избежать долгого разрешения переменной undefined из глобала через всю цепочку скопов. Но в последнем хроме void 0 работает даже чуть медленнее.
>> можно избежать долгого разрешения переменной undefined из глобала через всю цепочку скопов

а это точно происходит? Разве движки это не оптимизируют?
Дык, ссылочка на jsperf в конце коммента как раз и говорит о том, что использование void 0 вместо undefined в качестве микро-оптимизации зачастую абсолютно бесполезно.
Паттерн (function() {...})() стоило сразу же назвать IIFE. Про "||" написано, а про "&&" почему то нет.
Вы про такую конструкцию?:
(function(){
  var sad = true;
  function makeMeHappy() {
    console.log('I\'m happy now!');
    return false;
  }
  sad = sad && makeMeHappy();
})();
Я думаю имелось в виду проверка на != null. Что то типа a && a.b && a.b.c && a.b.c().
Есть ещё один удобный (ИМХО) хак, который я всегда использую вместо оператора switch:
var options = {
  case1: function () { ... },
  case2: function () { ... },
  ...,
  'default': function () { ... }
};
options[value||'default']();

Вместо функций можно непосредственные значения указывать, зависит от ситуации.
Это не хак, а простая реализация паттерна «стратегия».
Это паттерн-матчинг, разумная замена конструкции switch. Например в питоне этой конструкции вообще нет, вместо нее делают паттерн-матчинг. А в эрланге — так вообще нормальная практика, никаких ветвлений не нужно.
Совсем недавно оно в JS ещё и работало намного быстрее, чем switch. В новых версиях браузеров уже оптимизировали.
Без разрушающего присваивания (или разрушающего связывания) от паттерн-матчинга остается одно название.
Тогда уж лучше (options[value] || options['default'])() использовать.

А не то options[value||'default']() дурно ведёт себя, когда value пусть не == false, но и имени ни одного из свойств options не соответствует.
От value === «toString» все равно не застрахуешься…
Это убивает всю прелесть использования литерала объекта. Проще уж hasOwnProperty использовать, пусть это и далеко не так красиво выглядит.
Согласен. И это минус языка. На IE11+ можно уже использовать {__proto__: null, ...}, но всё равно не то.
А как же хак «вертикальная черта — ноль»? Который позволяет получить целую часть от числа (или конвертировать строку в число и вытащить целую часть):

"8.97"|0; // 8
8.97|0; // 8
"8.01"|0; // 8
"a801"|0; // 0
"801a"|0; //0
Способ веселый, но на очень больших числах начинает врать.
Обычное переполнение интеджера, уходит в отрицательное.
мой любимый хак:
if (~arr.indexOf('val')) {
    // Элемент в массиве есть
}
Ещё говорят, что это тоже хак:
var arr = [1,2,3,4];
arr.length = 0; // очищает массив
сомнительный хак.
var arr = [1,2,3,4];
arr.length = 0; // 15 символов
arr = []; // 9 символов

// Толи дело:
var arr = [4, 9, "e", 123, 321];
arr.length = 2;
arr; // [4, 9]
Надо заметить, что arr.length изменяет существующий массив, в то время как присваивание пустого массива создает новый массив. Иногда это может быть важно.
var arr = [1, 2, 3, 4];
arr.testProperty = true;
arr.length = 0;
arr.testProperty; // -> true
arr === arr; // true

var old = arr;

arr = [];
arr.testProperty; // -> undefined

old === arr; // false
Использование большинства подобных хаков приводит к небольшому уменьшению количества символов и сильному ухудшению читаемости и понятности кода. Если у тебя, %программист%, есть уверенность, что твой код будут читать и править люди, чья квалификация не уступает твоей, то ты можешь использовать эти хаки. Если такой уверенности нет, напиши гораздо более понятное
if (!age) {
  age = 10;
}
В tutorial’ах по значительной части динамических языков этот трюк описан и иногда даже рекомендован: из тех языков, что я знаю так делают Perl, Python, Ruby, Shell¹, Lua. В последнем так вообще вместо тернарного оператора (которого нет) часто используется a and b or c (в отличие от того же Python b здесь не должно быть всего лишь nil и false, что сильно расширяет область применимости).

Так что понимание такого кода достаточно вероятно.

¹ Речь идёт о только кодах возврата (т.е. о “присвоении” $?), что практически бесполезно. Конструкция $(( a || b )) может вернуть только 1 или 0.
Разумеется, квалифицированному программисту не составит разобраться во всех этих конструкциях. Более того, он в силу своего опыта знает во всех тонкостях как они работают и т.д. Безусловно, не составит труда и новичку сесть разобраться что именно хотел сказать автор кода. Я говорю о другом. О том, что понятность кода для программистов более низкой квалификации приводится в жертву его (кода) компактности, а это, на мой взгляд, неправильно. Грубо говоря, я могу нахреначить в своём коде столько хаков, что любой, прочитавший 5 его строк, проклянёт меня. А могу написать тот же самый по функциональности код таким образом, что любой юниор без труда сможет продолжать его развивать.
Зато для всех кроме новичков ваш код будет менее читабелен. Банально потому что длиннее.
Вы всегда именуете переменные одним или двумя символами? Почему нет, ведь иначе код становится длиннее?

Программирование — это искусство, в том числе искусство находить баланс. В количестве хаков, длине имен переменных, количестве комментариев, уровне абстракции и т.д.

Ещё раз: если вы уверены, что ваши хаки поймут все, кто будет читать и поддерживать код — на здоровье, лепите сколько хотите. Если такой уверенности нет, то лучше упростить код. Это же элементарно — подумать о тех, кто пойдёт за тобой.
UFO landed and left these words here
Речь как раз о том, чтобы не стать Эллочкой Людоедочкой, которой хватает 10 строк, чтобы выразить любой алгоритм.

Если честно, я в некотором недоумении. Я не призываю раздувать код, я не призываю отказаться от паттернов, от красивых и элегантных решений. Я призываю писать код так, чтобы он был понятен тому, кто его читает, даже если читающий обладает более низкой квалификацией. И говорю о том, что использование хаков, как правило, затрудняет, а не облегчает чтение кода. При этом я уже на протяжении 5 комментариев спорю с чем угодно, но только не с этим изначальным высказыванием.
UFO landed and left these words here
this.age = age || his_age || stored_age && parsed_age || 10.

У меня полное ощущение, что вы хорошо понимаете, что я пытаюсь донести. Разве нет?

UFO landed and left these words here
Наверное, я взял слишком простой и очевидный хак, чтобы продемонстрировать свою мысль. Признаю свою ошибку.
Никогда не считал себя квалифицированным кодером на js, но только из этой статьи узнал что что вот это this.age = age || 10 хак. Достаточно очевидная конструкция. Много где видел и сам писал. И читается проще чем if. ИМХО, конечно.
Да как же проще-то? Сравните:
1. Если не возраст, то сделать возраст равным десяти.
2. Сделать возраст равным возрасту или 10.

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

А если вы достаточно длительное время писали на Perl’е (почему‐то там я использовал эту конструкцию чаще всего), то age = age || 10 будет восприниматься именно так: «если возраст не определён, то он равен 10». Вам нужно обновить свою версию «встроенного в мозг интерпретатора»: он вполне способен по ходу дела повышать уровень абстрагирования. Не думаю, что тут имеет смысл сравнивать энергетические затраты на повышение уровня с затратами на чтение вчетверо большего числа строчек.

Ктати, если переменных со значением по‐умолчанию больше одной, то || всегда лучше:

this.age = age || 10;
this.sex = sex || "Male";

if (!age) {
    age = 10;
}
if (!sex) {
    sex = 10;
}
this.age = age;
this.sex = sex;
UFO landed and left these words here
UFO landed and left these words here
UFO landed and left these words here
Гм. Откуда в this возьмётся age?

Кроме того, у вас здесь три строчки «мусора»: кода, который не нужен для восприятия алгоритма (если такие конструкции раскиданы по всему коду, то к ним быстро привыкаешь), а также кода, который это восприятие затрудняет (если вы такую конструкцию видите в первый раз, то понять, что она делает, гораздо сложнее, чем в варианте с this.age = age || 10;).

Даже более того, вы используете ||. Супер! Будучи применённой к значениям внутри по‐первости (если о новичках: людях, плохо знакомых с вашим кодом) непонятного объекта defs (definitions? defaults? ещё что‐то?) она, разумеется, становится понятнее, чем в this.age = age || 10;.

Переменная defs понадобится только, если переменных уж слишком много: в этом случае для установки значений будет использоваться функция вида mergeObjects(this, args, defaults), а все переменные будут в объекте args.
Если этот хак общепринятый и программисту он не понятнет, то программист полезет в гугл или форум и станет немножечко продвинутей
Приведение переменной к числу при помощи +"123" лучше, чем используя parseFloat/parseInt тем, что parse* для строки "123foobar" вернут 123, тогда как +"123foobar" вернет NaN.
Еще в копилку хаков — a >>> 0 работает, как приведение числа к uint32_t:
12345 >>> 0 // 12345
-12345 >>> 0 // 4294954951
12345678901 >>> 0 // 3755744309
Работает лучше, чем a & 0xFFFFFFFF, из-за явной беззнаковости.
Чит для получения всех ключей объекта в массив:

var arr = [], i = 0, obj = {a:1,b:2,c:3};
for( arr[i++] in obj );
// arr = ['a','b','c']

Я бы использовал Object.keys если es5 доступно. А вообще если, нечто расширит Object.prototype в ie8 вы словите нечто веселое. Вам бы проверку для hasOwnProperty добаить и тогда это будет почти shim для Object.keys.
Зависит от того поведения, которое нужно. Временами надо получить и ключи прототипов. hasOwnProperty сюда не вкорячить, тут вся магия в arr[i++] in.
Оно и понятно, что в зависимости от того что нужно. Хотя признаться у меня не было случая когда нужны вообще все методы, даже прототипов, а вот ie8 появляется регулярно.
честно говоря от фразы
если вы поместите объект в условный оператор if, то он выполнит либо true-ветку кода (когда объект имеет значение true), либо выполнит false-ветку (соответственно, когда объект имеет значение false).

у меня мозг взрывается.
Напишите «переменная», «выражение», ведь неокрепшие разумом дети будут читать.
Однако стоит заметить, что с таким способом вам не удастся задать переменной значение 0, так как 0 является ложным выражением.

image
Разумеется, если значение по умолчанию 0 — то никаких проблем не возникает. Проблемы начинаются, когда значение по умолчанию — 10, а нам надо 0 передать.
В JavaScript || является примером выполнения короткого замыкания.

крайне неудачный перевод англ. термина Short-Circuit Evaluation, у нас обычно это называют «короткой схемой вычисления» или «упрощенный порядок вычисления выражений»

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

Поправьте плз, если я не прав.
function x(x){alert(x||0)};x(); //0
Прибавлю, что «void 0» ещё и набирать быстрее и проще, чем «undefined».
Ну это смотря где набирать. В моем редакторе автодополнение выкинет undefined уже после «un».
UFO landed and left these words here
Конвертация строки в число с помощью оператора +
И не только строки:

+new Date
В общем случае унарный плюс форсит вызов valueOf.

Скорее всего, вы бы применили методы parseFloat и parseInt.
В очередной раз незаслуженно не упоминается функция и конструктор Number. Функции parseInt и parseFloat делают несколько больше, чем конвертация в число. Наиболее близкий аналог это «выковыривание» числа из числоподобной строки. Для конвертации лучше прямолинено использовать конструктор Number.
Вот хороший пример:

['1','2','3'].map(parseInt);
['1','2','3'].map(Number);
С другой стороны, вместо if (x == «test») можно просто написать if (x). Если же x будет пустой переменной, то просто выполнится код из блока else.

Если x число и равно 0, то тоже выполнится else. Из-за этого многие пишут код, который потом работает, не так, как ожидается.
Понимаю, что перевод, но все эти вещи описываются в любом туториале (javascript.ru, mozilla) и книгах типа «Effective JS» и «JavaScript: the good parts». Причём объясняется лучше почему, как, зачем, когда надо, когда не надо.
И этот язык становится доминирующим в веб-программирвоании! За что, господи, за что?
Есть закономерность: Каждый, кто знакомится с внутренностями JS — начинает высказывать предсказуемыми фразами.
А никто и не говорит иного — хуже языка, нежели JS лично я пока не видел. Даже всеми осуждаемый PHP по сравнению с сабжем — является идеально структурированным и продуманным до мелочей.
Вы видимо мало языков знаете. Есть и хуже.
Этот пост о javascript. Я не хочу плодить оффтоп. Если вы хотите подискутировать на эту тему, то напишите отдельный пост о том, почему на ваш взгляд javascript ужасен и спросите мнения у сообщества. И уже в рамках этого поста мы с удовольствием все обсудим.
Из распространенных языков Javascript имеет наибольшее количество проблем:

— проблемы собственно языка и его синтаксиса: wtfjs.com/. Это просто убер-аргумент, тут не пройдет возражение, что в других языках не лучше. Лучше и гораздо.

— низкий порог вхождения и как следствие высокое число неквалифированных разработчиков, создающих библиотеки низкого качества

— несмотря на наличие стандарта ECMA script полнота его поддержки разными броузерами отличается, также имеются вещи работающие только в конкретном броуезере

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

— чтобы стать гуру языка узкого назначения, не имеющего фич отсутсвующих в других широкого назанчения, приходится тратить очень много времени. При этом зарплата гуру Javascript и Java будет выше у последнего.

— отладка сложных приложений — это ад, сложных приложений с большим количеством данных — двойной ад.

— коммьюнити на 90% состоящее из фан-боев, которые в упор отказываются видеть и признавать недостатки
Помню вашу статью про «фрактал отсоса». Вижу, что мнение ваше не изменилось. Повторно разводить тут полемику я не вижу смысла. У JS тьма недостатков, но для тех задач, которые он решает, у нас нет альтернативы. Потому и появились coffeescript и typescript, которые тоже далеки от идеала.
Вывод из морали: Objective-C появился для того, чтобы хорошенько развеселить очень грустных разработчиков.
Достаточно было сказать что в js слабая динамическая типизация и программа старается не падать почти никогда(пытаясь обработать необрабатываемое), все ваши аргументы против js проистекают отсюда.
Удивительно как вы эту одну особенность языка свели к множеству недостатков.
Javascript и правда ужасен, но и ваши аргументы тоже.
Понимаете, если просто написать так как вы, то человек читающий вас может подумать, что проблема в общем-то плевая, хотя за «в js слабая динамическая типизация и программа старается не падать почти никогда(пытаясь обработать необрабатываемое)» скрывается страшное.
Я хорошо знаю js, и мне он нравится — это я подтверждаю закономерность, или нарушаю?
А чем именно вам нравится этот язык в сравнении с другими?
Провоцируете? Хорошо.

По сравнению с PHP
В js всё-таки меньше бардака, и объектно-ориентированность прикручена получше. В JS можно понять несколько принципов, и дальше можно в уме прокручивать код не хуже интерпретатора:

— Значения приводятся к нужному типу, если это возможно. У объектов приведения к примитивам для это дёргаются методы valueOf и toString.
— Если хотя бы один операнд — строка, то весь оператор строка работает как конкатенация.
var объявляет переменную в скопе на уровне функции. Если перемнная явно не объявлена, она она через механизм делегирования берётся из верхних скопов.
— Если у объекта нет свойства, она через механизм делегирования берётся из прототипа.
this определяется при вызове, а не при создании.

В PHP же без php.net, открытого в соседней вкладке делать нечего.

По сравнению с Python
Да, считай, два брата-близнеца. Только питон не так активно приводит типы, как js. Половину wtfjs можно портировать на питон без особых изменений (напомню, что BOM/DOM не является частью языка), даже поведение супер-страшного прототипного наследования:

function Foo(){};
Foo.prototype.bar = 42;

var foo = new Foo();
console.log(foo.bar); // 42

Foo.prototype.bar = 32;
console.log(foo.bar); // 32


class Foo:
	bar = 42

foo = Foo()
print foo.bar # 42

Foo.bar = 32
print foo.bar # 32


Сравнивать с VBScript, надеюсь, не заставите? А с Руби у меня, к сожалению, не сложилось.
Значения приводятся к нужному типу, если это возможно. У объектов приведения к примитивам для это дёргаются методы valueOf и toString.

В php тоже приводятся к нужному типу, причём приведение типов более приятное, нежели в JS, у объектов также дёргается метод __toString.

Если хотя бы один операнд — строка, то весь оператор строка работает как конкатенация.

В php специально сделали оператор ".", для конкатенации, а "+" для сложения. При использовании конкатенации — всё будет стараться приводиться к строке, при сложении — к числам — это значительно удобнее и гибче, нежели в JS.

var объявляет переменную в скопе на уровне функции. Если перемнная явно не объявлена, она она через механизм делегирования берётся из верхних скопов.

$some — объявляет переменную в скоупе на уровне функции. Если требуется передать переменную в безымянную функцию — её требуется явно указать в операторе use — это облегчает понимание кода, так же в абсолютно любом месте кода ссылки на класс и на инстанс класса, включая родителей и наследников ($this, self, parent, static) никогда не поменяются — это намного удобнее и практичнее, нежели страдать с постоянно изменяющимися контекстами this и через раз использовать call\apply.

Если у объекта нет свойства, она через механизм делегирования берётся из прототипа.

Очень сомнительное преимущество. С таким же успехом в php можно создать абстрактный класс и назвать его Prototype и после наследования от оного — будет тоже самое, если у объекта нет свойства — оно возьмётся из абстрактного класса =)

this определяется при вызове, а не при создании.

А вот это как раз наоборот боль — изменяющийся контекст добавляет больше проблем, нежели их решений. Мне проще в нужных местах передать этот контекст в виде аргумента, нежели следить за тем, чтобы он нигде не поменялся от неосторожного телодвижения.
Если взять Ваш код на питоне, добавить в конец класса end и заменить print на puts (или p) — получится ruby. Так что отличий в примере почти нет.
В js всё-таки меньше бардака, и объектно-ориентированность прикручена получше.


Отсутствие унифицированного подхода к ООП плохо ходя бы потому, что затрудняет создание индексатора для языка, что в свою очередь мешает хорошей его поддержке в IDE. И если я правильно я понимаю, то построить иерархию классов в JS можно только выполнив код, поскольку явные декларативные конструкции языка, позволяющие определить кто чей потомок отсутствуют.Может вы помните PHP по четвертой версии, но там сейчас существует очень хорошая поддержка ООП. И не только я не согласен с тем, что ООП в JS не идеально, например в MooTools есть своя надстройка над ООП.

В JS можно понять несколько принципов, и дальше можно в уме прокручивать код не хуже интерпретатора:


Я с вами не согласен:

    var d = new Date("2012--12-01"); // объект будет создан без предупреждений

    d.toJSON();       // null
    d.getTime();      // NaN
    d.toString();     //'Invalid Date'
    d.toISOString()   // наконец-то бросит ошибку!


    []     == true // false - пустой массив, вроде бы интуитивно понятно
    [1]    == true // true  - единица, все логично - и массив непустой, и единица приводится к true
    [2]    == true // false - массив непустой, значит дело в единице, которая приводится к true... 
    [true] == true // false - либо мы имеем хитрое правило приведения, либо true != true
     
    // может все дело в магической единице ?
    [1 , 1]  == true // false нет...
     
    // а если вложенный массив?
    [ [1], [1] ]    == true // false
    [ [ [ [1] ] ] ] == true // true
     
    // но !
    new Array()    == true // false 
    new Array(1)   == true // false 
    new Array(1,2) == true // false 


Если вы считаете такое поведение допустимым, то вы лукавите, обвиняя PHP в бардаке.

— Значения приводятся к нужному типу, если это возможно. У объектов приведения к примитивам для это дёргаются методы valueOf и toString.


Это происходит как минимум в php и perl, но отличаются правила приведения.

— Если хотя бы один операнд — строка, то весь оператор строка работает как конкатенация.


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

Позвольте вам привести типичный код на JS, который я часто вижу в проектах:

  $("#id3").val(
      sum(
       $("#id1").val(),
       $("#id2").val()
      )
  );


А потом эту же функцию образную sum несколькими десятками строк ниже используют как:

  $("#id3").val(
      sum(
       5,
       10
      )
  );


Т.е. результат для например sum(5,10) и sum(«5», «10») будет разным. И очень мало людей настолько параноидальны, что будут думать, что в кишках каждой функции, в которую они кидают данные.

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

— var объявляет переменную в скопе на уровне функции. Если перемнная явно не объявлена, она она через механизм делегирования берётся из верхних скопов.


Или я вас не понял, или это есть во многих языках.

— Если у объекта нет свойства, она через механизм делегирования берётся из прототипа.


Позвольте, но это же есть в любом языке с традиционным ООП. Или я вас опять неправильно понял?

— this определяется при вызове, а не при создании.


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

В PHP же без php.net, открытого в соседней вкладке делать нечего.


Во-первых обычно область применения PHP несколько пошире, чем у JS. Или вы наизусть помните как читать файлы через ноду? API к монге тоже помните? Во-вторых php.net — это источник в котормо собрано все. Весь язык, все функции, охватывающие основную область применения, примеры и caveats к этим функциям. Для Js я такого не встречал, хотя тут играет роль минимализм.

По сравнению с Python
Да, считай, два брата-близнеца. Только питон не так активно приводит типы, как js.

Половину wtfjs можно портировать на питон без особых изменений (напомню, что BOM/DOM не является частью языка), даже поведение супер-страшного прототипного наследования:

function Foo(){};
Foo.prototype.bar = 42;

var foo = new Foo();
console.log(foo.bar); // 42

Foo.prototype.bar = 32;
console.log(foo.bar); // 32


class Foo:
    bar = 42

foo = Foo()
print foo.bar # 42

Foo.bar = 32
print foo.bar # 32




Не просто «не так активно приводит типы», а больно бьет по рукам за неявность. И, несмотря на возможность трюкачества с питонячьим ООП, там оно есть в явном виде. А поменять кусок класса в рантайме можно почти в любом динамическом языке, но обычно этим почему-то никто не пользуется. Скорее всего потому, что единственная вещь где это часто нужно — реализация наследования, которое таки реализовано явно в других языках.
В других языках это либо запрещено, либо есть специальный оператор конкатенации.
Извините, мне стало смешно. Наверное, C#, Java и Python слишком мало распространены…
Странно, но в питоне

"3" + 3


выдает ошибку.

Java и C# гораздо более строготипизированные языки, чем Javascript, так что там контроль типов аргументов происходит уже по сигнатуре функции. По этой же причине(типизация) вы всегда знаете что с чем вы складываете/конкатенируете, в отличие от javascript.

Можете пояснить из-за чего вам стало смешно?
Может вы перепутали с Ruby? Насколько я знаю — это единственный язык (помимо JS), где символ "+" используется как в качестве сложения, так и в качестве конкатенации и при этом он не выдёт ошибку при использовании этого оператора с разными типами.
Хм… Я и не говорил, что описанные мной принципы — это нечто уникальное для джаваскрипта. Это — минимум, знание которого позволит не удивляться wtfjs.

Когда при приведении к json метод возвращает null — это не удивительно, в json нет NaN. Когда таймстемп невалидной даты — невалидное число, для меня тоже нет в этом ничего удивительного. А примеры с == true надуманны. Вы видели, чтобы кто-то так писал на практике, сравнивая я true явно, причем двойным равно? Но так или иначе — тут оба операнда приводятся к числу, и никакой магии нет. И это, кстати, ничем не лучше пхпшного isEmpty().

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

Пробрасывать целый скоуп в функцию при помощи apply

Вы не знаете, что делает apply, ведь так?

И да, я помню, как в ноде прочитать файл (монгой я не пользуюсь), хотя пишу на ней пару десятков строчек в месяц максимум — стандартный модуль возвращает объект стандартного интерфейса Stream. И никаких плясок с ob_start(), из-за того, что какой-то метод может возвращать строки только записав в stdout.
Когда при приведении к json метод возвращает null — это не удивительно, в json нет NaN.


Проблема в том, что null — это валидный JSON, и возвращать такое не логично в случае, когда дата невалидна.

Когда таймстемп невалидной даты — невалидное число, для меня тоже нет в этом ничего удивительного.


Тут я с вами согласен, дело только за оставшимися функциями.

Вы не знаете, что делает apply, ведь так?


Очевидно я имел в виду контекст this, а не скоуп, область видимости, если вы хотите придраться к формулировке. И тем не менее я не вижу хороших способов применения этого.

Я задал вам вопрос потому, что мне кажется что все современные языки активно тащат фичи друг у друга, так что с точки зрения «приятных» вещей все они плюс-минус одно и то же. Добавление новых фич не ломает совместимость, и я рад что в новом стандарте ECMA script наконец добавили итерацию по значениям коллекций. Но вот исправить все эти по-вашему «надуманные» проблемы Javascript, на которые уже завязана куча кода, практически нереально. И поэтому я удивляюсь, что в этой части вы не замечаете разницы Javascript и других языков, продолжая его любить.
Ну, нравится мне этот язык. На нём можно писать для продакшна — жутко скучно со всеми включенными ворнингами jshint (кроме eqnull), используя только самые известные и несложные паттерны. Ну вроде как, в php можно использовать register_globals и $_REQUEST, но не стоит. Так и в js можно использовать with и ==, но не стоит.

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

Наверняка у других участников и коллег тоже подобное психоэмоциональное состояние перманентного стресса после JS, под конец рабочего дня ;)
Я уже больше 6 лет на фронте, было всякое, но сейчас: прикрутил нормальный пакетный менеджер, разруливающий зависимости, подучил матчасть по языку. И знаете, мне JS тоже нравится. При всех его «особенностях». Поэтому не говорите за всех.
Ах да. Про функцию sum. Это уже зависит от вас. Если внутри аргументы будут приводиться к Number, то ничего плохого не произойдёт, и не надо приводить ничего вручную при каждом вызове — это уже вопрос апи, а не языка.

Угадайте, что вернет `Math.max(«2», «3») ` из стандартной либы. Как ни странно, число 3.
Если внутри аргументы будут приводиться к Number


В этом и проблема — нельзя быть уверенным в чужом коде в такой, казалось бы, мелочи.
А ведь помнится ходили разговоры про tcl в браузере вместо/вместе c js…
Only those users with full accounts are able to leave comments. Log in, please.