2011-07-15 1 views
2

しかし、Rubyでブロックを生成する方法と同様に、特定のスコープで実行される任意のコードをJavaScriptで渡す機能があります。JavaScriptのRubyスタイルブロック?

は、例えばこれを持っ:

function injectHook() { 
    return function(block) { 
     block(); 
    } 
} 

(function() { 
    var a = 1; 
    self.inject = injectHook(); 
})(); 

inject(function() { 
    a++; 
}); 

inject(function() { 
    console.log(a); 
}); 

injectHookが異なるスコープで定義され、aにアクセスすることができなくなりますので、上記の試みは動作しません。

ここでの主な使用例は、複雑なコードのライブデバッグです。

編集:I started a GitHub project around this question

+0

この質問は完全ではありません。あなたは確かにそれらのステートメントを "言う"ことができます。あなたが "言う"ときに何を期待するのですか?そしてそのコードの中で "自己"は何を意味しますか?これはJavaScriptのコンセプトではありません。あなたは「これ」を意味しましたか? – Pointy

+0

私はもう少し明確にしようとしました。うまくいけば分かりやすいでしょう。 – kristopolous

+0

大きな質問のために+1: –

答えて

1

これは動作するはずです:

function Inject(scope) { 
    return 'Inject.' + scope + ' = ' + function(block) { 
     return eval('(' + block + ')()'); 
    }; 
} 

(function(){ 
    var a = 1; 
    eval(Inject('ref')); 
})(); 

Inject.ref(function(){ a++ }); 
Inject.ref(function(){ console.log('hello world', a) }); 
+0

私はあなたのソリューションが好きです、私はまた、少しルビーのishです答えを提供しました。いずれにしても大きな質問です! –

+0

すべてのブラウザが機能をデコンパイルしているわけではありませんが、主にモバイルブラウザですが、最小限のデスクトップも同様です。 –

+0

具体例はありますか? – kristopolous

0

申し訳ありませんが、それはJavaScriptでことはできません。コードは定義されたスコープにしかアクセスできず、スコープ外のローカル変数にアクセスすることはできません。

似た何かをする唯一の方法は、オブジェクトの上にある:

function injectHook(obj){ 
    return function(block){ 
     block.apply(obj); 
    } 
} 

function someClass(){ 
    this.a = 1; 

    this.inject = injectHook(this); 
} 

var instance = new someClass; 
instance.inject(function(){ 
    this.a++; 
}); 

は(注意:Firefoxの古いバージョンでは、あなたが可能やろうとしているものになりevalで「バグ」を持っているが、それはありません。広く可能)

+0

あなたは 'function f(){ var a = 1; eval( 'alert(a)'); } f(); 'はFF 5とはうまくいかないでしょうか? – kristopolous

+0

いいえ、古いバージョンのFFでは、関数 'f'の外側から' a'変数を取得できるコードがありました。 –

+0

@cwolves何??どのようにして、そのクロージャーに語彙的にスコープされていないコードからクロージャー内のローカル変数に到達することができますか? – Pointy

0

まず、偉大な質問!私はそれを実装する比較的簡単な方法を考案するのに少なくとも1時間を費やしました!

Object.prototype.yield = function() { 
    return "try { (" + this + ")() } catch (e) { console.log('**Context error** ' + e) }"; 
} 

// first yielding block 
var y1 = (Object(function() { 
    console.log('in y1, but still in the right context...'); 
    a++; 
})).yield(); 

// second yielding block 
var y2 = (Object(function() { 
    console.log('in y2, but still in the right context...'); 
    a = a + 5; 
})).yield(); 

// voila 
(function() { 
    var a = 1; 
    eval(y1); 
    eval(y2); 
    a--; 
    eval(y2); 
    console.log(a); // a == 11 now as expected 
})(); 

// another block without an `a` 
(function() { 
    var b = 1; 
    eval(y1); // gracefully fails 
})(); 

これは、それが複数の場所にもたらすことができるという意味で、もう少しルビーっぽい傾向にある:これは私がこの問題に取り組んだ方法です。それだけでなく、コードの特定のブロック(y1y2y3など)に譲ることができます。

この回答は役に立ちましたか?あなたの質問はすごかったです!

+0

悪くない。私はあなたが本当にこのような解決策を使って縄張りの共起に近づくことができると思う。 – kristopolous

+0

少し編集してコードを読みやすくしました(反射機能も必要ありません) –

関連する問題