Помогите пожалуйста, если можно с объяснением
Не могу решить задачу.
Написать функцию, которая принимает в качестве параметра объект и возвращает массив методов принимаемого объекта. |
DenisZlgst,
:cray: const foo = obj => Object.keys(obj); https://developer.mozilla.org/ru/doc...ts/Object/keys |
Цитата:
Это будет массив всех свойств, а нужны методы const foo = obj => Object.keys(obj).filter(m => typeof obj[m] === 'function') Но все равно непонятно какие именно методы нужны. Тут вернутся только собственные перечислимые. Еще могут быть и не перечислимые, и методы прототипов... И заданные не строками, а символами (Symbol)... В том числе и в прототипах. |
Вот те универсальная шляпа.)
/**
* @callback Filter
* @param value
* @param {string | symbol} key
* @param {?object} getset
* @param {?function} getset.get
* @param {?function} getset.set
* @returns {boolean}
*/
/**
* @typedef Options
* @type {object}
* @property {boolean=true} deep
* @property {boolean=true} getters
* @property {boolean=getters} setters
* @property {boolean=false} symbols
* @property {boolean=} enumerable
* @property {boolean=} configurable
* @property {boolean=} writable
*/
/**
* @param {object} obj
* @param {Filter} [filter]
* @param {Options} [options]
* @returns {string[]}
*/
function getPropertyKeys(obj, filter, options) {
if (typeof filter !== 'function') {
options = filter;
filter = (value, key) => true;
}
const {
deep = true,
getters = true,
setters = getters,
symbols = false,
...descriptorOptions
} = options ?? {};
const not = (descriptor, key) => key in descriptorOptions && descriptorOptions[key] !== descriptor[key];
const {
getOwnPropertySymbols,
getPrototypeOf,
getOwnPropertyDescriptors,
keys,
assign,
prototype
} = Object;
let current = obj;
let descriptors;
do {
descriptors = assign(getOwnPropertyDescriptors(current), descriptors);
if (current === prototype) break;
current = getPrototypeOf(current);
} while (deep && current);
let list = keys(descriptors);
if (symbols)
list = list.concat(getOwnPropertySymbols(descriptors));
return list.filter(key => {
const descriptor = descriptors[key];
const { get, set, value } = descriptor;
if (not(descriptor, 'enumerable'))
return false;
if (not(descriptor, 'configurable'))
return false;
if (get || set) {
return (setters || setters)
&& filter(get && get.call(obj), key, { get, set });
}
if (not(descriptor, 'writable'))
return false;
return filter(value, key);
});
}
getPropertyKeys([], value => typeof value === 'function', {
symbols: true
});
|
Aetae,
:) |
Aetae,
строки 32 - 34 верно или надо поменять местами? |
рони, верно, это была фишка со свапом: [a, b] = [b, a], чтоб типа obj [,filter [, options]]. Я конечно намудрил там излишне, поправил по-человечски.)
|
Aetae,
ясно. |
Цитата:
Либо (object, filter, options) либо (object, options) Менять местами - излишество. Хотя правильнее, наверно, (object, options, filter) |
Aetae,
интересная фишка!!! +++ |
voraa, не согласен на счёт (object, options, filter). В options нормальные умолчания.)
Правилбьно было бы конечно, чтоб и так (object, options, filter) и так (object, filter, options). Но это некрасивую условную раскоряку писать.) Давно хочу либу сделать для работы с аргументами функции в любых порядках и направлениях, да руки не доходят. Те что видел в npm мне эстетически не нравятся.) |
Цитата:
Простой пример - функция создания элемента С вариантами использования create (tag, options [, children [, parent]]) create (tag [, children | null [, parent]]) где tag - string children - Node | Array | string parent - Element options - object (но не Array | Node) Слишком много разных проверок, что бы просто создать элемент Проще зафиксировать параметры и проверять на null или undefined. Универсализм плохо сочетается с эффективностью. |
voraa, я это себе как-то так представляю(чисто черновой набросок):
function create ({tag, options, children, parent}) {
console.log({tag, options, children, parent})
}
function isType(arg, types) {
if(Array.isArray(types))
return types.some(type => isType(arg, type));
if(typeof types === 'function')
return types(arg);
return arg === types;
}
function findArgs(args, list) {
let maxArgsMatchLength = -1;
let maxArgsMatchNames;
list.forEach(({
sublist,
sublist: { length },
names
}) => {
if(length <= maxArgsMatchLength) return; // ничего не делаем если уже нашли больше аргументов
for(let i = length; i--;) {
if(!isType(args[i], sublist[i]))
return false;
}
maxArgsMatchLength = length;
maxArgsMatchNames = names;
});
if(maxArgsMatchLength === -1)
throw new Error('invalid arguments');
return Object.fromEntries(
maxArgsMatchNames
.slice(0, maxArgsMatchLength)
.map((key, i) => [key, args[i]])
)
}
function withAttrs(func, list) {
const bigList = list.flatMap(obj => {
const sublist = [];
const entries = Object.entries(obj);
const current = [];
const names = [];
for(let arg in obj) {
const type = obj[arg];
if(arg.endsWith('?')) {
arg = arg.slice(0, -1);
sublist.push(current.slice());
}
names.push(arg);
current.push(type)
}
sublist.push(current);
return sublist.map(arr => ({ sublist: arr, names }));
})
return function(...args) {
return func.call(this, findArgs(args, bigList));
}
}
isNode = () => true;
createWithArgs = withAttrs(create, [
{tag: isString, options: isPlainObject, 'children?': [isNode, isArray, isString], 'parent?': isElement},
{tag: isString, 'children?': [isNode, isArray, isString, null], 'parent?': isElement},
]);
createWithArgs('1', {a: 3}, [])
Все isX функции из lodash, но естественно возможно использование своих. +Обязательно должно бы кэширование: чтоб одна функция проверки типа вызывалась для одного конкретного аргумента только один раз. +Разделить проверку списка аргументов не всех сразу, а по порядку. +Добавить поддержку spread. +Типизировать для typescript(это будет ад, если вообще возможно). ... =) |
Это конечно жесть и ад.
Я плюнул на такие вещи. Если и делаю, то для конкретной функции и в случаях, когда просто можно сдвигать параметры влево |
Все это называется код ради кода.
Если вы это используете то у вас ошибки в архитектуре, голове ... |
Vlasenko Fedor,
Цитата:
Цитата:
Просто иногда пишешь функцию с чётким интерфейсом, а мыслишка в голове "а ведь было бы круто если бы можно было и так, и вот так, и ещё так и чтоб TS сам на это overload'ы вывел".) С TS кстати это не настолько ужасно, как может показаться: он должен проверять как возможные комбинации аргументов относительно переданной функции, так и делать чёткий интерфейс для новой. Т.е. тут нельзя будет опечататься или указать что-то не то. Как вариант обёртки для внешнего интерфейса какой-нить либы - почему нет.) |
Цитата:
мне кажется так достаточно для парметров
const test = (tag, params = {}) => {
const def = {
a: 'text',
b: 2
}
params = { ...def, ...params }
console.log(params)
}
test('tag', { b: 5, c: 3 })
без использования TS, глянув дефолтные всегда можно понять, что передать TS не учу, я им vbs, vb не могу простить только подумал MS продуктами уже 12 лет как и не пользуюсь и вроде ок :) |
Aetae,
Для ускорения строку 21 наверно можно так if (length != args.length) return; |
voraa, не, мыж не знаем что там за проверки, может ему ок, если последние аргументы будут undefined:
{foo: isString, bar: [isArray, undefined], 'buz': [isElement, undefined]},
По идее конечно в таком случае надо юзать 'foo?' но мало ли какие там сложные и хитрые проверки будут.) |
По идее
('str') и ('str', undefined, undefined) - разные вещи. В последнем случае количество аргументов будет 3 и проверка нормально сработает ЗЫ Я так нарвался на scrollIntoView() у меня там вызов получался scrollIntoView(x), а x было = undefined И долго чесал репу, почему не работает, как надо |
Ну так то да. Но тогда if (length > args.length) return; потому что можно передать левый мусор в отсутствующие аргументы и это будет ок.)
|
Я попытался повозиться с твоим скриптом, адаптировать его для собственных нужд. Работает нормально. Но столкнулся с небольшой неувязкой.
return func.call(this, findArgs(args, bigList)); предполагает, что функция может быть и методом. Но super из нее не вызовешь. С проверками типов тоже приходится быть очень аккуратным
[
{par1: isObject, 'par2?': isArray},
{par2: isArray}
]
isObject просто как o => typeof o === 'object' не сделаешь Надо o => typeof o === 'object' && !Array.isArray(o) Ну и других подобных ситуаций хватало. Поэтому проверки типов иногда становятся довольно громоздкими Меня такие коды бросают в дрожь из-за цены вызова функции по времени. Провел тестирование Вызывал 1 000 000 раз обычную функцию (но пустую) и делал вызов с такими проверками параметров. С одной стороны разница по времени в 50 раз! С другой стороны 0.6 сек на миллион вызовов. |
Дык, всё в туду списке указано.
1. Решается обработкой по порядку, т.е. напишешь так: voraa, [ {par2: isArray}, {par1: isObject, 'par2?': isArray} ] И если первое прошло, на второе не пойдёт. Там чутка поправить надо, убрать flatmap и добавить ещё один цикл.) Ну и isPlainObject. 2. Кэширование. Как в рамках одного вызова, так и в рамках всех вызовов в таске. Ну и 50 раз оверхед над пустой функцией не особо страшен, потому что он статичен. Возьми функцию по-тяжелее и процент оверхеда уменьшится.) А для особо критичных ситуаций - надо предусмотреть возможность вызова оригинальной функции. 3. super и не будет работать в функциях, а если ты обернёшь метод и положишь его обратно - всё будет норм. |
Цитата:
Это все прокатывает только для статических методов. И что бы пользоваться super приходится делать два метода - не обернутый и обернутый
class A extends B {
....
static f ({args...}) {
super.f()
}
static fwa = withAttrs(f, [...])
}
просто
static f = withAttrs(function ({args}) {
super.f() // !!!
}, [.....])
не сделаешь А не статический метод просто в классе не сделать, только через прототип туда его пихать Приходит в голову мысль получать то, что bigList отдельно, а саму функцию метод оформлять так
method (...args) {
let {par1, par2, par3} = findArgs(args, bigList);
.....
}
|
Вообще всегда так делали, коли надо:
constructor(){
super();
this.method = withAttrs(this.method);
}
Ток в ts, такое не прокатит, да. |
Цитата:
И в обычном js это как то не так. Методы должны быть в прототипе, а не в объекте. |
voraa, ну
A.prototype.method = withAttrs(A.prototype.method);тож сработает. А ts тут при том что очень не любит когда классы трогают уже после декларации.) |
| Часовой пояс GMT +3, время: 17:53. |