I feel like this may be a silly question, but I st...
# cfml-general
I feel like this may be a silly question, but I struggle to use dynamic values in closure functions. It seems like such an obvious use-case, but every bit of documentation or example I can find uses static values in the inner function. I know that I can let the inner function just search through the outer scopes until it finds a variable, but that just doesn't feel right to me. I feel like I should be able to explicitly provide a value to the function, like an argument default. Anyone know if this, or something similar, is possible? e.g. I feel like this should work, but doesn't...
Copy code
    myArray = ['foo','foo','foo','bar'];
    myCriteria = 'bar';
    filteredArray = myArray.filter(function(myArrayVal, criteria = myCriteria){
    	return Arguments.myArrayVal == Arguments.criteria;
What about it doesn't work? I believe the second argument in
is its index.
and the third is the array itself. What happens if you try
function(myArrayVal, i,a,criteria = myCriteria)
Ahh, yes... I see that now, I hadn't noticed that the second argument is the index... should have read the docs more closely. I guess I'm also mixing named and ordered arguments. Your suggestion doesn't work either, but I suppose I shouldn't expect it to... But, what's the alternative? If I'm using this in a function, as I almost always do, then I usually want to filter based on an argument that's passed to the outer function... but I can't access the outer function's arguments scope. So, I have to put it into the outer function's local scope and let the inner function search for it. Just feels inelegant.
I'm not sure what the best answer is. I've ended up doing the "resave argument as local variable" method too.
fwiw, in the closure you're doing a comparison with = and it should be ==.
Well, glad it's not just me then!! Just doesn't feel right having to do that when the variable is already there. I wonder if there's a reference to the outer variables scopre in there somewhere.
Hah! Bloody hell @websolete, you're quite right... I just hacked that together for an example. And now that's fixed, @Myka Forrest's first suggestion does indeed work!! Now if only I didn't have to put two innocuous arguments in there before the dynamic one...
BUT, according to MDN, that's exactly what closures are for.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
Sure, but is there a specific 'outer' scope that we could use? So, if I'm looking for the
scope of the outer function, I could use something like
? That'd be super helpful.
Not that I know of.
Shame... that'd be killer.
Well, thanks guys... at least I know that A) I'm not doing it wrong, and B) There is a way to do what I want, just one that makes the function hella ugly!
CFDocs' closure page doesn't scope its variables, which is a little disappointing to me. https://cfdocs.org/closures
Yeah, and a little confusing when you're coming to closures for the first time... Took me a while to get my head around the concept. Also, I read somewhere that actually scoping the inner function can really increase performance on a large dataset.
Correct. But not really what I wanted to achieve...
This, as suggested by @Myka Forrest, is more like what I was after: https://trycf.com/gist/f5bf5b4fd675ce43b6e1165fcab085a2/lucee5?theme=monokai
The point being that I didn't want to have to specify the
value elsewhere, because in most cases it already exists my outer function's arguments scope. So I'd want to use
myCriteria = Arguments.criteria
...and then I get to scope the value in the inner function too, which feels nicer.
That is an unsupported usage. ArrayFilter supports the following:
function(item [,index, array]){}
Where this stuff is powerful is that you can compose filters and pass them in as functions. Something like this: https://trycf.com/gist/a0410bec470b54d87d52eeee0599aad7/lucee5?theme=monokai
So the criteria is being passed around with the function - it is enclosed in the closure.
Your second link is the same as the first, have you saved changes?
hmm - maybe didn't copy correctly - in the meantime here is the Javascript version for comparison https://jsbin.com/xiqidekaqo/edit?js,console
Wow... ok, that's interesting!
It does seem like extra work, but it's very elegant...
It's not really more work, but it is a shift in thinking and very powerful.
Well I mean, calling the
function each time is similar to just pushing the criteria into the local scope, which I was trying to avoid... but I really like the code-zen of it, and I'd imagine it has better performance than searching the outer scope.
I appreciate that anyway... I've seen similar examples but I've not really been able to grasp it, passing the function to the function. Now I have that in the context of what I was trying to do, it makes more sense.
I find it quite fun doing things like that. There are others on here that are way better at it than I am.
array filter in Lucee passes in (item, idx, srcArray )to the closure, I need to update the docs
👍 1
sorry - got caught up in work. If you think it's too much typing you can write it using arrow functions - I used the longer syntax in my previous example as it's easier to grok if you're not familiar with arrow functions. This is the same with arrow functions: https://trycf.com/gist/df87e20498aa6b02d7986dd7c8c7a729/lucee5?theme=monokai