Pull to refresh

Comments 29

UFO just landed and posted this here
О, да я не один такой! =)
Спасибо большое за решение и за ссылку! MDN я возможно уже перечитал: все чаще нахожу вдохновение в самой спецификации. Там еще столько интересного…
О, я кажется когда-то давно проверял свою интуицию по Вашей статье (аж 2014 год!)… и был не очень доволен своим результатом )
Вот еще один интересный способ, тут мы избавились от вложенных функций, от comma operator и как-то короче вышло )))
const point = (x, y, p) => ([p, p.x, p.y, p.__proto__.toString] = [new Object, x, y, Function`return \`(\${this.x}, \${this.y})\``])[0];
UFO just landed and posted this here
Пардонс, вот уже рабочее решение

const point = (x, y, p) => ([p, p.x, p.y, p.__proto__.toString] = [Object.create(new Object), x, y, Function`return \`(\${this.x}, \${this.y})\``])[0];

const testMy = point(10,5);
testMy.x = 15;

console.log(testMy.toString())

const test = {};
console.log(test.toString())
Опять таки здесь, нет нормального наследования: для каждого нового объекта создается свой объект-прототип. В примере выше через верхний IIFE прототип создан один раз и доступ к нему создаваемые объекты имеют через замыкание.
Вот уже есть )))

const point = ((o = Object(), _ = o.toString = Function`return \`(\${this.x}, \${this.y})\``) => (x, y) => ([p, p.x, p.y] = [Object.create(o), x, y])[0])();

const testMy = point(10,5);
const testMy2 = point(20,5);
testMy.x = 15;

console.assert(testMy.__proto__ === testMy2.__proto__);

console.log(testMy.toString())

const test = {};
console.log(test.toString())

Отлично!
У вас явная предрасположенность к деструктуризации ) выглядит правда интереснее comma operator'а.
UFO just landed and posted this here
подстановки в template literals — это тоже фигурные скобки

Угу, я поэтому в своем примере использовал join строк вместо темплейта.

В принципе можно вообще без IIFE, использую свойства функции, многословней, но как бы тоже вариант.

const point = (x, y, o = point.obj = point.obj || Object(), _ = o.toString = o.hasOwnProperty('toString') ? o.toString : Function('return `(${this.x}, ${this.y})`'), p) =>
  ([p, p.x, p.y] = [Object.create(o), x, y])[0];
const testMy = point(10,5);
const testMy2 = point(20,5);
testMy.x = 15;


console.assert(testMy2.__proto__ === testMy.__proto__)
console.assert(point.obj.isPrototypeOf(testMy2))
console.log(testMy2.toString())

const test = {};
console.log(test.toString())


Вот еще более многословный вариант, зато не нужно привязываться к имени функции, просто в use strict не работает arguments.callee


const point = Function('x', 'y', `
  const o = arguments.callee.obj = arguments.callee.obj || Object();
  if (!o.hasOwnProperty('toString')) o.toString = Function('return \`(\${this.x}, \${this.y})\`');
  const p = Object.create(o);
  [p.x, p.y] = [x, y];
  return p;
`)



Вы уже сделали мой день )) можете предложить свой вариант обфускации, затронув какие-нибудь другие конструкции и особенности языка. Было бы классно )
Да, как бы особо не знаю, на медиуме почитываю старые постыАлександра Майорова, он тоже один из нас, любителей извращенного ненормального программирование.
И Вам спасибо, с Вашего поста про мемоизацию у меня как бы и пошел интерес в эту сторону ;)
Вот еще решение на основе параметров, тем самым мы избавились от comma operator в теле функции

const count = f => ((calls, df = (...args) => ++calls && f(...args), z = df.getCalls = () => calls) => df)(0);


Однако, если аргумент f не является функцией, по-хорошему мы должны выбросить исключение. А исключение throw не может быть выброшено в контексте выражения. Можно подождать throw expressions (stage 2) и попробовать еще раз. Или у кого-то уже сейчас есть мысли?


Можно сделать через eval:

const a = { count: 5, getCount(b) { return this.count + b} };
const b = { count: 10 };

const bind = (f, ctx, ...a) => (...args) =>
  typeof f === 'function'
    ? f.apply(ctx, a.concat(args))
    : eval(`throw new Error("This isn't function")`);

const getCountB = bind(a.count, b);

console.log(a.getCount(5));
console.log(getCountB(5));
Вот еще решение на основе параметров

Я даже не подумал об этом! Круто )


Можно сделать через eval

Вот оно уже настоящее зло )

Может так зла будет меньше заменяя eval на Function

const bind = (f, ctx, ...a) => (...args) =>
  typeof f === 'function'
    ? f.apply(ctx, a.concat(args))
    : new Function`throw new Error("This isn't function")`;
Ну, главное чтобы это Крокфорд не увидел )
Главное не использовать это в продакшине, а то от Крокфорда последствия неизвестные, но тим-лид может и настучать по голове за такой код )))
не, обычно тест на такой код записать просят. После пары тройки раз, чувак смекает в чем причина. И вроде как ты добрый и правильную дорогу указал, без насилия. гибче быть нужно.

Если гнаться за минимизацией, и опустить условие о приватном счетчике (которого в постановке задачи все равно не было), можно сделать вот так:


m=(f,t)=>t=(...a)=>t[t.c=t.c+1||1]=f(...a)

В результате получается круглое число символов и бонусом запоминаем результаты всех вызовов.
Проверить можно так:


var log=m((...a) => (console.log(...a), a[0]))
log(1,2,3,4)
log(5,6,7)
log(8,9)
console.log('got', log.c, 'calls')
Ну это уже какая-то смесь одной задачи с другой… в этой все таки хотелось сделать почище. Спасибо за интерес )
Издеваетесь, вот, думать людей заставляете…
const func = (f) => ( o = (...a) => (o.count++, f(...a)), o.count = 0 , o )
Нее, так нельзя ) счетчик должен остаться приватным.
Както очень долго над первым решением думал. Нужно больше практитки.
В условии не написано про приватность.
Можно к передаваемой функции прицепить атрибут. Некрасиво, но работает.
const func = (f) => ( f.count = 0 , o = (...a) => (f.count++, console.log(f.count), f(...a)), o.getCount = () => f.count, o )

А в чем собственно разница? Мы все равно можем поменять значение f.count напрямую, а потом дергать func.getCount неправильно. Надумано? но если декорировать одну и ту же функцию дважды, то аукнется факт использования исходной функции в качестве хранилища счетчика: он обнулится. Модифицировать переданную функцию считаю не лучшей практикой:


const sum = (x, y) => x + y;
let f1 = func(sum);
f1(1, 2); // 3
f1.getCount(); // 1
let f2 = func(sum);
f1.getCount(); // 0 ?

Для обеспечения приватности нам необходимо использовать для замыкания локальную переменную в теле декорирующей функции.

Упс… да, при повторном декорировании сломается. И count будет «приватным» только для анонимной функции. Я же говорю — издеваетесь)
Не то, чтобы специально! но даже в ненормальном программирование можно следовать нормальным практикам ) по возможности!
Sign up to leave a comment.

Articles