JavaScript中的Ruby样式块?

时间:2011-07-15 21:49:55

标签: javascript debugging closures

但我想要做的是能够在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

3 个答案:

答案 0 :(得分: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) });

答案 1 :(得分: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中有一个“错误”,它会使您尝试做的事情成为可能,但它并不是很有可能。)

答案 2 :(得分:0)

首先,好问题!我花了至少一个小时试图想出一个相对简单的实现方法!这就是我解决这个问题的方法:

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等。)

我希望这个答案很有用,你的问题很棒!