LINUX.ORG.RU

Пять строк с зависимостью

 ,


0

1

Читаю Airbnb JavaScript Style Guide, дохожу до пункта 3.7, где предлагается использовать (как один из хороших (или наилучших) вариантов.

Проверять наличие свойства можно так

const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(object, key));

, а можно так

import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));

Во втором варианте сама проверка на 5 символов меньше, но для этого в проект надо тянуть две библиотеки, первая состоит из 5 строк:

'use strict';

var bind = require('function-bind');

module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty);

, две из которых пусты. Она зависит от ещё одной библиотеки в чуть больше 50 строк.

А теперь самая суть, у этого трёхстрочника 15 миллионов загрузок в неделю.

А теперь вопрос: неужто у первого подхода есть какой-то тайный недостаток, вынуждающий тянуть какую-то левую библиотеку? Почему после left-pad такие штуки всё ещё популярны?

А теперь козырь. Я, может, что-то не понимаю, но

const has = function(object, key) {
    return Object.prototype.hasOwnProperty.call(object, key);
}
console.log(has(obj, key));

и оно вроде даже работает.

Ответ на: комментарий от abcq

Оно-то и пусть(хотя бред какой-то, ну да ладно), но в рекомендации по стилю кода — перебор.

fernandos ★★★ ()

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

Virtuos86 ★★★★★ ()
Ответ на: комментарий от fernandos

В питоне, например, искоропки есть hasattr(obj, 'attr'). Это что за ООП, если так коряво надо проверять наличие свойства?

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Боятся говнокода — к компьютеру не подходить.

Куда хуже — его писать, такой цели нет.

fernandos ★★★ ()

https://drewdevault.com/2021/11/16/Cash-for-leftpad.html — I will pay you cash to delete your npm module

Я могу лишь сказать, что это очевидный антипаттерн, а сам Airbnb JavaScript Style Guide, судя по всему, является эдаким подобием вики: «один посрал — второй поел». Именно потому я предпочитаю не пользоваться гайдами, если не знаю, кому за этот гайд можно будет плюнуть в харю.

А теперь вопрос: неужто у первого подхода есть какой-то тайный недостаток, вынуждающий тянуть какую-то левую библиотеку? Почему после left-pad такие штуки всё ещё популярны?

Не оскудеет IT идиотами никогда, пока в IT платят деньги.

Я, может, что-то не понимаю, но
const has = function(object, key)
и оно вроде даже работает.

> Object.prototype.hasOwnProperty = 2
2
> const has = function(object, key) {
...     return Object.prototype.hasOwnProperty.call(object, key);
... }
undefined
> console.log(has({a: 'asd'}, 'a'));
Thrown:
TypeError: Object.prototype.hasOwnProperty.call is not a function
    at has (repl:2:44)
>

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

byko3y ★★★★ ()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от Virtuos86

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

Воабще-то с Крокфордом и ES2015 JS стал юзабельным языком. До того это был треш, да, там даже модулей не было.

byko3y ★★★★ ()
Ответ на: комментарий от byko3y

Ну как юзабельным, дали лакированные костыли, и надели красивый костюмчик из твида и методичку как лучше на них ходить, и чего лучше избегать.

abcq ★★ ()
Ответ на: комментарий от byko3y

https://drewdevault.com/2021/11/16/Cash-for-leftpad.html — I will pay you cash to delete your npm module

Читал, хорошая статья.

Я могу лишь сказать, что это очевидный антипаттерн, а сам Airbnb JavaScript Style Guide, судя по всему, является эдаким подобием вики: «один посрал — второй поел». Именно потому я предпочитаю не пользоваться гайдами, если не знаю, кому за этот гайд можно будет плюнуть в харю.

А так хотелось.

Спасибо.

fernandos ★★★ ()
Ответ на: комментарий от fernandos

Самый адекватный вариант упомянут в гайде, как ни странно, это:

Object.prototype.hasOwnProperty(obj, 'key')

Его нужно использовать не потому, что злобные гномики перепишут hasOwnProperty, а потому что в роли объекта может прилететь черт знает что, вплоть до undefined:

> Object.prototype.hasOwnProperty(undefined, 'key')
false

Вся остальная аргументация из гайда — это джуновские бредни. Если кто-то переписал Object.prototype.hasOwnProperty, то значит была причина и ты должен использовать новую функцию. Если кто-то не должен был переписывать прототип, то его нужно бить по пальцам. Если прототип переписывает сторонняя либа из NPM, то бить нужно того, кто подключил левую либу из NPM без аудита.

byko3y ★★★★ ()
Ответ на: комментарий от Virtuos86

можешь попробовать сам объяснить феномен подобных десятистрочных модулей с биллионами загрузок

Бездумно копипастят с гайдов и stackoverflow. А потом кто-то включил либу в зависимость, а потом на ту новую либу возникают зависимости, и вот уже что не поставь — в любых раскладах нужно будет ставить left-pad. Отсюда и миллионы загрузок — их тем больше, чем либа фундаментальнее, то есть, чем больше других пакетов на нее ссылаются.

byko3y ★★★★ ()
Ответ на: комментарий от Virtuos86

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

Это не я, я не поощряю, какие ко мне вопросы? JS сейчас номер 1 ЯП в индустрии, и потому каждый школьник приходя в язык начинает писать свои left-pad-ы. Это тёмная сторона хорошего пакетного менеджера — удачи этим школьникам свою россыпь пятистрочных библиотек организовывать через AutoTools.

byko3y ★★★★ ()
Ответ на: комментарий от byko3y

Это тёмная сторона хорошего пакетного менеджера

Это тёмная сторона пакетного менеджера, который при размере кода меньше 2-3х экранов не выводит сообщение об ошибке или, как минимум, предупреждение.

fernandos ★★★ ()
Ответ на: комментарий от byko3y

Вам не кажется что слишком много нужно на такой небольшой ответ, язык дает возможность, кто-то ей обязательно воспользуется.

abcq ★★ ()
Ответ на: комментарий от fernandos

Это тёмная сторона пакетного менеджера, который при размере кода меньше 2-3х экранов не выводит сообщение об ошибке или, как минимум, предупреждение

В последнем моем проекте на JS были модули с нулем строк кода. Просто пустой файл, и подобных файлов в проекте было немало.

byko3y ★★★★ ()
Ответ на: комментарий от Virtuos86

Это что за ООП, если так коряво надо проверять наличие свойства?

Это что за ООП, если надо проверять наличие свойства? /fixed

no-such-file ★★★★★ ()
Ответ на: комментарий от abcq

Вам не кажется что слишком много нужно на такой небольшой ответ, язык дает возможность, кто-то ей обязательно воспользуется

hasOwnProperty — это редкий запрос. Для более частых вещей, например, запроса всех собственных свойств для итерации по ним, есть Object.keys(), которому не нужно prototype и call, поскольку он игнорирует значение this. Кстати, я обычно пишу {}.hasOwnProperty.call(obj, key) — это чутка короче.

byko3y ★★★★ ()

Я, может, что-то не понимаю

Ты не понимаешь, что тут на один вызов функции больше. Bind делает карринг, а ты из функции вызываешь другую функцию.

no-such-file ★★★★★ ()
Ответ на: комментарий от fernandos

Часто публикуете такие модули в публичный архив?

Ну типа в NPM хотя бы есть строки кода — скажи спасибо за это. Нужно понимать, что NPM — это тупо помойка случайного кода со всех уголков земли, как github, не нужно от них ждать чуда.

byko3y ★★★★ ()
Ответ на: комментарий от fernandos

бадья выполняется быстрее

Она выполняется 1 раз при привязке, если ты не понял. Кстати, вообще непонятно на какой хер нужно проверять наличие свойства? Если тебе прилетает НЕХ, и нужно её расколупать, то лучше взять lodash get и не мужать жопу. А если предполагается, что это будет какой-то объект класса, то проверять нужно через instanceof.

PS: но если очень хочется, там есть и has.

no-such-file ★★★★★ ()

Я использую Object.prototype.hasOwnProperty или 'key' in object. Из недостатков у hasOwnProperty - только длина самой записи, поэтому вариант со своей функцией тоже подойдёт, если у тебя таких проверок овердофига (что немного странно).

neversleep ★★ ()
Ответ на: комментарий от Virtuos86

феномен подобных десятистрочных модулей с биллионами загрузок

Это всё из-за безумного npm. Очень уж легко стало качать неведомую фигню. Никто ведь не смотрит, что оно там насосало, лишь бы скорее набыдлокодить. Я вот смотрю, и мне всегда дурно становится. Вся такая срань как npm, rubygems или pip должна быть запрещена женевской конвенцией.

bread ()
Ответ на: комментарий от bread

... на которую кладут с прибором половина тех, кто ее принимал

Virtuos86 ★★★★★ ()

Никто в треде (кажется, читал по диагонали) не обратил внимание на это:

// cache the lookup once, in module scope.

То есть, прежде всего, это способ сэкономить такты (хаха, можно подумать это волнует разработчиков на js), за счёт того, что при каждом вызове не надо будет лезть в Object.prototype за методом.

Поэтому данный вариант:

const has = function(object, key) {
    return Object.prototype.hasOwnProperty.call(object, key);
}

Не замена, а делает только хуже, т.к. к необходимости поиска метода добавляется ещё и лишний вызов функции.

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

emorozov ()
Ответ на: комментарий от byko3y

в роли объекта может прилететь черт знает что, вплоть до undefined

Ну это-то всегда может случиться, поэтому проще response?.hasOwnProperty(...), если манкипатчеров не боишься.

Nervous ★★★★★ ()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от emorozov

«Буду дышать через раз — спасу планету», очень странная экономия.

Не замена, а делает только хуже, т.к. к необходимости поиска метода добавляется ещё и лишний вызов функции.

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

fernandos ★★★ ()
Ответ на: комментарий от fernandos

«Буду дышать через раз — спасу планету», очень странная экономия.

Когда-то, ещё до Chrome и V8, я подобными трюками оптимизировал код на JS, который выполнялся секунд 30, до < 1 секунды. Получилась разница между совершенно неюзабельной страницей (т.к. до 30 секунд почти никто не дожидался) и более-менее юзабельной.

Это был код расцветки слов и установки обработчиков (для просмотра словаря, добавления слов в словарь) на одном сайте для изучения языков (не хочу вдаваться в подробности, каком именно). Часть этих действий делалась на стороне сервера, но всё на стороне сервера сделать было невозможно, а на стороне клиента мог быть, например, IE6, в котором эти действия выполнялись даже дольше 30 секунд.

Но это было лет 14 назад, не думал, что это до сих пор актуально.

Думаю, что и этот стиль был написан когда-то давно, и в него давно никто не смотрит и не обновляет.

emorozov ()
Ответ на: комментарий от byko3y

Если кто-то переписал Object.prototype.hasOwnProperty, то значит была причина и ты должен использовать новую функцию

Кто-то заюзал объект как map между ключами, приходящими от юзера, и какими-нибудь значениями. Один из ключей называется hasOwnProperty. Энжой юр uncaught TypeError: hasOwnProperty is not a function в рантайме.

И да, это происходит только потому, что нормальный Map завезли 5 лет назад, а не при релизе первой версии жабоскрипта.

EDIT: вейт, ты именно про Object.prototype, а не whateverObject.hasOwnProperty? Ну ок, но это жаваскрипт и может произойти что угодно.

x3al ★★★★★ ()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от emorozov

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

abcq ★★ ()

Библиотека is-number предназначена для проверки, является ли пришедшее значение числом.

В настоящий момент она находится на мажорной версии 7.

Think about it.

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

является ли пришедшее значение числом

Китайские числа понимает? Или только римские арабские?

anonymous ()
Ответ на: комментарий от emorozov

То есть, прежде всего, это способ сэкономить такты (хаха, можно подумать это волнует разработчиков на js), за счёт того, что при каждом вызове не надо будет лезть в Object.prototype за методом

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

byko3y ★★★★ ()
Ответ на: комментарий от Nervous

Ну это-то всегда может случиться, поэтому проще response?.hasOwnProperty(...), если манкипатчеров не боишься

При чем тут претензия к манкипатчу, если весь JS — это один сплошной манкипатч, где тебе пришлют JSON:

{ a: 1, b: 2, hasOwnProperty: 3 }
и удачи его парсить.

byko3y ★★★★ ()
Ответ на: комментарий от abcq

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

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

byko3y ★★★★ ()
Ответ на: комментарий от Miguel

Библиотека is-number предназначена для проверки, является ли пришедшее значение числом

Неактуально давно, хз почему оно до сих пор живо.

byko3y ★★★★ ()
Ответ на: комментарий от byko3y

пришлют JSON:{ a: 1, b: 2, hasOwnProperty: 3 } и удачи его парсить

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

Nervous ★★★★★ ()
Ответ на: комментарий от byko3y

Поэтому я уточнил, что подобные оптимизации использовал в 2007-2008 годах, когда в JS не было оптимизирующих компиляторов, и не было JIT.

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

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

emorozov ()

sudo cast @byko3y, @no-such-file, @emorozov: сделал первые бенчмарки.

➜ hyperfine "node ../const.js" "node ../func.js" "node has.js"
Benchmark 1: node ../const.js
  Time (mean ± σ):      1.541 s ±  0.008 s    [User: 1.529 s, System: 0.008 s]
  Range (min … max):    1.531 s …  1.553 s    10 runs
 
Benchmark 2: node ../func.js
  Time (mean ± σ):      1.271 s ±  0.008 s    [User: 1.265 s, System: 0.006 s]
  Range (min … max):    1.259 s …  1.284 s    10 runs
 
Benchmark 3: node has.js
  Time (mean ± σ):      1.379 s ±  0.007 s    [User: 1.380 s, System: 0.010 s]
  Range (min … max):    1.372 s …  1.392 s    10 runs
 
Summary
  'node ../func.js' ran
    1.08 ± 0.01 times faster than 'node has.js'
    1.21 ± 0.01 times faster than 'node ../const.js'
➜ cat ../func.js
let obj = {a: 10};
 
const hasF = function(object, key) {
    return Object.prototype.hasOwnProperty.call(object, key);
}
for (let i = 0; i < 10 ** 8; i++) {
    hasF(obj, 'a');
    hasF(obj, 'b');
}
➜ cat ../const.js
let obj = {a: 10};
 
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
for (let i = 0; i < 10 ** 8; i++) {
    has.call(obj, 'a');
    has.call(obj, 'b');
}
➜ cat has.js
import has from 'has';
let obj = {a: 10};
 
for (let i = 0; i < 10 ** 8; i++) {
    has(obj, 'a');
    has(obj, 'b');
}

Из этого всего самопальная функция оказалась самой быстрой.

fernandos ★★★ ()
Ответ на: комментарий от fernandos

самопальная функция оказалась самой быстрой

А теперь попробуй не выёживаться, а тупо вызывать obj.hasOwnProperty без всяких функций вообще.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.