获得第二级原型函数的“this”引用

时间:2011-05-27 06:14:59

标签: javascript prototype-programming prototypal-inheritance

我相当肯定这是不可能的,但是想知道是否有人对如何使它成为可能有一些巧妙的想法。

我想要以下代码:

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

换句话说,在这种情况下,我希望x.a.getThis引用thisx。有意义吗?

为了让这个工作 一个 级别很简单:

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对象,我希望能够引用一个超级列 - > column-family - >通过foo.a.b列,并在深层函数中保留对foo的引用。

3 个答案:

答案 0 :(得分:3)

如果没有某种强制绑定,你就无法做到这一点。你说你不想“欺骗”,但这违反了this的标准规则,所以你必须作弊。但JS让你作弊,所以这一切都很好。

顺便说一下,咖啡脚本的价值使得这一点变得如此微不足道。

foo = ->
  @a = getThis: => this

胖箭头=>从它所调用的范围中保留了它的上下文。这使您可以轻松地将上下文转发到另一个级别。

该代码被编译到这个JS:

var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
  return this.a = {
    getThis: __bind(function() {
      return this;
    }, this)
  };
};

这基本上就是你说你不想做的事。


或者,如果值不具体为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'

答案 1 :(得分:0)

由于函数的 this 的值是由调用设置的,因此无法在不启动时绑定值,从而无法可靠地执行。您事先无法知道如何调用它,或者哪些函数需要特殊或限制调用来“保留” this - >这个关系。

函数或调用者的this可以是任何对象,可能没有 this - >这个。考虑:

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

当你致电x.a.b()时,b的this就是了。但如果你这样做:

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

x.a.b.call(someOtherObject);

的价值是什么 - >这个在这些情况下?

答案 2 :(得分:0)

回答我自己的问题,因为其他人可能觉得它很有用。不确定我是否最终会使用这个或Squeegy的解决方案。这些函数只定义一次,然后克隆包含对象并注入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);