Блоки в стиле Ruby в JavaScript? - PullRequest
2 голосов
/ 16 июля 2011

Но я хотел бы иметь возможность передавать произвольный код в 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.

. Основной сценарий использования здесь -оперативная отладка сложного кода.

Редактировать: Я начал проект GitHub вокруг этого вопроса

Ответы [ 3 ]

1 голос
/ 16 июля 2011

Это должно работать:

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 голосов
/ 16 июля 2011

Прежде всего, отличный вопрос! Я потратил как минимум час, пытаясь придумать относительно простой способ его реализации! Вот как я решил эту проблему:

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
})();

Это имеет тенденцию быть немного более рубиновым в том смысле, что он может давать в нескольких местах. Не только это, но это еще один шаг вперед, поскольку он может передавать определенные блоки кода (y1, y2, y3 и т. Д.)

Надеюсь, этот ответ был полезен, ваш вопрос был замечательным!

0 голосов
/ 16 июля 2011

Извините, но это невозможно в 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, которая делает возможным то, что вы пытаетесь сделать, но это не всегда возможно.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...