Получение ссылки this для функции-прототипа 2-го уровня - PullRequest
3 голосов
/ 27 мая 2011

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

Я хочу, чтобы следующий код работал:

var x = new foo();
x.a.getThis() === x; // true

Другими словами, я хочу, чтобы x.a.getThis имел ссылку на this, являющуюся x в этом случае. Имеет смысл?

Чтобы заставить это работать один глубокий уровень прост:

function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true

Во-первых, я хочу, чтобы это работало в качестве прототипа, без "обмана" путем ручной привязки к this:

function foo(){
    this.a = {
        getThis : (function(){ return this; }).bind(this)
    };
}

Хотя вышеприведенный пример является идеальным функциональным примером того, чего я пытаюсь достичь, я просто не хочу, чтобы все дополнительные функции использовались для каждого экземпляра:)

К вашему сведению, фактический вариант использования здесь заключается в том, что я создаю классы для представления объектов Cassandra в узле, и я хочу иметь возможность ссылаться на супер-столбец -> столбец-семейство -> столбец через foo.a.b и сохраните ссылку на foo в глубокой функции.

Ответы [ 3 ]

3 голосов
/ 27 мая 2011

Вы не можете сделать это без какого-либо принудительного связывания.Вы говорите, что не хотите "обманывать", но это нарушает стандартные правила о том, что такое this, поэтому вам придется обманывать.Но JS позволяет вам обманывать, так что все хорошо.

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


Или, если значение не обязательно должно this, вы можете установить «владельца» в дочернем объекте.

var A = function(owner) {
  this.owner = owner;
};
A.prototype.getThis = function() {
  return this.owner;
};
var Foo = function() {
  this.a = new A(this);
};

var foo = new Foo();

if (foo.a.getThis() === foo) {
    alert('Happy dance');
} else {
    window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}

http://jsfiddle.net/4GQPa/

И версия сценария кофе этого, потому что я страстный и необоснованный фанат этого:

class A
  constructor: (@owner) ->
  getThis: -> @owner

class Foo
  constructor: -> @a = new A(this)

foo = new Foo()
if foo.a.getThis() is foo
  alert 'Happy Dance'
else
  window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
0 голосов
/ 27 мая 2011

Отвечая на мой собственный вопрос, потому что кто-то другой может найти его полезным.Не уверен, что в конечном итоге я пойду с этим или решением Скиджи.Функции определяются только один раз, а затем содержащийся объект клонируется и в него вставляется parent = this:

function foo(){
    var self = this, nest = this.__nestedObjects__ || [];

    nest.forEach(function(prop){
        self[prop] = extend({ parent : self }, self[prop]);
    });
}

// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
    bar : {
        enumerable : true,
        value : {
            foobar : function(){
                return this.parent;
            },
            foo : function(){},
            bar : function(){}
        }
    },
    __nestedObjects__ : { value : ['bar'] }
});

var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);

или на основе решения Squeegy:

function foo(){
    for(var cls in this.__inherit__){
        if(!this.__inherit__.hasOwnProperty(cls)){ continue; }

        this[cls] = new (this.__inherit__[cls])(this);
    }
}

var clsA;
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
    __inherit__ : { value : {
        bar : clsA = function(parent){
                Object.defineProperty(this, '__parent__', { value : parent });
            }
        }
    }
});

clsA.prototype = {
    foobar : function(){
        return this.__parent__;
    }
};

var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
0 голосов
/ 27 мая 2011

Невозможно сделать надежно без привязки значения в начале, так как значение this функции устанавливается вызовом.Вы не можете знать заранее, как он будет вызываться, или каким функциям требуется специальный или ограниченный вызов для «сохранения» отношения this -> this .

Функция или вызывающая функция this может быть любым объектом, вообще не может быть this -> this .Рассмотрим:

var x = {
  a : {
    b: function() {return this;}
  }
}

Когда вы звоните x.a.b(), тогда b's this - это a.Но если вы сделаете:

var c = x.a.b;
c(); // *this* is the global object

или

x.a.b.call(someOtherObject);

Каково значение this -> this в этих случаях?

...