bexphones Posted August 10, 2017 Share Posted August 10, 2017 hi, i'm happy to play now with short code and modularize them together. What saves time and readability ! But in this case i don't see what it's possible to do with the function foreach. Is it possible to use foreach like this config with a trick in the hide_weapon_internal ? //normal function who works if(dalle_moving[0]){ for (var j = 0; j < dalle_moving.length; j++){ dalle_moving[j].hide() } } //////////////////////////////////////////////////////////////////////////////////// //NOW WITH FUNCTIONAL PROGRAMATION function is_exist(obj){ if(typeof obj != "undefined"){ return true; }else{ return false; } } function foreach(table,action){ for(var i=0;i<table.length;i++){ action(table[i]); } } ////////////////////////////////////////// var hide_enemy=function(obj){ is_exist(obj[0]) && foreach(obj,obj.hide) } hide_enemy(dalle_moving) ////////////////////////////////////////// //obj.hide don't works because i must say action(obj[i].hide()) //is there a trick to do that with the function foreach as she is ? i have the feeling that 's possible ....no? Link to comment Share on other sites More sharing options...
ldd Posted August 11, 2017 Share Posted August 11, 2017 (edited) Couple of quick pointers: 1) Avoid using function names that closely match reserved words or already existing native code. Array.prototype.forEach already exists, so avoid names like 'forEach' 2) is_exist sounds weird, and can be simplified: const is_defined = (obj) => obj !== undefined just keep in mind that there are better check than this, and consider cases like when obj is null, etc (be careful when doing comparisons and read on the topic) 3) you are trying to use a method that can be accessed by each individual item in an array. If it is always hide, you can simply do const hide_enemies = (enemies) => enemies.forEach( (enemy) => enemy.hide() ); or if you need to call other methods, just use a string to represent a possible method name const hide_enemies = (enemies, actionString) => enemies.forEach( (enemy) => enemy[actionString]() ); In old-school syntax, you could write function hide_enemies(enemies){ enemies.forEach( function(enemy){ return enemy.hide(); }); } If you tell me more about why you are checking is_exist(obj[0]), we could probably avoid awkward checks. Finally, you could check out this quick guide to Array functions that may provide you with more information. Edited August 11, 2017 by ldd added a link to provide more information Link to comment Share on other sites More sharing options...
bexphones Posted August 11, 2017 Author Share Posted August 11, 2017 hi, thanks very much for these explanations. your quick guide for array is easy to understand , thanks again 9 hours ago, ldd said: If you tell me more about why you are checking is_exist(obj[0]), we could probably avoid awkward checks. i use an array to stock my objects. var enemy={} next i create the enemy i need for each levels with a prototype and methods. enemy[0]=new _proto_enemy() each level have different number of enemies. level 1 have for example 2 enemies and level2 > 4, etc.... i check if enemy exist in an update method to each levels to apply method on hem like collisions with another object (player), add in the game(game.add.existing(enemy[0]), debug hem. finally to loop trough and apply also method but with other object or methods. Link to comment Share on other sites More sharing options...
bexphones Posted August 12, 2017 Author Share Posted August 12, 2017 //WHY THIS NOT WORKS ? function hide_enemies(obj,action){ obj.forEach(function(item){ return item.action() }) } //WHY THIS WORKS ? function hide_enemies(obj){ obj.forEach(function(item){ return item.hide() }) } hi again could you explain why it doesn't work for the example 1 ? how must i declare "action" ? if i run hide_enemies(dalle,hide) it return the error item.action is not a function. for obj exist you have true, it's not necessary to invoke him, hide_enemies() works without because we make foreach. Thanks. PS : i'm not yet ready for this : const hide_enemies = (enemies, actionString) => enemies.forEach( (enemy) => enemy[actionString]() ); because i need to console.log sometimes what went wrong and in this case it's difficult. Link to comment Share on other sites More sharing options...
mattstyles Posted August 12, 2017 Share Posted August 12, 2017 On 11/08/2017 at 1:29 AM, ldd said: 1) Avoid using function names that closely match reserved words or already existing native code. Why? There's no problem with this. Extending built-in prototypes is generally frowned upon with good arguments to back it up still, but `forEach` is not a reserved word, its just an instance member on a built-in, of which there are hundreds. If I built an event emitter should I not call one of its methods `addEventListener`? On 11/08/2017 at 1:29 AM, ldd said: 3) you are trying to use a method that can be accessed by each individual item in an array. If it is always hide, you can simply do const hide_enemies = (enemies) => enemies.forEach( (enemy) => enemy.hide() ); I think the whole point of bex creating a custom for each function is for performance. (for reference, I'd do it exactly the same and just use [].forEach, at least at first). 28 minutes ago, bexphones said: //WHY THIS NOT WORKS ? function hide_enemies(obj,action){ obj.forEach(function(item){ return item.action() }) } //WHY THIS WORKS ? function hide_enemies(obj){ obj.forEach(function(item){ return item.hide() }) } There are a couple of ways of invoking a method of an instance: var speaker = { prefix: '::', say: function (message) { console.log(this.prefix, message) } } // Using dot notation to access the method speaker.say('hello!') // $ :: hello! // Using square brackets and strings speaker['say']('world!') // $ :: world! In your examples you're using the dot notation to invoke a function, in your first example you're trying to invoke `action` of `item` (item.action()), which probably doesn't exist. If you want to invoke a dynamic method of an object then using the square brackets notation would work: function callForAllEnemies (obj, method) { obj.forEach(function (item) { return item['methods]() }) } I've renamed it as it is now a generic helper to call a method for all enemies, if you explicitly call the function hide_enemies then you may as well explicitly call item.hide(). Note that your custom foreach function can do this as well with some small changes: function foreach (list, action) { let i = list.length while (--i) { list[i][action]() } } (As I'm assuming this function is for perf I've also used a negative counting while list, which I think is still generally the fastest array iteration method) You can swap things around and go more generic with things too if you wanted to get in to refactoring a little: const all = method => list => { let i = list.length while (--i) { list[i][action]() } } const hideAll = all('hide') const showAll = all('show') hideAll(enemies) All sorts of ways to solve problems. bexphones 1 Link to comment Share on other sites More sharing options...
bexphones Posted August 12, 2017 Author Share Posted August 12, 2017 9 minutes ago, mattstyles said: You can swap things around and go more generic with things too if you wanted to get in to refactoring a little: const all = method => list => { let i = list.length while (--i) { list[i][action]() } } const hideAll = all('hide') const showAll = all('show') hideAll(enemies) i start with lua langage + after i learn javascript ++ and now définitively i love FP +++ Link to comment Share on other sites More sharing options...
bexphones Posted August 12, 2017 Author Share Posted August 12, 2017 maybe yet a question how do you do to perform that ? function foreach(tableau,action){ for(var i=0;i<tableau.length;i++){ action(tableau[i]); } } const actions = console.log(this.name) && console.log(this.number) foreach(dalle,actions) and this also ? function test_args(arg1,arg2){ console.log(arg1) console.log(arg2) } test_args("koala","cat") //koala, cat test args("koala") //return only koala without errors Link to comment Share on other sites More sharing options...
mattstyles Posted August 13, 2017 Share Posted August 13, 2017 You want to specify multiple actions to your function? There are quite a few ways to achieve this, the simplest is just to ensure that `actions` is an array and just iterate over that array of functions calling them, but, you could go a different route with variadic arguments: function run (...args) { const data = args.shift() let i = data.length while (--i >= 0) { args.forEach(fn => fn(data[i])) } } const arr = [1, 2, 3] run(arr, i => console.log(i)) // 3 9 2 4 1 1 Something like this should do what you want, although there are a few ways to skin this cat, see the MDN resource on function arguments. Note that this uses the spread syntax, you can achieve the same with `Array.from(arguments)`, which is detailed on the mdn resource. All this does is grab the dataset from your list of arguments and then iterate over every other arguments calling it, you could do the same simply by insisting your actions parameter is an array. Link to comment Share on other sites More sharing options...
bexphones Posted August 14, 2017 Author Share Posted August 14, 2017 I did not know that we could write this like that ? args.forEach(fn => fn(data[i])) fn > reserved word for function... Yet one thing more learned thank you. Link to comment Share on other sites More sharing options...
mattstyles Posted August 14, 2017 Share Posted August 14, 2017 Yeah, fn isn't reserved, list of reserved words here, you could also use `func` but, rather than the generic word `function` we should probably be a bit more explicit by naming this function by what it does, in this case, maybe `iterator` would be more suitable and more useful for the next developer (or future self) to be able to quickly understand what the code does. Note that arrow functions can have an implicit return if you don't create an explicit function body, so, for example: const map = fn => list => list.map(fn) const square = i => i * i const squareList = map(square) const arr = [1, 2, 3] squareList(arr) // 1, 4, 9 There is so much going on here, and the reuse it fantastic. `square` could be rewritten as: function square (num) { return num * num } but arrows functions make this more succinct and even though we haven't explicitly used the `return` syntax we are in fact returning the square of the argument given to the function. Similarly we do the same thing for `map` where we return the output of `list.map(fn)` and pass the function `fn` to each entry in the list. This sort of pattern is fantastic for reuse as to create functionality that doubles numbers in a list we can simply add a doubling function and then create a new function which can map that over an array: const double = i => i * 2 const doubleList = map(double) doubleList(arr) // 2, 4, 6 We could have implemented doubling and squaring with just 2 functions, but, those functions would not be minimal, each would have to implement the number operation (doubling or squaring) AND implement the mapping algorithm (in this case just calling array.map, but, you can imagine as we move away from trivial examples this could get more complex). By extracting the mapping functionality our `double` and `square` functions deal with just one job, they are then consumed by a function that handles mapping. This has so many benefits: * As each function is minimal and deals with a single concern it is far far easier to test these functions and test them comprehensively. * We test just one thing, with the naive solutions we'd also be implicitly testing our map functionality, which is sub-optimal, we want to test that stuff explicitly and thoroughly. * If we change how we iterate over a list later (for example, maybe our lists get implemented as linked-lists or as objects, where array.map is no longer viable), we ONLY change our `map` function, everything else stays the same. This is golden, but as we've already written comprehensive tests for these functions we know that our changes don't break our library/framework/application. * We can name functions more easily as they do just one thing. Important for debugging and more important for any developers wanting to reuse our code (including our future selves when we come back to this stuff x months from now and have forgotten what we did back then!). bexphones 1 Link to comment Share on other sites More sharing options...
bexphones Posted August 14, 2017 Author Share Posted August 14, 2017 Waouh love the way you that you explain ! mattstyles 1 Link to comment Share on other sites More sharing options...
bexphones Posted August 17, 2017 Author Share Posted August 17, 2017 since i have print Professor Frisby's, i 'm reading it and it's very interesting thanks. Still a question...it's interesting becausew with fp i must re-learn the basic; this function return effectively false : var debub_position=true is_clic_valid =(count,f) =>{ let condition = (count) => { switch(count){ case 0: return true case 1: return true case 2: return true default: return false } } if ( condition == true && f == true ){ return true }else{ return false } } let ex=is_clic_valid(4,debug_position) console.log(ex) // return false But in this case it's true because i change this line however i think it's correct... (condition && f )? true : false var debub_position=true is_clic_valid =(count,f) =>{ let condition = (count) => { switch(count){ case 0: return true //break case 1: return true //break case 2: return true //break default: return false //break } } ( condition && f ) ? true : false } let ex=is_clic_valid(4,debug_position) console.log(ex) // return true what 's my mistake ? think also that break is not necessary in this case ? no ? Link to comment Share on other sites More sharing options...
ldd Posted August 18, 2017 Share Posted August 18, 2017 You are making the right type of mistakes! (which is good) try this: let fn = ()=>false; console.log( fn == true && true, fn && true); a function is truthy, but when compared to true with ==, it will return false. This seems voodo magic until you read the specs[0][1] ps: there is a difference between fn, and fn(), just like in your example. You'd need `condition(count)` to make it work [0] http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 [1] http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5 Link to comment Share on other sites More sharing options...
bexphones Posted August 18, 2017 Author Share Posted August 18, 2017 ok thanks, i understand with a classical if but with a ternary operator what's the good syntax ? (condition(count) && f) ? true : false Link to comment Share on other sites More sharing options...
bexphones Posted August 19, 2017 Author Share Posted August 19, 2017 because in this case this snippet return false and i if i do : console.log(condition(count)) // > true console.log(f) // > true // so true && true must return true ??? Link to comment Share on other sites More sharing options...
bexphones Posted August 20, 2017 Author Share Posted August 20, 2017 another mistery... function foreach(tableau,action){ for(var i=0;i<tableau.length;i++){ action(tableau[i]); } } stop_tw = (tw_name,f,obj) => { if(f){ obj.alpha=0 //foreach(tw_name,game.tweens.remove) > don't works !!!! for(var i=0;i<tw_name.length;i++){ // works but it's the same like foreach! game.tweens.remove(tw_name[i]) } f=false } } Link to comment Share on other sites More sharing options...
bexphones Posted August 22, 2017 Author Share Posted August 22, 2017 nobody ? first case : //first console.log(condition(count)) // > true console.log(f) // > true //function 1 if (condition(count) && f){ return true }else{ return false } //return logically true ok! //function 2 but strange result (condition(count) && f) ? true : false //return false ... WHy ? second case : //function 1 > works stop_tw = (tw_name,f,obj) => { if(f){ obj.alpha=0 for(var i=0;i<tw_name.length;i++){ // works but it's the same like for_each! game.tweens.remove(tw_name[i]) } f=false } } //function 2 > don't works and i don't understand why because it's the same than function 1 function for_each(tableau,action){ for(var i=0;i<tableau.length;i++){ action(tableau[i]); } } stop_tw_for_each = (tw_name,f,obj) => { if(f){ obj.alpha=0 for_each(tw_name,game.tweens.remove) //> don't works !!!! f=false } } Link to comment Share on other sites More sharing options...
mattstyles Posted August 22, 2017 Share Posted August 22, 2017 sorry, don't think I'm going to be too much help: 1st case: no idea, a ternary and an if/then should be the same, you are `return (clause) ? a : b` right? or making an assignment? Because ternaries aren't really for code branching, but for assignment. 2nd case: Still sounds like a binding issue, where the function loses its scope, or it gets altered or something, is the error that somewhere inside game.tweens.remove it can't find a property it is expecting? Link to comment Share on other sites More sharing options...
bexphones Posted August 24, 2017 Author Share Posted August 24, 2017 hi mattstyles, you are alright for ternary operator (condition(count) && f) ? true : false //don't work let cond = condition(count) (cond && f) ? true : false //works for the 2nd case, i have found my error. i start an another post about that. on the second post maybe you could give me some advice on my beginnings of functional programming... Link to comment Share on other sites More sharing options...
Recommended Posts