How to write this JavaScript code without eval (QUnit mocking)?

I experimented with QUnit checks and was looking for a good method to override functions using mocks to allow more atom tests. There are good solutions for specific cases, such as overriding $ .ajax ( Simple jQuery (1.5+) AJAX Mocking ), but I looked for a more general approach and came up with the following:

// 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 + "'];"); }); } } 

What can then be used as:

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

Now everything seems to be working fine, and although this might not be the worst use of eval (), I was wondering if this could really be written without using eval ()? I read a few other eval () questions here and tried various options such as accessing overrides using the window [], but this does not work for the $ .ajax case, for example (window ['$']. Ajax works, but not the window ['$. ajax']).

Perhaps I also think it's hard, and eval () can be used safely here, or is there a better approach at all for overriding functions?

+4
source share
2 answers

Why can't you just treat objects as objects?

 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; 
+2
source

The only way, as far as I know, is to provide the object name and properties separately. This also applies to built-in functions such as Object.defineProperty , which takes an object as one argument and a property name as a string as another argument.

 // overwrite properties inside `$` new overrides($, {"ajax": function (url, options) { alert("ajax: " + url + ', ' + options); }}); 

And something like this:

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

and

 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; }, 

This works because inst.obj and $ refer to the same object - changing properties on inst.obj also change $ in this case.

+1
source

Source: https://habr.com/ru/post/1388990/


All Articles