I don't understand why the following code passes this and arguments to func.apply.
I tried to play with the code to figure out what it is doing, searched on the internet, etc., but couldn't find anything about using apply this way.
function work(a, b) {
alert( a + b );
}
function spy(func) {
function wrapper(...args) {
wrapper.calls.push(args);
return func.apply(this,arguments);
}
wrapper.calls = []
return wrapper;
}
work = spy(work)
work(1, 2); // 3
work(4, 5); // 9
The following call returns the result of wrapper
work.apply(this,arguments(a,b))
The result of spy is the same as the above.
But what makes this and arguments do the right thing in wrapper? Because without the this it doesn't work and why when i declare
let work = spy(work)
It doesn't work.
work is already declared here (function declaration). You can use var instead if you want to redeclare.
In this particular example, you are not using this inside work function. So it doesn't make a difference even if you invoke func like this func(...args) as below:
function work(a, b) {
alert( a + b );
}
function spy(func) {
function wrapper(...args) {
wrapper.calls.push(args);
console.log({ this: this });
return func(...args);
}
wrapper.calls = []
return wrapper;
}
var work = spy(work)
work(1, 2);
work(4, 5);
I'm developing a simple Javascript Client API for my unit tests, as I'm studying TDD and learning better by doing things.
I'm following a model where they will only be a CHECK by test, I have my TEST function, which is where all the tests of a given file will be, and each test will be called by TEST_F with only one CHECK function each, thus not needing a description for each TEST_F, since with just a CHECK, it is simple and easy to understand with just a good "nameTest".
The problem I'm having is to use the Javascript spread, I actually know well how to solve my problem without it, but I would like to understand if it could help me simplify things here. The TEST function, as I said, might get several TEST_F functions as arguments, so I thought I'd do something like const TEST = (... f) => {};, but I'm not sure how to use each "f" argument since each TEST_F function returns me an object, which I want to use to accuse the TEST_Fs that fail. I will try to explain what I try to do with the code below that we know will not work, but only to understand where I am trying to get:
/* --------------------------------------------------------------- */
/* ------------------- Test API ---------------------------------- */
/* --------------------------------------------------------------- */
const TEST = (fileName, ...f) => {
const passing = [];
const failing = [];
console.log('Running unit tests in '+fileName+':');
const tStart = performance.now();
const result = ...f(); // I know it's not possible, but you understand what I'm trying to do?
result.resultTest==='passed'?passing.push(result):failing.push(result);
const tEnd = performance.now();
const duration = tEnd - tStart;
const lenPassing = passing.length;
const lenFailing = failing.length;
console.log('Passing: '+lenPassing+' ('+duration+'ms)');
console.log('Failing: '+lenFailing);
if(lenFailing > 0){
let stg = '';
for(let i = 0; i < lenFailing; i++){
stg += (i + ') ' + failing[i].nameTest + ' (' + failing[i].durationTest + ')' + '\n');
}
console.log(stg);
}
};
const TEST_F = (nameTest, f) => {
const tStart = performance.now();
const resultTest = f();
const tEnd = performance.now();
const durationTest = tEnd - tStart;
return { nameTest: nameTest, durationTest: durationTest, resultTest: resultTest };
};
const CHECK_EQUAL = (value, expected) => {
return ((value === expected)?'passed':'failed');
};
export {
TEST,
TEST_F,
CHECK_EQUAL
};
Up 1:
How would I solve my problem without using the spread? creating a TEST object that contains an array of TEST_F and then would create a function to run the tests, something like EXECUTE_TEST, but what I want to avoid is having to call a function always in my test files, I want something simple like:
TEST("main.js",
TEST_F("test1", () => {
return CHECK_EQUAL(3, 3);
}),
TEST_F("test2", () => {
return CHECK_EQUAL(7, 3);
})
);
which I was able to solve with the #TJ Crowder answer:
for(let fn of f) {
const result = fn;
result.resultTest==='passed'?passing.push(result):failing.push(result);
}
If your goal is to call each function in the f array and get the results from them into the passing or failing arrays, I'd probably use a simple for-of:
for (const fn of f) {
const result = fn();
result.resultTest==='passed'?passing.push(result):failing.push(result);
}
or forEach or similar, any of the array looping mechanisms would do the job.
I'm using a JavaScript spy library,
simple-spy.
I've found out that when spying on a given function,
the resulting spy always has an arity of 0.
This creates a problem with my use of
this currying function.
So I've submitted a pull-request
that adds arity transparency to
the spy library.
The code looks like this:
function spy(fn) {
const inner = (...args) => {
stub.callCount++;
stub.args.push(args);
return fn(...args);
};
// ends up a string like
// 'a,b,c,d'
// depending on the `fn.length`
const stubArgs = Array(fn.length)
.fill(null)
.map((m, i) => String.fromCodePoint(97 + i))
.join();
const stubBody = 'return inner(...arguments);';
// this seems to be the only way
// to create a function with
// programmatically specified arity
const stub = eval(
// the wrapping parens is to
// prevent it from evaluating as
// a function declaration
`(function (${stubArgs}) { ${stubBody} })`
);
stub.reset = () => {
stub.callCount = 0;
stub.args = [];
};
stub.reset();
return stub;
}
exports.spy = spy;
This seems to work.
Is it possible to do this
without the use of eval?
Is it possible to
reduce the use of eval
to even less that this?
I'm aware that there are other issues
with this spy implementation.
It is simplistic and it works
for my use case so far.
Like Benjamin wrote, I used a simple:
function spy(fn) {
const stub = (...args) => {
stub.callCount++;
stub.args.push(args);
return fn(...args);
};
stub.reset = () => {
stub.callCount = 0;
stub.args = [];
};
stub.reset();
Object.defineProperty(stub, 'length', {value: fn.length});
return stub;
}
exports.spy = spy;
Much, much better looking.
In javscript we can do this
var text = "the original text";
text+=";Add this on";
If a library has a function already defined (e.g)
//In the js library
library.somefunction = function() {...};
Is there a way to add something on so that I can have two functions run?
var myfunction = function() {...};
Something like:
library.somefunction += myfunction
So that both myfunction() and the original library.somefunction() are both run?
You can use this kind of code (leave scope empty to use default scope):
var createSequence = function(originalFn, newFn, scope) {
if (!newFn) {
return originalFn;
}
else {
return function() {
var result = originalFn.apply(scope || this, arguments);
newFn.apply(scope || this, arguments);
return result;
};
}
}
Then:
var sequence = createSequence(library.somefunction, myFunction);
I think what you want to create is a Hook (function) - you want to call library.somefunction but add a bit of your own code to run before. If that's the case, you can make your myfunction either call or return the library function after it's done with your bit of code.
var myfunction = function() {
// your code
// ...
return library.somefunction();
}
Let's say I have var a = function() { return 1; }. Is it possible to alter a so that a() returns 2? Perhaps by editing a property of the a object, since every function is an object?
Update: Wow, thanks for all the responses. However, I'm afraid I wasn't looking to simply reassign a variable but actually edit an existing function. I am thinking along the lines of how you can combine partial functions in Scala to create a new PartialFunction. I am interested in writing something similar in Javascript and was thinking that the existing function could perhaps be updated, rather than creating an entirely new Function object.
You can do all kinds of fun stuff with javascript, including redefining functions:
let a = function() { return 1; }
console.log(a()); // 1
// keep a reference
let old = a;
// redefine
a = function() {
// call the original function with any arguments specified, storing the result
const originalResult = old.apply(old, arguments);
// add one
return originalResult + 1;
};
console.log(a()); // 2
Voila.
Edit: Updated to show this in a crazier scenario:
let test = new String("123");
console.log(test.toString()); // logs 123
console.log(test.substring(0)); // logs 123
String.prototype.substring = function(){ return "hahanope"; }
console.log(test.substring(0)); // logs hahanope
You can see here that even though "test" is defined first, and we redefine substring() afterwards, the change still applies.
Side note: you really should reconsider your architecture if you're doing this...you're going to confuse the crap out of some poor developer 5 years down the road when s/he's looking at a function definition that's supposed to return 1, but seems to always return 2....
So you want to modify the code of a function directly, in place, and not just reassign a different function to an existing variable.
I hate to say it, but as far as I have been able to figure it out - and I have tried -, it can't be done. True, a function is an object, and as such it has methods and properties which can be tweaked and overwritten on the object itself. Unfortunately, the function body is not one of them. It is not assigned to a public property.
The documentation on MDN lists the properties and methods of the function object. None of them gives us the opportunity to manipulate the function body from the outside.
That's because according to the spec, the function body is stored in the internal [[Code]] property of the function object, which can't be accessed directly.
I used something like this to modify an existing function whose declaration was not accessible to me:
// declare function foo
var foo = function (a) { alert(a); };
// modify function foo
foo = new Function (
"a",
foo.toSource()
.replace("alert(a)", "alert('function modified - ' + a)")
.replace(/^function[^{]+{/i,"") // remove everything up to and including the first curly bracket
.replace(/}[^}]*$/i, "") // remove last curly bracket and everything after<br>
);
Instead of toSource() you could probably use toString() to get a string containing the function's declaration. Some calls to replace() to prepare the string for use with the Function Constructor and to modify the function's source.
let a = function() { return 1; }
console.log(a()) // 1
a = function() { return 2; }
console.log(a()) // 2
technically, you're losing one function definition and replacing it with another.
How about this, without having to redefine the function:
var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2
I am sticking to jvenema's solution, in which I don't like the global variable "old". It seems better to keep the old function inside of the new one:
function a() { return 1; }
// redefine
a = (function(){
var _a = a;
return function() {
// You may reuse the original function ...
// Typical case: Conditionally use old/new behaviour
var originalResult = _a.apply(this, arguments);
// ... and modify the logic in any way
return originalResult + 1;
}
})();
a() // --> gives 2
All feasible solutions stick to a "function wrapping approach".
The most reliable amongst them seems to be the one of rplantiko.
Such function wrapping easily can be abstracted away. The concept / pattern itself might be called "Method Modification". Its implementation definitely belongs to Function.prototype. It would be nice to be backed
one day by standard prototypal method modifiers like before, after, around, afterThrowing and afterFinally.
As for the aforementioned example by rplantiko ...
function a () { return 1; }
// redefine
a = (function () {
var _a = a;
return function () {
// You may reuse the original function ...
// Typical case: Conditionally use old/new behaviour
var originalResult = _a.apply(this, arguments);
// ... and modify the logic in any way
return originalResult + 1;
};
})();
console.log('a() ...', a()); // --> gives 2
.as-console-wrapper { min-height: 100%!important; top: 0; }
... and making use of around, the code would transform to ...
function a () { return 1; }
console.log('original a ...', a);
console.log('a() ...', a()); // 1
a = a.around(function (proceed, handler, args) {
return (proceed() + 1);
});
console.log('\nmodified a ...', a);
console.log('a() ...', a()); // 2
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function(d){function f(a){return typeof a==e&&typeof a.call==e&&typeof a.apply==e}function g(a,b){b=null!=b&&b||null;var c=this;return f(a)&&f(c)&&function(){return a.call(b||null!=this&&this||null,c,a,arguments)}||c}var e=typeof d;Object.defineProperty(d.prototype,"around",{configurable:!0,writable:!0,value:g});Object.defineProperty(d,"around",{configurable:!0,writable:!0,value:function(a,b,c){return g.call(a,b,c)}})})(Function);
</script>
This is a Clear Example based on a control timepicker eworld.ui
www.eworldui.net
Having a TimePicker eworld.ui where JavaScript is unreachable from outside, you can't find any js related to those controls. So how can you add a onchange event to the timepicker ?
There is a js function called when you Select a time between all the options that the control offer you. This function is: TimePicker_Up_SelectTime
First you have to copy the code inside this function.
Evaluate...quikwatch...TimePicker_Up_SelectTime.toString()
function TimePicker_Up_SelectTime(tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
document.getElementById(tbName).value = selTime;
if(lblName != '')
document.getElementById(lblName).innerHTML = selTime;
document.getElementById(divName).style.visibility = 'hidden';
if(enableHide)
TimePicker_Up_ShowHideDDL('visible');
if(customFunc != "")
eval(customFunc + "('" + selTime + "', '" + tbName + "');");
eval(postbackFunc + "();");
}
Now
Using the code that you have saved before reassign the same source code but add whatever you want..
TimePicker_Up_SelectTime = function (tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
document.getElementById(tbName).value = selTime;
if (lblName != '')
document.getElementById(lblName).innerHTML = selTime;
document.getElementById(divName).style.visibility = 'hidden';
if (enableHide)
TimePicker_Up_ShowHideDDL('visible');
if (customFunc != "")
eval(customFunc + "('" + selTime + "', '" + tbName + "');");
eval(postbackFunc + "();");
>>>>>>> My function >>>>> RaiseChange(tbName);
}
I've added My Function to the function so now I can simulate an onchange event when I select a time.
RaiseChange(...) could be whatever you want.
If you're debugging javascript and want to see how changes to the code affects the page, you can use this Firefox extension to view/alter javascripts:
Execute JS firefox extension:
https://addons.mozilla.org/en-US/firefox/addon/1729
You can change functions like other objects
var a1 = function(){return 1;}
var b1 = a1;
a1 = function(){
return b1() + 1;
};
console.log(a1()); // return 2
// OR:
function a2(){return 1;}
var b2 = a2;
a2 = function(){
return b2() + 1;
};
console.log(a2()); // return 2
Can you not just define it again later on? When you want the change try just redefining it as:
a = function() { return 2; }
const createFunction = function (defaultRealization) {
let realization = defaultRealization;
const youFunction = function (...args) {
return realization(...args);
};
youFunction.alterRealization = function (fn) {
realization = fn;
};
return youFunction;
}
const myFunction = createFunction(function () { return 1; });
console.log(myFunction()); // 1
myFunction.alterRealization(function () { return 2; });
console.log(myFunction()); // 2