Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Получить объект содержащий caller (https://javascript.ru/forum/misc/3120-poluchit-obekt-soderzhashhijj-caller.html)

no_alex 19.03.2009 23:21

Получить объект содержащий caller
 
Данная тема создана с целью разделить два вопроса смешанных в одной теме здесь:
http://javascript.ru/forum/misc/3116...ascript-2.html

Вкратце повторю суть задачи.

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

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

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


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

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


Теперь пример "не рабочего" кода, который я обещал привести:
var A = {
    t : function()
    {
        var this_func = arguments.callee; // Ссылка на текущую функцию
        var caller = this_func.caller; // Ссылка на вызывающую функцию (в данном случае я получаю ссылку на свойство из прототипа)
        var that = caller.ref // Попытка получить ссылку на объект из которого произошел вызов
        alert(that.x);
    }
}

var B = function(x)
{
	this.x = x; // Сохраняю свойство, для тестирования
	this.z.ref = this; // Пытаюсь сохранить ссылку на текущий объект, чтобы потом его получить. Но поскольку this.z фактически является свойством прототипа, это свойство потом презапишется
}
B.prototype = {
	x : "",
	z : function()
	{
		A.t();
	}
}


var B1 = new B("LALA1");
B1.z();
var B2 = new B("LALA2");
B2.z();


Ключевые моменты в коде я прокомментировал.

Если запустить код, том виде как я привел - вроде-бы все работает как надо. Мы получим, как и ожидаем два алерта: "LALA1" и "LALA2".

Но если изменить финальную часть этого кода, например так:
var B1 = new B("LALA1");
var B2 = new B("LALA2");
B1.z();
B2.z();

то все работает не правильно. Оба алерта будут "LALA2".

Хотелось бы получить что-либо подобное, но правильно работающее. ;)

Gvozd 19.03.2009 23:44

хоть убейте до сих пор не пойму чем вам apply не подходит:
var A = {
    t : function()
    {
        alert(this.x);
    }
}
 
B = function(x)
{
    this.x = x; // Сохраняю свойство, для тестирования
}
B.prototype = {
    x : "",
    z : function()
    {
        A.t.apply(this);
    }
}
 
 
B1 = new B("LALA1");
B2 = new B("LALA2");
B1.z();
B2.z();

no_alex 20.03.2009 00:00

Цитата:

хоть убейте до сих пор не пойму чем вам apply не подходит
Потому что метод t() на самом деле очень сложный и мне надо в нем через this обращаться к другим свойствам объекта A.

Ну и вторая цель - вызовы из B1, мне надо сделать максимально простыми.
Сейчас я делаю примерно так:
var A = {
    t : function(that)
    {
        alert(that.x);
    }
}
 
B = function(x)
{
    this.x = x; // Сохраняю свойство, для тестирования
}
B.prototype = {
    x : "",
    z : function()
    {
        A.t(this);
    }
}
 
 
B1 = new B("LALA1");
B2 = new B("LALA2");
B1.z();
B2.z();

и потом получаю ссылку на текущий объект как аргумент метода t(). По сути, это даже проще, чем то что Вы предлагаете.

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

Gvozd 20.03.2009 00:19

Цитата:

Сообщение от no_alex
Но мне сейчас очень хочется отказаться от этого аргумента, если получиться до него "достучаться" каким-либо другим способом.

почему?он вам сильно мозолит глаза?
или вы считаете что так будет медленнее?мне кажется навряд ли медленне, хотя не уверен

no_alex 20.03.2009 00:30

Gvozd,
Ну я же объяснил свои цели в начале:
Цитата:

Объект A сейчас создается один раз и затраты на его создание сейчас большого значения не имеют. А вот объекты типа B будут создаваться регулярно и затраты на их создание мне надо максимально уменьшить. Т.е. минимализировать количество процедур в объекте B и аргументов передаваемых в объект A.
Можно еще так сказать: Объект A сейчас создаю я. А вот объекты B1, B2, B3,... потом будут создавать другие люди. И у меня сейчас цель облегчить другим жизнь. ;)
Но при этом сделать это так, чтобы это не вызвало путаницы.

Gvozd 20.03.2009 00:43

То есть усложнять конструктор B() и прототип создаваемых объектов нельзя?
ну, тогда не знаю как решить вашу задачу

no_alex 20.03.2009 00:57

Цитата:

То есть усложнять конструктор B() и прототип создаваемых объектов нельзя?
Конструктор усложнять можно. Там, на самом деле, конструктор будет только мой.
В прототипе так же можно создать какие-то вспомогательные методы, но только для того чтобы эти методы вызывались сами в какой-то момент. Чтобы тому кто будет писать B1, B2, B3,... не пришлось специально вызывать эти методы, иначе это будет сложнее чем передавать this через аргументы.

Gvozd 20.03.2009 01:09

я правильно понимаю:
var A = {
    t : function(that)
    {
        alert(that.x);
    }
}
 
B = function(x)
{
    this.x = x; // Сохраняю свойство, для тестирования
}
B.prototype = {
    x : "",
    z : function()
    {
        A.t(this);
    }
}
//выше находится ваш код.там творим, все что нам надо
//ниже код других людей.тут надо сделать чтобы все было максимально просто и прозрачно
 
B1 = new B("LALA1");
B2 = new B("LALA2");
B1.z();
B2.z();

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

no_alex 20.03.2009 01:34

ok.
Вот так примерно работает тот скрипт, что у меня есть:
var A = {
    t : function(that)
    {
        alert(that.x);
    }
}
 
var B = function()
{
    this.tttt = 123; // Делаю что-то свое
    if(this.__constructor !== undefined && this.__constructor.constructor == Function) {
        this.__constructor.apply(this, arguments); // Вызываю "кастомерский" конструктор
    }
}
B.prototype = {
    some_special_method : function()
    {
    },
//выше находится наш код. Там творим, все что нам надо
//ниже код других людей. Тут надо сделать чтобы все было максимально просто и прозрачно
    x : "",
    __constructor : function(x) // Конструктор других людей
    {
        this.x = x; // Сохраняю свойство, для тестирования
    },
    z : function()
    {
        A.t(this);
    }
}
 
B1 = new B("LALA1");
B2 = new B("LALA2");
B1.z();
B2.z();


Теперь еще раз, с Вашего позволения, повторю задачу (для тех, кто возможно, не внимательно следил за нашим диалогом, но хочет сейчас к нему подключится).
Надо в этой строчке:
A.t(this);

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

Gvozd 20.03.2009 01:51

так подойдет?
var A = {
    t : function()
    {
        alert(this.x);
    }
}
 
B = function(qwe)
{
    this.x = qwe; // Делаю что-то свое
    if(this.__constructor !== undefined && this.__constructor == Function) {
        this.__constructor.apply(this, arguments);
    }
}

//конструкция, добавляющая A в верхнюю часть прототипирования
B_proto_constr=function(){}
B_proto_constr.prototype=A
B.prototype=new B_proto_constr()
//конструкция, добавляющая A в верхнюю часть прототипирования

    B.prototype.some_special_method = function()
    {
    };
//выше находится наш код. Там творим, все что нам надо
//ниже код других людей. Тут надо сделать чтобы все было максимально просто и прозрачно
    B.prototype.x = "",
    B.prototype.__constructor = function() // Конструктор других людей
    {
    };
    B.prototype.z = function()
    {
        this.t();//вынесли this из параметров.но приписали вначале))
    }
 
B1 = new B("LALA1");
B2 = new B("LALA2");
B1.z();
B2.z();

я решил добавить A в качестве прототипа прототипа объектов B


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