I am facing a situation where I need to add the same blocks of code to the start and the end of multiple functions in JavaScript. e.g.
function funcA () {
// code block 1
...
// code unique to funcA
...
// code block 2
...
}
function funcB () {
// code block 1
...
// code unique to funcB
...
// code block 2
...
}
function funcC () {
// code block 1
...
// code unique to funcC
...
// code block 2
...
}
I wonder what is the right pattern to use here to minimize the duplications.
Its called the extract method refactoring.
function block1()
{
// code block 1
}
function block2()
{
// code block 2
}
function funcA () {
block1();
// code unique to funcA
....
block2();
}
function funcB () {
block1();
// code unique to funcB
....
block2();
}
function funcC () {
block1();
// code unique to funcC
....
block2();
}
You could use another function to build your functions for you:
function makeFunc( specialProcessing ) {
return function() {
// block 1
specialProcessing( x, y, z );
// block 2
};
}
var func1 = makeFunc( function( x, y, z ) {
// stuff for func1
});
var func2 = makeFunc( function( x, y, z ) {
// stuff for func2
});
If you have sizable chunks of code in these blocks that can be applied to each function universally, by simply changing the variables in use, then you should extract those blocks of codes to separate methods. This has the advantage of promoting code reuse, improving readability of your code, and making it much, much easier to test and debug, particularly if you're following test-driven development ideals or even just running your own functional testing. It is always a goal of good software engineering and design to create small methods that are useful in many places to reduce the work you have to do and decrease the number of bugs in your code.
Blocks can be extracted to functions and called using the apply method. This will keep context and forward any arguments passed to original function.
function funcA() {
block1.apply(this, arguments);
// specific code to funcA
block2.apply(this, arguments);
}
arguments will contain any arguments passed to parent function
If you know it'll always be set up like that and you don't want to have the actual function calls inside of it, or maybe some will be in different orders I always like to set up a function to interwine the function calls for me.
jsFiddle DEMO
// Set up dynamically to handle calling any number of functions
// in whatever order they are specified in the parameters
// ie: setupFunctionOrder(func1, func2, func3, func4);
function setupFunctionOrder () {
for (i = 0; i < arguments.length; i++) {
arguments[i]();
}
}
function block1 () { log('\nblock1 - running'); }
function block2 () { log('block2 - running'); }
function funcA () { log('funcA - running'); }
// ** Useage:
// now we make the actual call to set up the ORDER of calling -funcA-
setupFunctionOrder(block1, funcA, block2);
Just pass in the function you want to be unique. Like this:
function reusableFunc(fn) {
//reused code block here
fn();
//reused code block here
}
var myResuableFunc1 = function (args) {
reusableFunc(function () {
//do your business here.
});
};
var myResuableFunc2 = function (args) {
reusableFunc(function () {
//do your business here.
});
};
//Or another way
function myResuableFunc3(args) {
reusableFunc(function () {
//do your business here
});
}
Then, you can create as many functions using the shared code as you want and, through the power of closures, pass these newly created functions around any way that you like.
Related
I have a function called "destination" nested in scrip1.js file. If I add this file at the end of webpage using , how can I trigger it at the next step? Here are some contents of script1.js.
script1.js
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
$("body").on("click", ".notify-btn", function (event) {
event.preventDefault();
destination(some args);
});
someOtherFunction();
start();
}
$.fn.something = function (options) {
return this.each(function () {
if (undefined == $(this).data("something")) {
var plugin = new $.something(this, options);
$(this).data("something", plugin);
}
});
};
I tried this, but is not working. Chrome console is showing error about this function.
<script type="text/javascript" src="script1.js"></script>
<script>
$.fn.something().destination();
</script>
I can not change this script1.js, so any possible way?
There's no specific connection between variables declared during function execution - and how the rest of the world sees the result of execution. So this code:
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
}
start();
... lets destination value (remember, functions in JS are first-class citizens) go away when start() completes its execution. That's actually quite convenient if you want to encapsulate some implementation details and hide it from users; this technique (also known as Module pattern) was often used in pre-class world to implement private properties in vanilla JavaScript.
However, all the values returned from a function can be reused. For example, here...
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return {
destination
};
}
return start();
}
... you make destination function a part of object that is returned from start(). Now $.something returns an object, too; that means it can be reused:
var plugin = new $.something(this, options);
// ...
plugin.destination('some', 'args');
If you're afraid changing the return value might hurt someone, you can try to assign value of destination to $.something object itself as its property, like this:
$.something = function(element, options) {
function start() {
function destination(arg1, arg2..) {
$.notify(some args);
}
return destination;
}
// ...
const destination = start();
$.something.destination = destination;
}
The returned value is not modified, yet function is accessible. Still, that's not actually a good workaround; the biggest issue is that any subsequent calls on $.something will rewrite the value of that function, which might be not a good thing if its execution depends on some scoped variables.
While technically there's a way to fetch destination function code by parsing $.something source code, I really doubt it's worth the effort in your case.
I couldn't be able to find any good explanation of how the method works exactly and how it could be useable. In the documentation I found the description:
setDefinitionFunctionWrapper(fn, options)
Set a function used to wrap step / hook definitions. When used, the
result is wrapped again to ensure it has the same length of the
original step / hook definition. options is the step specific
wrapperOptions and may be undefined.
I'm not experienced programmer and I do not understand what "wrapping" means in this context. I'd be glad if someone will explain the subject more effectively
I tried using the snippet Jorge Chip posted and It does not work.
You should use this instead:
const {setDefinitionFunctionWrapper} = require('cucumber');
setDefinitionFunctionWrapper(function(fn){
if(condition){//you want to do before and after step stuff
return async function(){
//do before step stuff
await fn.apply(this, arguments)
//do after step stuff
}
}
else{//just want to run the step
return fn
}
}
in the snippet he posted he used args which will not work he also used await inside of a non async function which will also not work
A wrapper function is a subroutine in a software library or a computer program whose main purpose is to call a second subroutine or a system call with little or no additional computation.
Usually programmers wrap functions with another function to do extra small actions before or after the wrapped function.
myWrappedFunction () { doSomething }
myWrapper () { doSmallBits; myWrappedFunction(); doSmallBits; }
(1) https://en.wikipedia.org/wiki/Wrapper_function
Digging into CucumberJS, setDefinitionFunctionWrapper is a function that will be called on every step definition and should return the function you want to execute when that step is called.
An example of a dummy setDefinitionFunctionWrapper would be something like:
setDefinitionFunctionWrapper(function (fn, opts) {
return await fn.apply(this, args);
}
As of cucumber 2.3.1. https://github.com/cucumber/cucumber-js/blob/2.x/src/support_code_library/builder.js
After you install the cucumber library, see the source code in /node_modules/cucumber/lib/support_code_library/builder.js
At the line 95:
if (definitionFunctionWrapper) {
definitions.forEach(function (definition) {
var codeLength = definition.code.length;
var wrappedFn = definitionFunctionWrapper(definition.code, definition.options.wrapperOptions);
if (wrappedFn !== definition.code) {
definition.code = (0, _utilArity2.default)(codeLength, wrappedFn);
}
});
} else {
...
definitionFunctionWrapper bascially takes code(fn) and opts and return the new code(fn).
Understanding this piece of code we can make this function in our step file:
var { setDefinitionFunctionWrapper } = require('cucumber');
// Wrap around each step
setDefinitionFunctionWrapper(function (fn, opts) {
return function() {
console.log('print me in each step');
return fn.apply(this, arguments);
};
});
I am wondering if there is some neat way of knowing if a function is called in the current tick (the tick in which the function was declared), or the next tick (or some future tick) of the Node.js event loop
for example:
function foo(cb){
// we can fire callback synchronously
cb();
// or we can fire callback asynchronously
process.nextTick(cb);
}
say will call foo like so:
function outer(){
const currentTickId = process.currentTickId;
function bar(){ //bar gets created everytime outer is called..
if(process.currentTickId === currentTickId){
//do something
}
else{
// do something else
}
}
// foo is always called in the same tick that bar was
// declared, but bar might not be called until the next tick
foo(bar);
}
most applications won't need something like this, but I am writing a library and it would be useful to have this functionality, if it's possible! note that process.currentTickId is made up by me for this example
It looks like you've already discovered process.nextTick.
You could use this to rig up a system to achieve "process.currentTickId" as the code in your question indicates you need:
process.currentTickId = 0;
const onTick = () => {
process.currentTickId++;
process.nextTick(onTick);
};
process.nextTick(onTick);
NPM lib:
https://www.npmjs.com/package/event-loop-ticks
Improved answer basing on #Emmett post:
let _tick = 0;
const onTick = () => {
_tick++;
setImmediate(() => process.nextTick(onTick)).unref();
};
process.nextTick(onTick);
Just wondering if there is anyway to fire some code when a function is called, without adding the code to the function, for example:
function doSomething(){
//Do something
}
//Code to call when doSomething is called
You can wrap the function :
(function(){
var oldFunction = doSomething;
doSomething = function(){
// do something else
oldFunction.apply(this, arguments);
}
})();
I use an IIFE here just to avoid polluting the global namespace, it's accessory.
Well, yes, it's not actually hard to do. The crucial thing is that a function's name is just an identifier like any other. You can redefine it if you want to.
var oldFn = doSomething;
doSomething = function() {
// code to run before the old function
return oldFn.apply(this, arguments);
// code to run after the old function
};
NB that it's better to do oldFn.apply(this, arguments) rather than just oldFn. In many cases it won't matter, but it's possible that the context (i.e. the value of this inside the function) and the arguments are important. Using apply means they are passed on as if oldFn had been called directly.
What about something like:
function doSomething(){
doSomething.called = true;
}
//call?
doSomething();
if(doSomething.called) {
//Code to call when doSomething is called
}
I know you said you don't want to modify the original function, but consider adding a callback. Then you can execute code based on different results in your function (such as onSucess and onError):
function doSomething(onSuccess, onError){
try {
throw "this is an error";
if(onSuccess) {
onSuccess();
}
} catch(err) {
if(onError) {
onError(err);
}
}
}
Then, when you call doSomething, you can specify what you want done with inline functions:
doSomething(function() {
console.log("doSomething() success");
}, function(err) {
console.log("doSomething() error: " + err);
});
I haven't found a good reference for declaring my own functions inside the
jquery.ready(function(){});
I want to declare them so they are inside the same scope of the ready closure. I don't want to clutter the global js namespace so I don't want them declared outside of the ready closure because they will be specific to just the code inside.
So how does one declare such a function...and I'm not referring to a custom jquery extension method/function...just a regular 'ol function that does something trivial say like:
function multiple( a, b ){
return a * b;
}
I want to follow the jquery recommendation and function declaration syntax. I can get it to work by just declaring a function like the multiply one above...but it doesn't look correct to me for some reason so I guess I just need some guidance.
I believe that you would be okay just declaring the function inside the ready() closure, but here you can be a bit more explicit about the local scoping:
jQuery.ready(function() {
var myFunc = function() {
// do some stuff here
};
myFunc();
});
It might sound simple but you just ... declare the function. Javascript allows functions to have inner functions.
$(document).ready( function() {
alert("hello! document is ready!");
function multiply(a, b) {
return a * b;
}
alert("3 times 5 is " + multiply(3, 5));
});
I have a StartUp function, and I use it as printed bellow:
function StartUp(runnable)
{
$(document).ready(runnable.run);
}
var ExternalLinks =
{
run: function()
{
$('a[rel="external"]').bind('click', ExternalLinks.click);
},
click: function(event)
{
open(this.href);
return false;
}
}
StartUp(ExternalLinks);
var ConfirmLinks =
{
run: function()
{
$('a.confirm').bind('click', ConfirmLinks.click);
},
click: function(event)
{
if (!confirm(this.title)) {
return false;
}
}
}
StartUp(ConfirmLinks);
My web sites are modular, so every module has N actions and every action can have a .js file, so I just write function and call it with StartUp(...functionName...)