This is probably quite a simple problem, but it's causing me to scratch my head, so I'm posting it here.
I have some jQuery in the following form:
if (jQuery('.SearchRegions:checked').length == 0) {
jQuery('.SearchRegions').each(function(){
//code
});
} else {
jQuery('.SearchRegions:checked').each(function(){
//the same code
});
}
Obviously it seems ridiculous to repeat a big block of code inside each of these functions. But when I tried to name and move the function, it all seemed to break down - perhaps because of issues with scope and/or jQuery(this) inside the function no longer referring to the same object?
Can anyone help me by posting a general idea of what my code should look like? (Or any other optimisings or recastings to make it work would be much appreciated!)
You can definitely just define a function and use it by name:
function someHandler(event) {
// code code code
}
jQuery('.SearchRegions').each(someHandler);
Note that when you refer to the function by name, you don't include "()".
Assuming that closures are indeed the problem, you can parameterize your "anonymous" function to pass those values in to it. For example:
function eachRegion(values, $container, foo) {
// common code which uses scope variables `values`, `$container`, and `foo`
}
// elsewhere, in code defining `values`, `$container`, and `foo`...
if (jQuery('.SearchRegions:checked').length == 0) {
jQuery('.SearchRegions').each(function(){
eachRegion(values, $container, foo);
});
} else {
jQuery('.SearchRegions:checked').each(function(){
eachRegion(values, $container, foo);
});
}
You could define your function as a variable and use that in your each method call.
var yourEachFunction = function(){$("ul").append("<li>" + $(this).val() + "</li>");}
if (jQuery('.SearchRegions:checked').length == 0) {
jQuery('.SearchRegions').each(yourEachFunction );
} else {
jQuery('.SearchRegions:checked').each(yourEachFunction );
}
Example of this working on jsfiddle.
Related
So I am currently reading through Clean Code and I really like the idea of super small functions that each tell their own "story". I also really like the way he puts how code should be written to be read in terms of "TO paragraphs", which I've decided to kind of rename in my head to "in order to"
Anyway I have been refactoring alot of code to include more meaningful names and to make the flow in which it will be read a little better and I have stumbled into something that I am unsure on and maybe some gurus here could give me some solid advice!
I know that code-styles is a highly controversial and subjective topic, but hopefully I wont get reamed out by this post.
Thanks everyone!
PSA: I am a noob, fresh out of College creating a web app using the MEAN stack for an internal project in an internship at the moment.
Clean Code refactor
//Modal Controller stuff above. vm.task is an instance variable
vm.task = vm.data.task;
castTaskDataTypesForForm();
function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
}
function castPriorityToInt() {
vm.task.priority = vm.task.priority === undefined ?
0 : parseInt(vm.task.priority);
}
function castReminderInHoursToInt() {
vm.task.reminderInHours = vm.task.reminderInHours === undefined ?
0 : parseInt(vm.task.reminderInHours);
}
function castDueDateToDate() {
vm.task.dueDate = new Date(vm.task.dueDate);
}
function getAssigneObjFromAssigneeString() {
vm.task.assignee = getUserFromId(vm.task.assignee);
}
Possibly better refactor? / My question ----------------------------
//Modal Controller stuff above. vm.task is an instance variable
vm.task = vm.data.task;
castTaskDataTypesForForm();
function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
function castPriorityToInt() {
vm.task.priority = vm.task.priority === undefined ?
0 : parseInt(vm.task.priority);
}
function castReminderInHoursToInt() {
vm.task.reminderInHours = vm.task.reminderInHours === undefined ?
0 : parseInt(vm.task.reminderInHours);
}
function castDueDateToDate() {
vm.task.dueDate = new Date(vm.task.dueDate);
}
function getAssigneObjFromAssigneeString() {
vm.task.assignee = getUserFromId(vm.task.assignee);
}
}
Posting the IIFE example here so I have more room to work with. I'm not saying this is the best option, it's the one I would use with the info the OP gave us.
var castTaskDataTypesForForm = (function() {
var castPriorityToInt = function castPriorityToInt() { ... },
castReminderInHoursToInt = function castReminderInHoursToInt() { .. },
castDueDateToDate = function castDueDateToDate() { ... },
getAssigneObjFromAssigneeString = function getAssigneObjFromAssigneeString() { ... };
return function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
};
}());
vm.task = vm.data.task;
castTaskDataTypesForForm();
This way the helper functions only get defined once and are kept private inside the closure. You can obv remove the var x = function x syntax if you prefer the function x() style.
edit: If the function only gets called once, your own examples are probably the cleaner code. The reason you'd use the IIFE syntax would be to keep the helper functions only accesible by the main function, like in your own second example.
MEANjs uses the second method sometimes (with callbacks for example). I personally think it's nice if you are not intending to use those helpers outside of the main function.
I'm wondering if there is another way to write this function without using a modulo. I realized that I have another piece of code that requires me to click the #mail-wrap button and doing so messes up the number of clicks which affects this function.
It's just a simple switch. I'm not too good with conditionals.
$('#mail-wrap').click(function (e) {
e.preventDefault();
var c = 0;
if (c++ % 2 == 0) {
$('#contact-button').addClass('project-button').text('Projects');
} else {
$('#contact-button').removeClass('project-button').text('Get in touch');
}
});
Edit: Changed the question a bit. Sorry, the last one was too broad.
As Boldewyn mentioned, most likely your problem is that you are defining a global variable c. But if you would like to avoid this variable completely you could check for the CSS-class of contact-button via the jQuery hasClass function, i.e.
$('#mail-wrap').click(function (e) {
...
var contactButton = $('#contact-button');
if (!contactButton.hasClass('project-button')) {
$('#contact-button').addClass('project-button').css('width', '71px').text('Projects');
...
} else {
$('#contact-button').removeClass('project-button').css('width', '96px').text('Get in touch');
...
}
});
The code is interfering with other code, because you have implicitly generated a global variable c. Possible fix: Use an IIFE:
(function() {
var c = 0;
/* rest of your code above ... */
})();
I only want my JavaScript to run once, but I cannot control how many times the javascript file is executed. Basically I'm writing a tiny JS snippet into a CMS, and the CMS is actually calling it 5-10 times. So solutions like this:
function never_called_again(args) {
// do some stuff
never_called_again = function (new_args) {
// do nothing
}
}
never_called_again();
Don't seem to work because as soon as my snippet is run again from the top the function is re-declared, and 'do some stuff' is re-evaluated. Perhaps I'm just not doing it properly, I'm not great with JS. I'm considering using something like try-catch on a global variable, something like
if (code_happened == undefined) {
\\ run code
code_happened = true;
}
EDIT: There is a consistent state e.g. if I set a variable I can see when my snippet is run again. But having to declare it before I access it, I don't know how to say 'does this variable exist yet'
Try this:
var doneTheStuff;
function whatever() {
if (!doneTheStuff) {
doneTheStuff = true;
// do the stuff
}
}
Redundant variable declarations don't affect the value of the variable. Once one of the functions has set the variable to true, the others won't do anything.
if (typeof code_happened === 'undefined') {
window.code_happened = true;
// Your code here.
}
The typeof check gets you around the fact that the global hasn't been declared. You could also just do if (!window.code_happened) since property access isn't banned for undefined properties.
Use a closure, and set a flag. If the flag is true, just return:
if ( ! window.never_called_again ) {
window.never_called_again = (function () {
var ran = false;
return function (args) {
if ( ran ) return;
ran = true;
// Do stuff
};
}());
}
Here's the fiddle: http://jsfiddle.net/U2NCs/
With jQuery, the function .one() may be useful : http://api.jquery.com/one/
W3School exemple here : http://www.w3schools.com/jquery/event_one.asp
In this way, the code is executed only once.
if(typeof onceRun == "undefined") window.onceRun=(
()=>{
//your codes...
console.log("runing...")
return true
}).call()
I have an object ajax_tryit which calls ajax_generic ans sends it 3 functions. They are all named.
Would it be better (more efficient, a tad faster) to use anonymous functions.
Application...This is the ajax call back function which can do 3 things, pass, fail, or undefined(usually a php error).
function ajax_generic( server_response_text, pass_func, fail_func, undefined_func )
{
var aml_status = check_aml( server_response_text.slice( 0, 6 ) );
if( aml_status === Constant.AML.PASS )
{
pass_func();
}
else if( aml_status === Constant.AML.FAIL )
{
fail_func();
}
else
{
undefined_func();
}
}
function ajax_tryit( server_response_text, html_div )
{
var pass_func = function {window.location.reload()};
var fail_func = function(server_response_text) { alert( 'ajax_tryit(): ' + server_response_text ) } ;
var undefined_func = function(server_response_text) { alert( 'php error: ' + server_response_text ) };
ajax_generic( pass_func, fail_func, undefined_func );
}
Named functions (that is, functions created with function declaration statements) are actually pretty nice because you can see their names in stack traces. Other than that, it doesn't much matter so long as the functions are declared in the appropriate scope (or if the scope doesn't matter).
Giving a function a name in a function definition expression is technically legal, but it's not a good idea because the various JavaScript engines can't be trusted not to do something weird.
It always depends on which is more clear, and so in this case I'd say the answer is no. Right now you have fairly descriptive names. Taking them out would make code harder to maintain, and would make indentation confusing. They don't pose any problems by having names.
One thing you could change, though, is the indentation and syntax:
function ajax_tryit(server_response_text, html_div) {
function pass_func() {
window.location.reload()
}
function fail_func(server_response_text) {
alert('ajax_tryit(): ' + server_response_text)
}
function undefined_func(server_response_text) {
alert('php error: ' + server_response_text)
}
ajax_generic(pass_func, fail_func, undefined_func);
}
EDIT: Also, in reply to your comment:
Save 3 variables..so a tad more efficient.
No, it's not more efficient not to use variables, especially here. Don't worry about that.
Anon functions are good to use when you need to pass variables to callback functions or change the scope
Example (passing arguments to callback function):
var somevar = "test";
setInterval( function()
{
test(somevar);
},5000);
function test(Msg)
{
alert(Msg);
}
if you had just done
setInterval(test,5000);
you would have just gotten a blank alert box, extremely simplified example.
For changing scope look at the answer given there it shows an example of when needing to change scope.
But other then that there is no real need to switch out named functions for anon ones.
I have a function, a(), that I want to override, but also have the original a() be performed in an order depending on the context. For example, sometimes when I'm generating a page I'll want to override like this:
function a() {
new_code();
original_a();
}
and sometimes like this:
function a() {
original_a();
other_new_code();
}
How do I get that original_a() from within the over-riding a()? Is it even possible?
Please don't suggest alternatives to over-riding in this way, I know of many. I'm asking about this way specifically.
You could do something like this:
var a = (function() {
var original_a = a;
if (condition) {
return function() {
new_code();
original_a();
}
} else {
return function() {
original_a();
other_new_code();
}
}
})();
Declaring original_a inside an anonymous function keeps it from cluttering the global namespace, but it's available in the inner functions.
Like Nerdmaster mentioned in the comments, be sure to include the () at the end. You want to call the outer function and store the result (one of the two inner functions) in a, not store the outer function itself in a.
The Proxy pattern might help you:
(function() {
// log all calls to setArray
var proxied = jQuery.fn.setArray;
jQuery.fn.setArray = function() {
console.log( this, arguments );
return proxied.apply( this, arguments );
};
})();
The above wraps its code in a function to hide the "proxied"-variable. It saves jQuery's setArray-method in a closure and overwrites it. The proxy then logs all calls to the method and delegates the call to the original. Using apply(this, arguments) guarantees that the caller won't be able to notice the difference between the original and the proxied method.
Thanks guys the proxy pattern really helped.....Actually I wanted to call a global function foo..
In certain pages i need do to some checks. So I did the following.
//Saving the original func
var org_foo = window.foo;
//Assigning proxy fucnc
window.foo = function(args){
//Performing checks
if(checkCondition(args)){
//Calling original funcs
org_foo(args);
}
};
Thnx this really helped me out
You can override a function using a construct like:
function override(f, g) {
return function() {
return g(f);
};
}
For example:
a = override(a, function(original_a) {
if (condition) { new_code(); original_a(); }
else { original_a(); other_new_code(); }
});
Edit: Fixed a typo.
Passing arbitrary arguments:
a = override(a, function(original_a) {
if (condition) { new_code(); original_a.apply(this, arguments) ; }
else { original_a.apply(this, arguments); other_new_code(); }
});
The answer that #Matthew Crumley provides is making use of the immediately invoked function expressions, to close the older 'a' function into the execution context of the returned function. I think this was the best answer, but personally, I would prefer passing the function 'a' as an argument to IIFE. I think it is more understandable.
var a = (function(original_a) {
if (condition) {
return function() {
new_code();
original_a();
}
} else {
return function() {
original_a();
other_new_code();
}
}
})(a);
The examples above don't correctly apply this or pass arguments correctly to the function override. Underscore _.wrap() wraps existing functions, applies this and passes arguments correctly. See: http://underscorejs.org/#wrap
In my opinion the top answers are not readable/maintainable, and the other answers do not properly bind context. Here's a readable solution using ES6 syntax to solve both these problems.
const orginial = someObject.foo;
someObject.foo = function() {
if (condition) orginial.bind(this)(...arguments);
};
I had some code written by someone else and wanted to add a line to a function which i could not find in the code. So as a workaround I wanted to override it.
None of the solutions worked for me though.
Here is what worked in my case:
if (typeof originalFunction === "undefined") {
originalFunction = targetFunction;
targetFunction = function(x, y) {
//Your code
originalFunction(a, b);
//Your Code
};
}
I've created a small helper for a similar scenario because I often needed to override functions from several libraries. This helper accepts a "namespace" (the function container), the function name, and the overriding function. It will replace the original function in the referred namespace with the new one.
The new function accepts the original function as the first argument, and the original functions arguments as the rest. It will preserve the context everytime. It supports void and non-void functions as well.
function overrideFunction(namespace, baseFuncName, func) {
var originalFn = namespace[baseFuncName];
namespace[baseFuncName] = function () {
return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0)));
};
}
Usage for example with Bootstrap:
overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) {
// ... do stuff before base call
baseFn(obj);
// ... do stuff after base call
});
I didn't create any performance tests though. It can possibly add some unwanted overhead which can or cannot be a big deal, depending on scenarios.
So my answer ended up being a solution that allows me to use the _this variable pointing to the original object.
I create a new instance of a "Square" however I hated the way the "Square" generated it's size. I thought it should follow my specific needs. However in order to do so I needed the square to have an updated "GetSize" function with the internals of that function calling other functions already existing in the square such as this.height, this.GetVolume(). But in order to do so I needed to do this without any crazy hacks. So here is my solution.
Some other Object initializer or helper function.
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons = this.updateToolbarButtons(viewer);
Function in the other object.
updateToolbarButtons = function(viewer) {
var _viewer = viewer;
return function(width, height){
blah blah black sheep I can refer to this.anything();
}
};
Not sure if it'll work in all circumstances, but in our case, we were trying to override the describe function in Jest so that we can parse the name and skip the whole describe block if it met some criteria.
Here's what worked for us:
function describe( name, callback ) {
if ( name.includes( "skip" ) )
return this.describe.skip( name, callback );
else
return this.describe( name, callback );
}
Two things that are critical here:
We don't use an arrow function () =>.
Arrow functions change the reference to this and we need that to be the file's this.
The use of this.describe and this.describe.skip instead of just describe and describe.skip.
Again, not sure it's of value to anybody but we originally tried to get away with Matthew Crumley's excellent answer but needed to make our method a function and accept params in order to parse them in the conditional.