Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Пометить функцию атрибутом (https://javascript.ru/forum/misc/68389-pometit-funkciyu-atributom.html)

Tranquill 13.04.2017 14:50

Пометить функцию атрибутом
 
Привет всем!

Можно ли в JavaScript'е как-то пометить функцию, например чем-то вроде атрибута, чтобы потом можно было ее найти рефлексией?
Хочется иметь возможность в рантайме обнаруживать определенные функции. Например так

var obj = { 
  f1: function() { return 1; }, 
  f2: function() { return 2; }, // Хочу найти только это функцию, а не все три
  g1: function() { return 3; }
  h1: 'not a function'   
}

for ( var key in obj ) { 
  if (    obj.hasOwnProperty( key )
       && typeof( obj[key] ) == 'function' 
    // && ??
      ) {
    console.log( 'Special function found: %s', key );
  }
}


Спасибо.

ksa 13.04.2017 16:10

Цитата:

Сообщение от Tranquill
Можно ли в JavaScript'е как-то пометить функцию, например чем-то вроде атрибута

Функция так же является объектом - значит может иметь атрибуты. :yes:

ksa 13.04.2017 16:40

Цитата:

Сообщение от Tranquill
Можно ли в JavaScript'е как-то пометить функцию

Как вариант...

var obj = { 
	f1: function() { return 1; }, 
	// Хочу найти только это функцию, а не все три
	f2: function() { return 2; }, 
	g1: function() { return 3; },
	h1: 'not a function'   
};
obj.f2.test=true;
for ( var key in obj ) { 
	if (    obj.hasOwnProperty( key )
		&& typeof( obj[key] ) == 'function' 
		&& obj[key].test
	) {
		alert( 'Special function found: %s '+ key );
	};
};

Tranquill 13.04.2017 16:55

Цитата:

Сообщение от ksa (Сообщение 449958)
Как вариант...

var obj = { 
	f1: function() { return 1; }, 
	// Хочу найти только это функцию, а не все три
	f2: function() { return 2; }, 
	g1: function() { return 3; },
	h1: 'not a function'   
};
obj.f2.test=true;
for ( var key in obj ) { 
	if (    obj.hasOwnProperty( key )
		&& typeof( obj[key] ) == 'function' 
		&& obj[key].test
	) {
		alert( 'Special function found: %s '+ key );
	};
};

Уже думал о таком варианте, но тут плохо то, что нет локальности.
То есть функция в одном месте объявляется, а помечается где-то в другом.
Такое трудно поддерживать будет. Может как-то по-другому можно?

SV0L0CH 13.04.2017 18:08

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

Tranquill 13.04.2017 18:25

Цитата:

Сообщение от SV0L0CH (Сообщение 449965)
Переменной содержащей функцию можно присвоить другую функцию, в том числе полученную из предыдущей. Собственно, так и можно менять поведение функций.

Это верное утверждение, но не отвечающее на мой вопрос. Менять поведение не нужно, а требуется как-то отличать одни функции объекта от других.

SV0L0CH 13.04.2017 18:44

Цитата:

Сообщение от Tranquill
требуется как-то отличать одни функции объекта от других

Они и отличаются друг от друга... именем... Хотя функции объектов (методы) по способу вызова отличаются от отдельных функций.
Если надо параметризировать просто функции, то можно воспользоваться параметром this, а так же стандартным набором: Function.prototype.call , Function.prtotype.apply , Function.prototype.bind
Кроме this поведение функции можно привязать к любому другому конкретному объекту, в том числе и к самой функции, как и рекомендовалось выше.

Tranquill 13.04.2017 21:10

SV0L0CH,
Так и просится сказать "я ему про Фому, а он мне про Ерёму".

Попробую с другой стороны объяснить. Если взять, скажем, код на дотнете или на джаве, то там есть такое понятие как атрибуты. Атрибут можно создать самому, и потом любой метод класса пометить этим самым атрибутом. Далее, есть рефлексия, которая, среди прочего, позволяет программно итерировать по множеству методов класса и определять задан ли такой-то атрибут для такого-то метода. И таким образом программист имеет возможность выделить в классе подмножество методов и потом что-то с ним сделать.
Прошу обратить внимание на локальность этого процесса. Пометка атрибутом происходит точно в том месте, где метод объявляется. Это принципиально отличается от предложенного выше способа, при котором мне надо где-то отдельно в коде писать obj.myFunction.isSpecial = true; Как минимум отличается тем, что имя помеченной функции упоминается в коде дважды - в месте её определения и в месте, где ее помечают. Дублирование злейший враг сопровождаемости кода, и мне этот способ не подходит.

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

SV0L0CH 13.04.2017 22:26

Tranquill, Если нужен синтаксический сахар, то можно разработать собственный язык с трансляцией в JavaScript. Это вполне нормально, я сам пишу на CoffeeScript.
Кроме того, для подобных нужд можно обойтись и библиотекой, хотя выглядеть это будет недостаточно наглядно и читаемо.
В нативном варианте подобных извращений не предусмотрено.

Tranquill 13.04.2017 22:33

SV0L0CH,
Ну что не предусмотрено, то я не так уж уверен в этом. Например можно попробовать получить тело функции, посмотреть на ее первую строчку и попробовать найти в ней специальным образом отформатированный комментарий. Это конечно хак, но может будет работать. Мне достаточно чтобы работало в хроме и ие в силу специфики продукта.
Просто может я какой-то более прямой способ не замечаю.

А что за библиотеку вы имели в виду?

ksa 13.04.2017 22:56

Цитата:

Сообщение от Tranquill
Может как-то по-другому можно?

В случае с безымянной функцией, никак ничего к ней не присобачить... :no:

Цитата:

Сообщение от Tranquill
получить тело функции, посмотреть на ее первую строчку и попробовать найти в ней специальным образом отформатированный комментарий

Такое вполне работоспособно. :yes:
Метод toString() применим к функциям.

SV0L0CH 13.04.2017 23:09

Tranquill, Не у всех функций можно получить тело. Тело недоступно для родных функций и функций полученных через bind , так что вариант сразу можно отметать.
Ну а чтобы не разделять код, на секции из методов и их атрибутов(полей), можно воспользоваться самописной утилитой наследования, в которой вместо мтетодов задаётся объект с самим методом и набором полей поумолчанию. Подобное извращение я видел в ExtJS, так что можно посмотреть в качестве примера. Только там поля методов не использовались, кроме name .
Как что смело можно начинать сочинять костыль реализующий эту задумку и оформить его в виде отдельной JS библиотеки.
Так же напоминаю, что arguments.callee хоть и поддерживается, но не рекомендуется, так как считается устаревшим, и надо это учесть.

Tranquill 13.04.2017 23:23

Похоже я забыл сказать, что методы, которые хочется помечать, полностью под моим контролем. Виноват-с :)
Речь не идет о том, что объект приходит откуда-то извне и я пытаюсь работать с его методами. Напротив, объект мой и методы тоже мои. То есть проблемы с нативными функциями и bind нет.

Malleys 09.06.2017 22:47

Цитата:

Сообщение от Tranquill (Сообщение 449960)
Уже думал о таком варианте, но тут плохо то, что нет локальности.
То есть функция в одном месте объявляется, а помечается где-то в другом.
Такое трудно поддерживать будет. Может как-то по-другому можно?

var obj = { 
  f1: function() { return 1; }, 
  f2: (function(f) { f[Symbol.for("My Favorite Function")] = true; return f; })(function() { return 2; }),
  g1: function() { return 3; },
  h1: 'not a function'   
};

for (var key in obj) { 
  if (    obj.hasOwnProperty(key)
       && typeof(obj[key]) == 'function' 
       && Symbol.for("My Favorite Function") in obj[key]
      ) {
    console.log('Special function found: %s', obj[key]);
  }
}

MallSerg 11.06.2017 15:43

Еще одного человека покусал сишарп и он стал недееспособен как кодер. Сишарп калечит разработчиков ((.

нет нужды в Symbol.for(он предназначен для других задач) проще просто добавить атрибут к анонимной функции а потом проверять его

такой код до ужаса кривой и неправильный тут плохо все )).

var obj = {
  f1: function() { return 1; },
  f2: ( (f)=> { return f.atr=true , f ;})(function() { return 2; }), 
  g1: function() { return 3; },
  h1: 'not a function'  
};
 
for (var key in obj) {
  if (    obj.hasOwnProperty(key)
       && typeof(obj[key]) == 'function'
       && obj[key].atr == true
      ) {
      alert ( 'Special function found: %s  == ' +key +" -> "+ obj[key] );
    //console.log('Special function found: %s', obj[key]);
  }
}


Часовой пояс GMT +3, время: 13:49.