Как написать этот код JavaScript без Eval (QUNIT Mocking)? - PullRequest
4 голосов
/ 03 января 2012

Я экспериментировал с тестами QUnit и искал хороший метод для переопределения функций с помощью имитаций, чтобы включить больше атомарных тестов.Существуют хорошие решения для конкретных случаев, например, переопределение $ .ajax ( Simple jQuery (1.5+) AJAX Mocking ), но я искал более общий подход и придумал следующее:

// Constructor for overrides.
function overrides(overrides) {
    this.overrides = overrides;
}

// Implementation for overrides.
overrides.prototype = {
    set: function () {
        var functions = {};
        $.each(this.overrides, function (key, value) {
            eval("functions['" + key + "'] = " + key + ";");
            eval(key + " = value;");
        });
        this.functions = functions;
    },

    reset: function () {
        var functions = this.functions;
        $.each(this.overrides, function (key, _) {
            eval(key + " = functions['" + key + "'];");
        });
    }
}

Что может быть использовано следующим образом:

module("Comments", {
    setup: function () {
        this.overrides = new overrides({ "$.ajax": function (url, options) {
            alert("ajax: " + url + ', ' + options);
        }
        });

        this.overrides.set();
    },
    teardown: function () {
        this.overrides.reset();
    }
});

Теперь, когда все работает нормально, и хотя это может быть не самое худшее использование eval (), мне было интересноесли это действительно может быть написано без использования eval ()?Я прочитал несколько других вопросов о eval () и попробовал различные варианты, такие как доступ к переопределениям с помощью window [], но это не работает, например, для случая $ .ajax (window ['$']. Ajaxработает, но не window ['$. ajax']).

Возможно, я также думаю о том, что hard и eval () можно использовать здесь безопасно, или в целом есть лучший подход для переопределений функций?

Ответы [ 2 ]

2 голосов
/ 03 января 2012

Почему нельзя просто относиться к объектам как к объектам?

functions[key] = key;

var arr = key.split('.');
var obj = window;

for (var i = 0; i < arr.length; i++){
  if (obj) obj = obj[arr[i]];
}

obj = value;
1 голос
/ 03 января 2012

Насколько я знаю, единственный способ - указывать имя объекта и свойства отдельно. Это также относится и к нативным функциям, таким как Object.defineProperty, которые принимают объект как один аргумент, а имя свойства как строку как другой аргумент.

// overwrite properties inside `$`

new overrides($, {"ajax": function (url, options) {
    alert("ajax: " + url + ', ' + options);
}});

И как то так:

function overrides(obj, overrides) {
    this.obj = obj;
    this.overrides = overrides;
}

и

set: function () {
    var functions = {};
    var inst = this;

    $.each(this.overrides, function (key, value) {
        functions[key] = inst.obj[key]; // old function
        inst.obj[key] = value; // overwrite function
    });

    this.functions = functions;
},

Это работает, потому что inst.obj и $ ссылаются на один и тот же объект - изменение свойств на inst.obj также модифицирует $ в этом случае.

...