Overloading в JavaScript
Привет!
Существует в JS методика или какой-нибудь хак, позволяющий перехватывать и корректно обрабатывать запросы к несуществующим методам? Как пример, метод __call в PHP5. |
try/catch ?
|
ZoNT,
Предполагается, что это "забота" не того кто будет делать вызов, а того кто создал объект. При таком вызове мне надо получить имя запрашиваемого метода и переданные аргументы. |
Как вариант, меня еще устроило-бы такое решение: если-бы с помощью "caller" можно было получить ссылку не только на вызывающую функцию но и на объект содержащий этот метод. В этом случае в прототипе можно произвести какие-либо вспомогательные действия (определить какие-то свойства и т.п.).
Но в последнем случае обязательно надо учитывать что на основе этого прототипа будет создано много объектов. У меня получилось создать ссылку только на последний объект, а на "текущий" - никак... :( P.S. В идеале хотелось бы обе методики иметь в арсенале "Overloading" и "caller" со ссылкой на объект. |
в общем, я так и не понял, что тебе надо...
|
no_alex, на данный момент такой функционал есть только у FF. Метод называется __noSuchMethod__ (это именно аналог __call из PHP и method_missing из Ruby).
В остальный случаях: либо проверка через in - if ('method' in object) {...}, либо try {...} catch () {...}. |
Dmitry A. Soshnikov,
Цитата:
Цитата:
Попробую еще раз пояснить что мне надо во втором случае. Есть некий объект (A) у которого будут вызываться различные методы. И есть серия объектов (B1, B2, B3,...) которые будут обращаться к методам A. У B1, B2, B3,... общий прототип (P). В прототипе P или в конструкторе, при создании объекта, я могу создать что-либо, что позволит потом получить ссылку на этот объект. Теперь сама задача: когда B1, B2, B3,... обращается к методам A в этих методах я могу обратиться к "caller", но при этом я получаю ссылку на саму функцию прототипа P. А мне еще надо получить ссылку на объект у которого она была вызвана. Пока объект B1 существует в единственном экземпляре проблем нет - я его цепляю к прототипу и потом легко получаю, но как только появляется B2, B3,... уже достучаться до текущего объекта не получается. |
Цитата:
|
попробуйте поигратся с 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() |
Kolyaj,
что такое паттерн делегатор? |
|
спасибо.
щаз почитаю |
Gvozd,
Цитата:
Но я не совсем это имел в виду |
no_alex,
так вам мой код подходит, или как? или я вас неправильно понял? |
Gvozd,
Цитата:
У меня как раз цель отказаться от передачи this через аргументы. Я хочу упростить вызов этих методов. С this в аргументах я эту задачу уже решил, но слишком часто приходится писать этот this и хочется эту проблему упростить. Второе, вызовов типа: A.func2.apply(this,[]) у меня не будет. Все методы вызываются у "своих" объектов. И третье, созданные объекты совершенно не обязательно являются свойствами объекта "windows". Мне не известно где они будут располагаться. |
Цитата:
Цитата:
если объект B1 юудет находится в любом другом месте, то в коде ничего не поменяется кроме того, что это сравнение в таком виде будет false выдавать. но this/that все равно будет указывать именно на него, где бы он не был |
Цитата:
В целом идею Вы поняли правильно, только вот если-бы реализовать ее "на автомате". Чтобы this не передавать, а определять автоматически. Цитата:
|
п кажется я понял, что вы хотите теперь:
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() |
Цитата:
всего лиш 13 лишних символов в ввашем коде? |
вот в таком варианте функции ничего лишнего не передается, и не используется 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() |
Нет, у меня цель немного другая.
Грубо говоря объект A сейчас создается один раз и затраты на его создание сейчас большого значения не имеют. А вот объекты типа B будут создаваться регулярно и затраты на их создание мне надо максимально уменьшить. Т.е. минимализировать количество процедур в объекте B и аргументов передаваемых в объект A. Т.е. надо усложнять объект A, для того чтобы максимально упростить вызов его методов из объектов B. Так-же не будет проблемой если мы усложним конструктор объекта B. В конце концов, можно добавить какие-то вспомогательные методы в прототип P, через которые я буду оброащаться к объекту A. Но это решение мне уже не нравится, т.к. будет вызывать путаницу. В этом случае уже лучше будет заставлять передавать this, через аргументы. И в последнем примере у Вас опять this внутри метода объекта A содержит ссылку на "чужой" объект. Меня это решение не устраивает. |
чем вам вариант сделать A прототипом объектов B не подходит?
если вам нужен самостоятельный прототип у объектов B, то тогда делаем P прототипом объектов B, а A в свою очередь пусть будет прототипом объекта P |
Увы, все не так просто...
Я чуть позже напишу пример того как я пытался решить эту задачу. Но тот пример будет не рабочий. В нем каждый повторный созданный объект затирает предыдущий. Но возможно Вы подскажете как можно в моем примере эту проблему "разрулить". Если не возражаете, давайте прервем это обсуждение на пару часиков, или, если удобно - до завтра. |
no_alex,
та мне-то удобно вообще не решать вашу проблему:wacko: жду вашего примера. обсудим-попробуем когда вам удобно, тогда и выкладывайте |
Цитата:
Всё-таки, у doesNotUnderstand (Smalltalk), method_missing (Ruby) / __call (PHP), __noSuchMethod__ (JS in Firefox) и т.д. другая цель - выставить последнюю "точку обороны", когда объект (просмотрев всю цепь наследования) не может ответить на сообщение (точно так же, как будто мы открыли неправильный URL - браузер же, всё-таки, отреагировал, выдав нам соотвествующее сообщение). А делегировать или нет в этом методе к другим объектам - это дело десятое. |
Цитата:
|
Цитата:
В любом случае, __noSuchMethod__ (и иже с ними) тут не при чём (паттерна "Делегатор" это может коснуться только косвенно, т.к. объект может и не делегировать ни к кому, а выполнить какой-нибудь свой другой метод). |
Цитата:
|
Цитата:
Цитата:
Цитата:
var a = { __noSuchMethod__: function (id, args) { alert('Called: ' + id + ', args: ' + args); } }; a.test(); a.test2(1, 2, 3); |
Цитата:
|
Цитата:
P.S.:> ладно, главное, что теперь (надеюсь) нет путаницы с паттерном "Делегатор", "механизмом делегирования в JS" и "обработкой ситуации с неопознанным методом". |
Цитата:
Цитата:
|
Цитата:
|
Kolyaj, Dmitry A. Soshnikov,
Что-то я не пойму суть вашего спора. Вроде-бы говорите об одном и том-же, но при этом продолжаете спорить. :) Будем считать, что "Overloading" разобрались. Для JS эта фича существует только в FF. Возможно существует какой-то хак, который позволяет эту проблему решить кроссбраузерно. Если да, то надеюсь, мы здесь это услышим. Kolyaj, респект. Вы очень точно угадали мои цели: Цитата:
Что же касается второй задачи, которую я поднял в этой теме. Я уже сильно жалею что смешал эти два разных вопроса в одной теме. Приношу свои извинения! Просто для меня это две части одной задачи. И для меня решение хотя-бы одной из этих задач, было-бы достаточным. Чтобы избежать дальнейшей путаницы, для второго вопроса я открыл другую тему: http://javascript.ru/forum/misc/3120...jj-caller.html . Gvozd, надеюсь Вам не влом будет продолжать это обсуждение? ;) |
Цитата:
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',[]); |
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!']); Не думаю, что это решение многим понравится. |
Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 10:01. |