Challenge Seek and Destroy has an issue.
User Agent is: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
.
Please describe how to reproduce this issue, and include links to screenshots if possible.
My code:
function isequal(value) {
return value !== this;}
function destroyer(arr) {
filtered = arguments[0];
for (i=1; i<arguments.length; i++){
filtered = filtered.filter(isequal,arguments[i]);
}
return filtered;
}
destroyer([1, 2, 3, 1, 2, 3], 1);
Although my code above returns all the correct output and passes all the tests, the system will not let me proceed to the next challenge. It marks all the tests as failed. Seems to be a bug.
This is a weird one. The value being returned as filtered
from the function does not match what is shown in the output.
The code is incorrect as can be verified by running it with an added console.log(filtered);
before the return filtered;
line, but then why does it show the correct value in the output section?
It may be some strange effect of the arguments object within the filter
call, or of this
within the callback function.
Still trying to get to the bottom of this but I fear I'm not familiar enough with the code running process behind the scenes. Replacing the function call in the code above with a variable assignment and then logging the variable to the console like this:
function isequal(value) {
return value !== this;}
function destroyer(arr) {
filtered = arguments[0];
for (i=1; i<arguments.length; i++){
filtered = filtered.filter(isequal,arguments[i]);
}
return filtered;
}
var result = destroyer([1, 2, 3, 1, 2, 3], 2);
console.log("Result: " + result);
results in these two lines printed to the console:
Result: 1,2,3,1,2,3
Result: 1,3,1,3
The first is seemingly the value used by the tests, and the second what is printed to the output for the user to see. Notably the first is also what is logged in an external environment like repl.it or Node locally, with the second omitted entirely.
FCC gurus please chime in 😄
My go at seeing what is going on:
function isequal(value) {
return value !== this;}
function destroyer(arr) {
filtered = arguments[0];
for (i=1; i<arguments.length; i++){
filtered = filtered.filter(isequal,arguments[i]);
}
console.log(`Filtered by: ${arguments[1]} \n Before: ${arguments[0]} \n After: ${filtered}`);
return filtered;
}
destroyer([1, 2, 3, 1, 2, 3], "My Test");
Console.log();
Filtered by: My Test
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3
Filtered by: My Test
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3
Filtered by: 2
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3
Filtered by: 2
Before: 1,2,3,5,1,2,3
After: 1,2,3,5,1,2,3
Filtered by: 2
Before: 3,5,1,2,2
After: 3,5,1,2,2
Filtered by: 2
Before: 2,3,2,3
After: 2,3,2,3
Filtered by: tree
Before: tree,hamburger,53
After: tree,hamburger,53
So the campers test case is running twice?
I logged value
and this
in isEqual
and that seemed fine.
@BKinahan as for your Result
: ¯\_(ツ)_/¯
that's just weird
Someone told me to insert this line: "use strict" and now it works in
repl.it
I have no idea why that changes the behaviour: See below:
function destroyer(arr) {
function isequal(value) {
"use strict";
return value !== this;}
var filtered = arguments[0];
for (var i=1; i
}
return filtered;
}
destroyer([1,2,3,4,5],2,3);
On Sat, Jul 23, 2016 at 11:10 AM, Stuart Taylor [email protected]
wrote:
My go at seeing what is going on:
function isequal(value) {
return value !== this;}function destroyer(arr) {
filtered = arguments[0];
for (i=1; ifiltered = filtered.filter(isequal,arguments[i]);
}
console.log(Filtered by: ${arguments[1]} \n Before: ${arguments[0]} \n After: ${filtered}
);
return filtered;
}
destroyer([1, 2, 3, 1, 2, 3], "My Test");Console.log();
Filtered by: My Test
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3Filtered by: My Test
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3
Filtered by: 2
Before: 1,2,3,1,2,3
After: 1,2,3,1,2,3Filtered by: 2
Before: 1,2,3,5,1,2,3
After: 1,2,3,5,1,2,3Filtered by: 2
Before: 3,5,1,2,2
After: 3,5,1,2,2Filtered by: 2
Before: 2,3,2,3
After: 2,3,2,3Filtered by: tree
Before: tree,hamburger,53
After: tree,hamburger,53—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/FreeCodeCamp/FreeCodeCamp/issues/9851#issuecomment-234706264,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATg8c5YSo0334kWXp6wo1qP48apQWQc9ks5qYcxqgaJpZM4JS09B
.
ICT Consultant
Tel: +256782457826
Someone told me to insert this line: "use strict" and now it works in repl.it
I have no idea why that changes the behaviour. Can some one explain? See below:
function destroyer(arr) {
function isequal(value) {
"use strict";
return value !== this;}
var filtered = arguments[0];
for (var i=1; i
}
return filtered;
}
destroyer([1,2,3,4,5],2,3);
"use strict";
alerts the developer to bad syntax that would normally be parsed regardless in normal
mode, which is why you had to declare filtered
with a var
in your working code.
And apparently it does things to this
in isequal()
. But I still struggle with this
so can't offer you any more.
One issue though, I though all of the campers code ran in a global "use strict";
cc/ @FreeCodeCamp/issue-moderators
I also tried starting with "use strict" at the very beginning of the code,
and it worked. Very confusing. See below:
"use strict";
function destroyer(arr) {
function isequal(value) {
return value !== this;}
var filtered = arguments[0];
for (var i=1; i
}
return filtered;
}
destroyer([1,2,3,4,5],2,3);
On Sat, Jul 23, 2016 at 1:28 PM, Stuart Taylor [email protected]
wrote:
"use strict"; alerts the developer to bad syntax that would normally be
parsed regardless in normal mode, which is why you had to declare filtered
with a var in your working code.And apparently it does this to this in isequal(). but I still struggle
with this.—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/FreeCodeCamp/FreeCodeCamp/issues/9851#issuecomment-234711233,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATg8czVsmJjBngeL9orgcHWUYGYWd-E3ks5qYey6gaJpZM4JS09B
.
ICT Consultant
Tel: +256782457826
interesting comments... Seems even more of a problem, then I thought. Yes, nlubega, I see your code does work, I get correct answers individually on everything but they are not accepted by my system to pass the test. However mine say's not to add the "use strict" with your code.
The one thing I can tell you is "use strict" helps in variable typo error, since javascript is known as a loose script writing programming language. You can actually create variables on the "fly". i.e.
say you have:
var myVar = "abc";
and later you say something like
myvar = "123"; //notice the V in var is lower vs upper. i.e. this is technically a different variable.
Since I never created a:
var myvar;
or planned for it you would think it would crash, but I've heard javascript will allow such.
by typing "use strict" at the top of all your code, it causes this type of error to crash (i.e. you can find and fix your mistake.
I've read in multiple places this mode is highly encouraged in all your normal writings... Not sure however if its needed in these lessons. Up to now I never have used it for passing these lessons.
Also, to point out, i've heard the next version of Javascript which is now a year old, I think its called "harmony", makes the "use strict" mode standard now. But for now I'm still using it in anything I write, less these lessons.
My simple error that brought me into this room, may be the root of the problem?
If I just run the test immediately... without typing in any of my own code whatsoever and/or
just hit reset, then run.
The parameters within destroyer get spit back as just the internal [array] and no destroyer digits.
i.e. destroyer([1,2,3,4,5],2,3); would come back as just [1,2,3,4,5]. This is odd? as I would expect
to see the exact same info, returned to me. (without the destroyer digits sent over to me as parameters any code I write can never come back right)
Not sure if that helps find the actual problem.
Hmm I may see the reason too its not working... the very next lesson show this.
function getIndexToIns(arr, num) {
// Find my place in this sorted array.
return num;
}
getIndexToIns([40, 60], 50);
An almost identical setup but notice that parameters taken in have BOTH (arr, num)
whereas in this problem you only take in (arr). "function destroyer(arr)"
Check this out. It turns out isequal
changes arguments[i]
into a Number object, so the value !== this
means value
is compared to an object, and so it always returns true
.
I ran the same code above, without "use strict"
and it ran fine. However, this code also works, passes all tests, and lets me proceed to the next challenge; I just wanted to use ES6 for the spread operator on arguments
:
//jshint esversion: 6
function isFoundInArray(value) {
return this != value;
}
function destroyer(arr) {
// Remove all the values
var args = [...arguments];
var arrayToDestroy = args.shift();
//since we shift()-ed args, which is a destructive operation, it now is an array with just the values to filter by.
for (var i = 0; i<args.length;i++) {
var filterBy = args[i];
//argument passed to filter() after callback sets 'this' in the callback function.
arrayToDestroy = arrayToDestroy.filter(isFoundInArray,filterBy);
}
return arrayToDestroy;
}
destroyer([7,8,9,10], 8, 9);
I'm having issues with this challenge as well.
I want to work on this.
I read CONTRIBUTING.md, cloned and ran freeCodeCamp on my computer but I need some help. Where should I start? Which files or directories are the potential sources of this issue?
@nsgonultas thanks for your interest in contributing! The best place to get contributing help is to visit the Contributors chat room.
I think this issue is too hard for me. It's okay if anyone wants to take it, I'm not working on this anymore.
I'll take a stab at it
Okay, I think I figured it out. The reason why it's not working is because the "arguments" object is getting the arguments from the callback, not the destroyer function. Create a variable to enclose the values in the "arguments" object. That's why jdhine's code works, because he put the arguments into a variable, and then the callback was able to use the "arguments" object that you actually need.
Why the code works with 'use strict': "arguments objects for strict mode functions store the original arguments when the function was invoked." (MDN)
I've delved into this issue a bit more. Going from @elisecode247's and @kevcomedia's findings, here's what I found.
The second argument of Array.prototype.filter
is the optional thisArg
. If you pass an object, it will set this
inside the callback. Without 'use strict';
, this can only be an object. If what's passed as the thisArg
isn't an object, it will set this
to an empty object. With 'use strict;'
, this
is no longer forced to be an object. It can now be set to a number. My source is Elise's MDN article, a bit further down.
@Bouncey I think this issue can be closed, as it was a code problem (a difficult one though). I'd love to hear your thoughts though. Maybe the description should be altered in some way to make people aware of this problem.
@FreeCodeCamp/moderators As I said in my comment above, this is a code issue. It's one that's easy to make and hard to detect though. What should we do about this?
@systimotic I was all for closing the issue and treating it as an edge case. But now there is an other issue with near identical code. Is this on StackOverflow or something?
How would you suggest we adjust the instructions?
I read this whole thing twice now and i still dont get it
😕
As I said before, this mistake is easy to make and hard to detect. It's quite complicated, so it makes sense that @parisclinkscales does not understand what's going on.
I have so much trouble coming up with a solution I have rewritten even just this comment at least four times. What it boils down to:
I can't come up with a solution that won't confuse some users.
@systimotic @parisclinkscales @Bouncey This is an easy-to-read solution:
function destroyer(arr) {
var args = [];
for(var i in arguments) { // gets all arguments and save them for the callback
args.push(arguments[i]);
}
function isEqual(element){ // when you create a new function, a new arguments object is created
for (var j = 1; j < args.length; j++){
if(element == args[j]){
return false;
}
}
return true;
}
return arr.filter(isEqual);
}
And cleaner solution:
function destroyer(arr) {
return arr.filter(function(value) {
return !this.includes(value);
}, Array.prototype.slice.call(arguments, 1));
}
@parisclinkscales
I looked at your code, and this is the fix:
function seeker (value){
return value !== this.valueOf(); // 'this' is an object, so you need to call valueOf method
}
function destroyer(arr) {
var filtered = arguments[0];
for (var i = 1;i < arr.length;i++){
filtered = filtered.filter(seeker,arguments[i]);
}
return filtered;
}
@elisecode247 Thank you for those suggestions. I believe the main problem here doesn't lie in having a correct solution, rather finding a way where campers won't go with the incorrect, hard to detect solution.
One other solution I just found is to change the comparative operator from !==
to !=
If you are not using a strict comparison operator it will work.
Is this still blocked
? /cc @Bouncey @systimotic
Thanks for waking us up @raisedadead 🙂
I think Stuart may have blocked this originally because he was waiting for my feedback.
To summarize, this mistake is easy to make and hard to detect. I can't come up with simple way to prevent this from happening without causing confusion.
I'll change this to discussing, any input on what we could do would be very much appreciated.
Just went through, the thread, I think this should be closed as an edge case with the camper's code. I agree detecting such code is costly, and adding any instructions will cause confusion to users.
Closing. Feel free to continue the discussion or re-open, but in my honest opinion, this should be left as it is.