Having done a lot of reflection in both JS and C# (well, .NET really, it's a library and runtime feature, not a language feature), I think I can confidently say that .NET is light years ahead of JS when it comes to reflection. I don't think I've seen a system better than .NET's. Because of the way it is built, you can still write type safe code. That's impossible to do in JS.
I think people forget that, in JS, the types still exist. Just because it's not statically typed doesn't mean you don't have to think about types and what types are appropriate for given scenarios.
With JS, it's impossible to tell just from inspecting a reference to a function what it expects from you and what you can expect to give back. You have the length property to tell you the number of arguments and that's it. Of course, that's assuming it's not using a variadric arguments pattern, in which case the length value only tells you the minimum number of parameters expected, but not that more are possible.
Even if you can make reasonable assumption about the number of parameters, you won't be able to tell at all what types the function expects for those parameters. Want to list all the functions in a class that take two numbers and return a different number? Can't do it.
But still, if you could make reasonable assumptions about the type of things that go in and out of the function, you won't know how to even call the function. Does the function expect to be called as a method of a class? Does it expect to be called as a static function? The best you can hope for is to toString the function and check if the source includes the word "this". Here's hoping it's one written in JS itself and not one that is implemented internally in the browser.
Now before anyone says "why would you ever need anything like that?", it's an absolute necessity for building any sort of user-driven or data-driven reporting system. You need to be able to tell when your data set matches the functions you want to apply to them, at run-time, because the data isn't available at design-time. It's the classic reflection use case.
As far as I'm concerned, safety-guaranteed reflection is impossible in JS, unless you throw away JS functions almost completely and create your own Functor class with all the extra type information that you would need.