Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Overloading в JavaScript (https://javascript.ru/forum/misc/3116-overloading-v-javascript.html)

no_alex 19.03.2009 15:49

Overloading в JavaScript
 
Привет!
Существует в JS методика или какой-нибудь хак, позволяющий перехватывать и корректно обрабатывать запросы к несуществующим методам?

Как пример, метод __call в PHP5.

ZoNT 19.03.2009 16:08

try/catch ?

no_alex 19.03.2009 16:13

ZoNT,
Предполагается, что это "забота" не того кто будет делать вызов, а того кто создал объект. При таком вызове мне надо получить имя запрашиваемого метода и переданные аргументы.

no_alex 19.03.2009 16:29

Как вариант, меня еще устроило-бы такое решение: если-бы с помощью "caller" можно было получить ссылку не только на вызывающую функцию но и на объект содержащий этот метод. В этом случае в прототипе можно произвести какие-либо вспомогательные действия (определить какие-то свойства и т.п.).
Но в последнем случае обязательно надо учитывать что на основе этого прототипа будет создано много объектов. У меня получилось создать ссылку только на последний объект, а на "текущий" - никак... :(

P.S. В идеале хотелось бы обе методики иметь в арсенале "Overloading" и "caller" со ссылкой на объект.

ZoNT 19.03.2009 16:44

в общем, я так и не понял, что тебе надо...

Dmitry A. Soshnikov 19.03.2009 16:49

no_alex, на данный момент такой функционал есть только у FF. Метод называется __noSuchMethod__ (это именно аналог __call из PHP и method_missing из Ruby).

В остальный случаях: либо проверка через in - if ('method' in object) {...}, либо try {...} catch () {...}.

no_alex 19.03.2009 17:14

Dmitry A. Soshnikov,
Цитата:

на данный момент такой функционал есть только у FF
Жаль, жаль... Мне надо кроссбраузерное решение. :(

Цитата:

либо проверка через in - if ('method' in object) {...}
У меня проблема именно "поймать" этот объект.



Попробую еще раз пояснить что мне надо во втором случае.

Есть некий объект (A) у которого будут вызываться различные методы. И есть серия объектов (B1, B2, B3,...) которые будут обращаться к методам A.
У B1, B2, B3,... общий прототип (P). В прототипе P или в конструкторе, при создании объекта, я могу создать что-либо, что позволит потом получить ссылку на этот объект.

Теперь сама задача: когда B1, B2, B3,... обращается к методам A в этих методах я могу обратиться к "caller", но при этом я получаю ссылку на саму функцию прототипа P. А мне еще надо получить ссылку на объект у которого она была вызвана.

Пока объект B1 существует в единственном экземпляре проблем нет - я его цепляю к прототипу и потом легко получаю, но как только появляется B2, B3,... уже достучаться до текущего объекта не получается.

Kolyaj 19.03.2009 17:28

Цитата:

Сообщение от ZoNT
в общем, я так и не понял, что тебе надо

Ему нужно реализовать паттерн делегатор. Если бы его можно было в js реализовать, я бы бед не знал :)

Gvozd 19.03.2009 17:34

попробуйте поигратся с this-ом
если я правильно понял вашу задачу, то вот два варианта решения:
A=
	{
	'func':function(that)
		{
		console.log(['func',that==window.B1])//TRUE.that указывает на B1, вызвавший функцию
		},
	'func2':function()
		{
		console.log(['func2',this==window.B1])//TRUE.this указывает на B1, вызвавший функцию
		}
	}

B_proto=
	{
	'function':function()
		{
		console.log([this,this==window.B1,this==window.B2])//this указывает на B1, вызвавший функцию
		A.func(this)
		A.func2.apply(this,[])
		}
	}
function B()
	{
	//functio
	}
B.prototype=B_proto;

B1=new B();
B2=new B();
B1.function()

Gvozd 19.03.2009 17:35

Kolyaj,
что такое паттерн делегатор?

Kolyaj 19.03.2009 17:45

http://ru.wikipedia.org/wiki/%D0%A8%...BD%D0%B8%D1%8F

Gvozd 19.03.2009 17:46

спасибо.
щаз почитаю

no_alex 19.03.2009 17:51

Gvozd,
Цитата:

что такое паттерн делегатор?
http://ru.wikipedia.org/wiki/%D0%A8%...BD%D0%B8%D1%8F
Но я не совсем это имел в виду

Gvozd 19.03.2009 18:01

no_alex,
так вам мой код подходит, или как?
или я вас неправильно понял?

no_alex 19.03.2009 18:06

Gvozd,
Цитата:

если я правильно понял вашу задачу, то вот два варианта решения:
Не совсем правильно...
У меня как раз цель отказаться от передачи this через аргументы. Я хочу упростить вызов этих методов. С this в аргументах я эту задачу уже решил, но слишком часто приходится писать этот this и хочется эту проблему упростить.

Второе, вызовов типа:
A.func2.apply(this,[])

у меня не будет. Все методы вызываются у "своих" объектов.

И третье, созданные объекты совершенно не обязательно являются свойствами объекта "windows". Мне не известно где они будут располагаться.

Gvozd 19.03.2009 18:13

Цитата:

Сообщение от no_alex
Второе, вызовов, типа:
A.func2.apply(this,[])
у меня не будет все методы вызываются у "своих" объектов.

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

Цитата:

Сообщение от no_alex
И третье, созданные объекты совершенно не обязательно являются свойствами объекта "windows". Мне не известно где они будут располагаться.

глупость сказали.я написал сравнение с window.B1 Только для того чтобы показать что объект this/that в каждом случае указывает именно на объект его вызвавший.
если объект B1 юудет находится в любом другом месте, то в коде ничего не поменяется кроме того, что это сравнение в таком виде будет false выдавать. но this/that все равно будет указывать именно на него, где бы он не был

no_alex 19.03.2009 18:18

Цитата:

я написал сравнение с window.B1
Сорри. Я понял - это чисто для проверки.

В целом идею Вы поняли правильно, только вот если-бы реализовать ее "на автомате". Чтобы this не передавать, а определять автоматически.

Цитата:

попробуйте выразить эту мысль по другому, потому что я вас не понимаю
В Вашем примере Вы вызываете метод обекта A, так чтобы this указывал на другой объект. Я таких вызавов не планирую. Во всех методах обекта A, this всегда должен указывать на объект A.

Gvozd 19.03.2009 18:20

п кажется я понял, что вы хотите теперь:
A=
	{
	'func':function(that)
		{
		//that указывает на объект, вызвавший функцию
		with(that)
			{
			alert(a)
			//тут переменная a является свойством a вызвавшего объекта
			}
		},
	'func2':function()
		{
		//this указывает на объект, вызвавший функцию
		with(this)
			{
			alert(b)
			//тут переменная a является свойством b вызвавшего объекта
			}
		}
	}

B_proto=
	{
	'function':function()
		{
		console.log([this,this==window.B1,this==window.B2])//this указывает на B1, вызвавший функцию
		A.func(this)
		A.func2.apply(this,[])
		}
	}
function B()
	{
	//functio
	this.a='qwerty';
	this.b='йцукен';
	}
B.prototype=B_proto;

B1=new B();
B1.function()

B2=new B();
B2.a='asdfgh'
B2.b='фывапр'
B2.function()

Gvozd 19.03.2009 18:21

Цитата:

Сообщение от no_alex
В целом идею Вы поняли правильно, только вот если-бы реализовать ее "на автомате". Чтобы this не передавать, а определять автоматически.

а чем вам метод с apply -то не годится.ю
всего лиш 13 лишних символов в ввашем коде?

Gvozd 19.03.2009 18:29

вот в таком варианте функции ничего лишнего не передается, и не используется apply
A=
	{
	'func':function()
		{
		// тут this указывает на вызвавший объект
		alert(this.a)
		with(this)
			{
			alert(a)
			}
		}
	}

B_proto=
	{
	'function':function()
		{
		this.func()
		},
	'func':A.func,
	}
function B()
	{
	//functio
	this.a='qwerty';
	}
B.prototype=B_proto;

B1=new B();
B1.function()

B2=new B();
B2.a='asdfgh'
B2.function()

no_alex 19.03.2009 18:54

Нет, у меня цель немного другая.
Грубо говоря объект A сейчас создается один раз и затраты на его создание сейчас большого значения не имеют. А вот объекты типа B будут создаваться регулярно и затраты на их создание мне надо максимально уменьшить. Т.е. минимализировать количество процедур в объекте B и аргументов передаваемых в объект A.

Т.е. надо усложнять объект A, для того чтобы максимально упростить вызов его методов из объектов B. Так-же не будет проблемой если мы усложним конструктор объекта B.

В конце концов, можно добавить какие-то вспомогательные методы в прототип P, через которые я буду оброащаться к объекту A. Но это решение мне уже не нравится, т.к. будет вызывать путаницу. В этом случае уже лучше будет заставлять передавать this, через аргументы.

И в последнем примере у Вас опять this внутри метода объекта A содержит ссылку на "чужой" объект. Меня это решение не устраивает.

Gvozd 19.03.2009 19:03

чем вам вариант сделать A прототипом объектов B не подходит?
если вам нужен самостоятельный прототип у объектов B, то тогда делаем P прототипом объектов B, а A в свою очередь пусть будет прототипом объекта P

no_alex 19.03.2009 19:12

Увы, все не так просто...

Я чуть позже напишу пример того как я пытался решить эту задачу. Но тот пример будет не рабочий. В нем каждый повторный созданный объект затирает предыдущий. Но возможно Вы подскажете как можно в моем примере эту проблему "разрулить".

Если не возражаете, давайте прервем это обсуждение на пару часиков, или, если удобно - до завтра.

Gvozd 19.03.2009 19:16

no_alex,
та мне-то удобно вообще не решать вашу проблему:wacko:
жду вашего примера. обсудим-попробуем
когда вам удобно, тогда и выкладывайте

Dmitry A. Soshnikov 19.03.2009 19:36

Цитата:

Сообщение от Kolyaj
Ему нужно реализовать паттерн делегатор. Если бы его можно было в js реализовать, я бы бед не знал

JS и так полностью пропитан делегированием. И реализовать именно паттерн "Делегатор" не преставляет труда (что мешает вызвать из a.test() b.test() ?).

Всё-таки, у doesNotUnderstand (Smalltalk), method_missing (Ruby) / __call (PHP), __noSuchMethod__ (JS in Firefox) и т.д. другая цель - выставить последнюю "точку обороны", когда объект (просмотрев всю цепь наследования) не может ответить на сообщение (точно так же, как будто мы открыли неправильный URL - браузер же, всё-таки, отреагировал, выдав нам соотвествующее сообщение). А делегировать или нет в этом методе к другим объектам - это дело десятое.

Kolyaj 19.03.2009 20:08

Цитата:

Сообщение от Dmitry A. Soshnikov
что мешает вызвать из a.test() b.test() ?

То, что test может быть любым.

Dmitry A. Soshnikov 19.03.2009 21:02

Цитата:

Сообщение от Kolyaj
То, что test может быть любым.

? Ниче не понял =) В паттерне "Делегатор" описывается метод, который вызывает (такой же) метод объекта-делегатора (который может меняться динамически).

В любом случае, __noSuchMethod__ (и иже с ними) тут не при чём (паттерна "Делегатор" это может коснуться только косвенно, т.к. объект может и не делегировать ни к кому, а выполнить какой-нибудь свой другой метод).

Kolyaj 19.03.2009 21:20

Цитата:

Сообщение от Dmitry A. Soshnikov
Ниче не понял =) В паттерне "Делегатор" описывается метод, который вызывает (такой же) метод объекта-делегатора (который может меняться динамически).

И все прекрасно, пока мы знаем имена всех методов, которые могут быть вызваны. Есть у нас допустим объект А, и мы хотим создать для него делегатор Б, который будет как-то изменять вызов некоторого множества методов, а остальные методы должны остаться без изменений. Например, обертка для DOM-узла, которая определяет свои методы, а родные, точнее неопределенные в ней, делегирует DOM-элементу. Такое нереально написать в JS, т.к. руками все методы переписывать нереально и нецелесообразно, а метода а-ля __call нет.

Dmitry A. Soshnikov 19.03.2009 21:25

Цитата:

Сообщение от Kolyaj
И все прекрасно, пока мы знаем имена всех методов

Это и есть паттерн "Делегатор".

Цитата:

Сообщение от Kolyaj
__call

А это - обработка события, когда объект не может ответить на сообщение (и как очень частный случай здесь может быть делегация).

Цитата:

Сообщение от Kolyaj
Такое нереально написать в JS

Еще раз - под FF - пожалуйста:

var a = {
  __noSuchMethod__: function (id, args) {
    alert('Called: ' + id + ', args: ' + args);
  }
};

a.test();
a.test2(1, 2, 3);

Kolyaj 19.03.2009 21:54

Цитата:

Сообщение от Dmitry A. Soshnikov
Еще раз - под FF - пожалуйста:

Написать на JS === должно работать везде, где есть JS.

Dmitry A. Soshnikov 19.03.2009 22:01

Цитата:

Сообщение от Kolyaj
Написать на JS === должно работать везде, где есть JS.

В принципе, если какая-то админская система, не обязательно.

P.S.:> ладно, главное, что теперь (надеюсь) нет путаницы с паттерном "Делегатор", "механизмом делегирования в JS" и "обработкой ситуации с неопознанным методом".

Kolyaj 19.03.2009 22:05

Цитата:

Сообщение от Dmitry A. Soshnikov
В принципе, если какая-то админская система, не обязательно.

Админку на ext'е быстрей и проще написать, а там ничего такого не надо.

Цитата:

Сообщение от Dmitry A. Soshnikov
ладно, главное, что теперь (надеюсь) нет путаницы с паттерном "Делегатор", "механизмом делегирования в JS" и "обработкой ситуации с неопознанным методом или еще нужно объяснить".

Мне, по большому счету, все равно, как что называется. :)

Dmitry A. Soshnikov 19.03.2009 22:06

Цитата:

Сообщение от Kolyaj
Мне, по большому счету, все равно, как что называется.

Главное, чтобы понимание было ;)

no_alex 19.03.2009 22:24

Kolyaj, Dmitry A. Soshnikov,
Что-то я не пойму суть вашего спора. Вроде-бы говорите об одном и том-же, но при этом продолжаете спорить. :)

Будем считать, что "Overloading" разобрались. Для JS эта фича существует только в FF. Возможно существует какой-то хак, который позволяет эту проблему решить кроссбраузерно. Если да, то надеюсь, мы здесь это услышим.


Kolyaj, респект.
Вы очень точно угадали мои цели:
Цитата:

Например, обертка для DOM-узла, которая определяет свои методы, а родные, точнее неопределенные в ней, делегирует DOM-элементу.



Что же касается второй задачи, которую я поднял в этой теме. Я уже сильно жалею что смешал эти два разных вопроса в одной теме. Приношу свои извинения!
Просто для меня это две части одной задачи. И для меня решение хотя-бы одной из этих задач, было-бы достаточным.
Чтобы избежать дальнейшей путаницы, для второго вопроса я открыл другую тему: http://javascript.ru/forum/misc/3120...jj-caller.html .
Gvozd, надеюсь Вам не влом будет продолжать это обсуждение? ;)

Gvozd 19.03.2009 23:22

Цитата:

Сообщение от no_alex
. Возможно существует какой-то хак, который позволяет эту эту проблему решить кроссбраузерно

есть идея.но она не сильна хороша:
a={
'call_function':function(name,param)
	{if(this[name]!==undefined&&this[name].constructor==Function)
		return this[name].apply(this,param)},
'func':function(){alert('sa')}
}
a.call_function('func',[]);

no_alex 20.03.2009 00:27

Gvozd, с Вашего позволения, я чуть-чуть изменю Ваш код, чтобы он был более читабельным:
var a = {
    'call_function' : function(name, param)
    {
        if(this[name] !== undefined && this[name].constructor == Function) {
            return this[name].apply(this, param);
        }
        return null;
    },
    'func' : function(p1)
    {
        alert(p1);
    }
}
a.call_function('func', ['ok!']);


То есть Вы подлагаете все вызовы делать, вместо классического способа:
a.func('ok!');

- таким способом:
a.call_function('func', ['ok!']);


Не думаю, что это решение многим понравится.

Dmitry A. Soshnikov 20.03.2009 01:12

Цитата:

Сообщение от no_alex
Что-то я не пойму суть вашего спора. Вроде-бы говорите об одном и том-же, но при этом продолжаете спорить.

Да мы не спорим, мы беседуем. А разговор был абсолютно про разное. Какой толк знать/понимать/называть неверно? А так, хоть расставились точки на ё ;)

Цитата:

Сообщение от no_alex
Возможно существует какой-то хак, который позволяет эту эту проблему решить кроссбраузерно.

Нет, к сожалению.


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