В js есть пара очень малоизвестных фич.
Таких, как, например, оператор "," — позволяет писать несколько команд в строку, возвращает последний.
var x = (1, 2, 3); // x = 3
А ещё можно изображать питон:
if (something)
firstFunc(),
secondFunc();
К другим не очень известным фичам относятся, например, блоки или метки циклов (чтобы выходить чрез break во внутреннем цикле из внешнего цикла), кому интересно.
Вы бы, коль уж берёте смелость на себя критиковать язык, хоть не признавались в незнании в нём базовых вещей :)
Это не переопределение операторов, это обычное приведение типов. Попробуйте создать объект с функциями toString и valueOf (возвращающимися соответственно строку и число) и скастить его в строку или число.
А вот +0.5 это такой интересный способ округления по законам математики.
Это очень давно известная штука.
floor(число + 0.5) — правильно округляет число (дробная часть меньше 0.5 — вниз, выше — вверх),
где floor отбрасывает дробную часть.
К слову, как-то немножко поигрался с методами быстрого счёта, и после них появилось ощущение, что мозги начали думать гораааздо быстрее. Ненадолго, правда.
Я считаю, что this логичен. This хранит контекст, в котором функция вызвана. Ну, TheShock уже всё отлично объяснил.
Смотрите, вот тут мне нужен родной контекст функции:
SomeClass.prototype.init = function () {
this.element.addEventListener('click', this.onElementClick);
};
SomeClass.prototype.onElementClick = function () {
this.style.color = 'red';
};
// так делать не очень хорошо, но не суть: легко придумывается более адекватный и правильный, но многословный пример
А здесь нужен контекст класса, и я просто делаю bind:
SomeClass.prototype.init = function () {
this.element.addEventListener('click', this.onElementClick.bind(this));
};
SomeClass.prototype.onElementClick = function () {
this.element.style.color = 'red';
};
Я тоже хотел привести пример с естественными языками ). Но больше в том плане, что приходить в английский и говорить «у вас неправильно, потому что у вас перфекты, вот смотрите, у нас в русском всего 3 времени, и нам норм» (что, к слову, не так, перфекты в русском вроде бы вполне себе есть) — как минимум, не очень правильно.
И язык программирования такого типа (условно) никак не может считаться хорошим универсальным языком.
Сравнивать языки программирования и естественные тоже не очень правильно по очевидной причине. Правильнее сравнивать ЯП с эсперанто, токи пона, ифкуилем, илакшем и иже с ними.
А так программа кое-как работает, пусть неправильно
А может, внезапно, работать правильно! Хотя бы чуть-чуть.
Вот я пишу-пишу в программе на Java, и вдруг там непойманный exception в одном из модулей, и вся программа вылетает. И мой несохранённый документ… тоже вылетает.
А вот я пишу-пишу в программе на JS / [другом языке, позволяющем ошибки], и вдруг там непойманный exception в одном из модулей. Пол-интерфейса ломается, зато второй половины мне хватает, чтобы сохранить документ. И я благополучно перезапускаю программу и работаю дальше.
Если я правильно понял ваш пример.
Мне совершенно неочевидно, почему сразу не написать функцию, которая позволяла бы явный выбор единицы измерения.
Напрашивается заметить, что все 4 параметра могут быть в разных системах координат, а там ещё есть и цвет, и делать ещё 5 доппараметров в функции как-то некрасиво, как минимум.
Но тут гораздо важнее иное: логика превращения каких-то единиц в пиксели может быть достаточно сложной (сложнее, чем взять константу и, например, умножить на число). Ну, например, я написал плагин для изометрии и хочу делать так (пример немножко утрированный):
var pointInIsometria = {
plane: planeObject,
rectOfPlane: [x, y, z]
};
ctx.rect(pointInIsometria, pointInIsometria, 200, 200, 'red');
// или даже так:
ctx.rect(planeObject, [x, y, z], 200, 200, 'red');
Кроме того, мне не нужно добавлять какие-то дополнительные параметры, чтобы позволять что-то расширять. Я по умолчанию разрешаю это делать практически со всеми своими объектами и методами (но с риском выстрелить в ногу, разумеется). И совершенно не забочусь, что пойдёт, если кто-то расширит как-то не так.
На ум пришла аналогия: это как продавать машину, разрешать на ней менять колёса, двигатель и дворники (компоненты, хочу заметить, вполне себе самостоятельные, и замена любого из них на делающий то же, но по-другому, и предоставляющий тот же io-интерфейс, не ломает систему в целом), но забивать на гарантию в случае нестоковой комплектации ).
P.S.
Признаться, я совершенно не думал о доппараметре в функции (хоть он тут и совсем не к месту). Из той же библиотеки у меня есть интересный пример, связанный с прототипным наследованием. Интересно, сможете ли вы реализовать подобное на C / C++, например? Да и на любом языке без прототипов, вообще говоря, было бы интересно.
У меня у объектов на канвасе есть функция attr. Она возвращает / изменяет значение во внутреннем хэше объекта:
rect.attr('x'); // -> 20; работает как getAttr
rect.attr('x', 200); // работает как setAttr
Но кроме этого она проверяет наличие геттера / сеттера в объекте attrHooks в классе, и дёргает его. Например, на изменение координат прямоугольника дёргается перерисовка.
Фишка в том, что есть несколько классов (Rect, Circle, Path, Image, Text), которые наследуются от абстрактного класса Drawable. У Drawable есть свои общие attrHooks, и у каждого из классов есть свои специфические. При этом я хочу, чтобы при добавлении новых методов в attrHooks у Drawable они появлялись у всех его наследников (если они там не перезаписаны, естественно). Но не наоборот — специфические attrHooks у Rect не должны затрагивать attrHooks у Drawable.
На прототипах это реализовалось достаточно легко:
function drawableAttrHooks() {}
Drawable.prototype.attrHooks = drawableAttrHooks.prototype;
Rect.prototype.attrHooks = new drawableAttrHooks();
// теперь если я напишу
Drawable.prototype.attrHooks.someProperty = 5;
// то оно прокинется в Rect:
Rect.prototype.attrHooks.someProperty; // -> 5
// но в обратную сторону это не действует:
Rect.prototype.attrHooks.someAnotherProperty = 8;
Drawable.prototype.attrHooks.someAnotherProperty; // -> undefined
Как удобно отослать к диагнозу вместо нормального ответа по теме.
… определённо говорит об удобстве, высокой продуманности...
Подобное можно написать о любой фиче в любом языке. А уж в функциональных-то — тем более.
А this в самом деле очень прост. Не говоря уже про return. Я даже описал всё это всего лишь двумя абзацами.
Немного негодования по теме
Если я приду в ваш язык и буду негодовать, что return где-то не требуется, что вы сделаете? Согласитесь «ну да, вот язык такой ужасный, сам мучаюсь» или пошлёте читать мануал?
Если я приду в C++ и заявлю, что деление на h и cpp-файлы некошерно, и вообще никто в 2к17 не подключает файлы к проекту с помощью директивы препроцессора, а все делают это функцией?
Если я приду в Python и заявлю, что язык ужасный, потому что в нём нет {}, а вместо этого отступы?
Да, в конце концов, если я приду в любой сильно типизированный язык и скажу, «сильная типизация — это фигня, и поэтому язык плохой»?
Нет, я так не делаю ). Потому что понимаю, что языки разные, разным людям по-разному удобно, и вообще (как мне кажется) тут имеет место аналог гипотезы лингвистической относительности.
И мне не совсем понятно, почему вы приходите в JS и заявляете о неправильности this (к слову, я могу назвать ряд действительно слабых (по моему мнению) вещей в js — например, typeof… но уж никак не полностью логичный this).
А с this на самом деле всё понятно и логично.
В JS функция и класс — это одно и то же. Только первая вызывается просто со скобочками, а вторая ещё и со словом new. Ну типа funcName() и new ClassName(). И это вполне естественно и очевидно, что в классе this указывает на экземпляр класса. В функции же this указывает на объект, если функция является методом объекта, в противном случае на глобал.
Стрелочных функций в js издавна не было — они появились только в ES6. Для простоты и удобства: теперь вместо длинного «function () {… }.bind(this)» можно написать просто "() => {}". При этом около многострочных стоит оговорка: в них нужен return.
В любом туториале по стрелочным функциям (или туториале по особенностям ES6, где упоминаются стрелочные функции), в любом! — упоминается, что многострочные стрелочные функции требуют return.
Кто вам виноват, что вы не потрудились прочитать базовых вещей?
Первая статья из этого цикла "JavaScript как..." была написана как раз-таки функциональщиком, отрицающим такие индустриально-базовые вещи, как return и скобочки.
Упс, прошу прощения, неправильно выразился.
Стоило написать так: представь, что ты пишешь std:sort или std:string, и захотел разрешить в каком-то месте их расширять.
Да, в определенных пределах, выход за которые грозит отстрелом ноги.
Таких, как, например, оператор "," — позволяет писать несколько команд в строку, возвращает последний.
А ещё можно изображать питон:
К другим не очень известным фичам относятся, например, блоки или метки циклов (чтобы выходить чрез break во внутреннем цикле из внешнего цикла), кому интересно.
Вы бы, коль уж берёте смелость на себя критиковать язык, хоть не признавались в незнании в нём базовых вещей :)
Это не переопределение операторов, это обычное приведение типов. Попробуйте создать объект с функциями toString и valueOf (возвращающимися соответственно строку и число) и скастить его в строку или число.
Это перевод wtfjs, отсюда и заголовок
Это очень давно известная штука.
floor(число + 0.5) — правильно округляет число (дробная часть меньше 0.5 — вниз, выше — вверх),
где floor отбрасывает дробную часть.
Я считаю, что this логичен. This хранит контекст, в котором функция вызвана. Ну, TheShock уже всё отлично объяснил.
Смотрите, вот тут мне нужен родной контекст функции:
А здесь нужен контекст класса, и я просто делаю bind:
Сравнивать языки программирования и естественные тоже не очень правильно по очевидной причине. Правильнее сравнивать ЯП с эсперанто, токи пона, ифкуилем, илакшем и иже с ними.
А может, внезапно, работать правильно! Хотя бы чуть-чуть.
Вот я пишу-пишу в программе на Java, и вдруг там непойманный exception в одном из модулей, и вся программа вылетает. И мой несохранённый документ… тоже вылетает.
А вот я пишу-пишу в программе на JS / [другом языке, позволяющем ошибки], и вдруг там непойманный exception в одном из модулей. Пол-интерфейса ломается, зато второй половины мне хватает, чтобы сохранить документ. И я благополучно перезапускаю программу и работаю дальше.
Если я правильно понял ваш пример.
Напрашивается заметить, что все 4 параметра могут быть в разных системах координат, а там ещё есть и цвет, и делать ещё 5 доппараметров в функции как-то некрасиво, как минимум.
Но тут гораздо важнее иное: логика превращения каких-то единиц в пиксели может быть достаточно сложной (сложнее, чем взять константу и, например, умножить на число). Ну, например, я написал плагин для изометрии и хочу делать так (пример немножко утрированный):
Кроме того, мне не нужно добавлять какие-то дополнительные параметры, чтобы позволять что-то расширять. Я по умолчанию разрешаю это делать практически со всеми своими объектами и методами (но с риском выстрелить в ногу, разумеется). И совершенно не забочусь, что пойдёт, если кто-то расширит как-то не так.
На ум пришла аналогия: это как продавать машину, разрешать на ней менять колёса, двигатель и дворники (компоненты, хочу заметить, вполне себе самостоятельные, и замена любого из них на делающий то же, но по-другому, и предоставляющий тот же io-интерфейс, не ломает систему в целом), но забивать на гарантию в случае нестоковой комплектации ).
У меня у объектов на канвасе есть функция
attr. Она возвращает / изменяет значение во внутреннем хэше объекта:Но кроме этого она проверяет наличие геттера / сеттера в объекте attrHooks в классе, и дёргает его. Например, на изменение координат прямоугольника дёргается перерисовка.
Фишка в том, что есть несколько классов (Rect, Circle, Path, Image, Text), которые наследуются от абстрактного класса Drawable. У Drawable есть свои общие attrHooks, и у каждого из классов есть свои специфические. При этом я хочу, чтобы при добавлении новых методов в attrHooks у Drawable они появлялись у всех его наследников (если они там не перезаписаны, естественно). Но не наоборот — специфические attrHooks у Rect не должны затрагивать attrHooks у Drawable.
На прототипах это реализовалось достаточно легко:
Подобное можно написать о любой фиче в любом языке. А уж в функциональных-то — тем более.
А this в самом деле очень прост. Не говоря уже про return. Я даже описал всё это всего лишь двумя абзацами.
Если я приду в C++ и заявлю, что деление на h и cpp-файлы некошерно, и вообще никто в 2к17 не подключает файлы к проекту с помощью директивы препроцессора, а все делают это функцией?
Если я приду в Python и заявлю, что язык ужасный, потому что в нём нет {}, а вместо этого отступы?
Да, в конце концов, если я приду в любой сильно типизированный язык и скажу, «сильная типизация — это фигня, и поэтому язык плохой»?
Нет, я так не делаю ). Потому что понимаю, что языки разные, разным людям по-разному удобно, и вообще (как мне кажется) тут имеет место аналог гипотезы лингвистической относительности.
И мне не совсем понятно, почему вы приходите в JS и заявляете о неправильности this (к слову, я могу назвать ряд действительно слабых (по моему мнению) вещей в js — например, typeof… но уж никак не полностью логичный this).
funcName()иnew ClassName(). И это вполне естественно и очевидно, что в классе this указывает на экземпляр класса. В функции же this указывает на объект, если функция является методом объекта, в противном случае на глобал.Стрелочных функций в js издавна не было — они появились только в ES6. Для простоты и удобства: теперь вместо длинного «function () {… }.bind(this)» можно написать просто "() => {}". При этом около многострочных стоит оговорка: в них нужен return.
В любом туториале по стрелочным функциям (или туториале по особенностям ES6, где упоминаются стрелочные функции), в любом! — упоминается, что многострочные стрелочные функции требуют return.
Кто вам виноват, что вы не потрудились прочитать базовых вещей?
Первая статья из этого цикла "JavaScript как..." была написана как раз-таки функциональщиком, отрицающим такие индустриально-базовые вещи, как return и скобочки.
Есть аналоги Malbolge — ифкуиль, например
Я не очень понимаю.
C# / C++ / Haskell / Java / etc -разработчики активно нападают на JS.
Js-разработчики защищают свой язык.
Фанатики как раз первые, а вовсе не вторые. Почему вы написали пост про js-фанатиков, а не haskell-фанатиков или c#-фанатиков?
Заметьте, вовсе не js-разработчики всё это на Хабре начали.
Простите, я правильно понял, у вас львиная доля багов в коде происходит из-за вычитания строк из чисел?
Это пирожок, его надо писать в 4 строчки и с маленькой буквы
Упс, прошу прощения, неправильно выразился.
Стоило написать так: представь, что ты пишешь std:sort или std:string, и захотел разрешить в каком-то месте их расширять.
Да, в определенных пределах, выход за которые грозит отстрелом ноги.