3

これは不可能だと私はかなり確信していますが、それを可能にする方法について誰かが独創的なアイデアを持っているかどうかを見たかったのです。

次のコードを機能させたい:

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

言い換えれば、私はこの場合にいることx.a.getThisへの言及を持ちたいのです。わかる?thisx

これを1レベル深く機能させるには、次のようにします。

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

1つは、これをプロトタイプとして機能させ、手動でバインドして「不正行為」を行わないようにすることthisです。

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

上記は私が達成しようとしていることの完璧な機能例ですが、各インスタンスにすべての追加機能が必要なわけではありません:)

参考までに、ここでの実際のユースケースは、ノード内のCassandraオブジェクトを表すクラスを作成しており、を介してスーパー列->列ファミリー->列を参照し、foo.a.bへの参照を保持できるようにすることです。foo深い機能。

4

3 に答える 3

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'
于 2011-05-27T06:31:58.473 に答える
0

関数のthisの値は呼び出しによって設定されるため、開始時に値をバインドせずに確実に実行することはできません。これがどのように呼び出されるか、またはthis- > this関係を「保持」するために、どの関数が特別な呼び出しまたは制限された呼び出しを必要とするかを事前に知ることはできません。

関数または呼び出し元thisは任意のオブジェクトである可能性があり、this- >thisがまったくない可能性があります。検討:

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

を呼び出すx.a.b()と、bthisはaになります。しかし、あなたがそうするなら:

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

また

x.a.b.call(someOtherObject);

これらの場合、this- > thisの値は何ですか?

于 2011-05-27T06:48:59.613 に答える
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);
于 2011-05-27T06:50:09.560 に答える