The term "compiled" used in this context refers to a language that is normally assumed to be translated directly into the language or format native to the machine it is going to be run on. Typical cases include both C and C++. But, understand that both of these languages can also be interpreted. An example of a C interpreter is Pico C, which handles a subset of C.
So, the real question is about environments. A language may be run in a compiled or interpreted environment. A clear distinction between the two cases can be made by the following test:
Does the language possess a "command level" mode
in which forward references are inherently impossible?
Think about this for a moment. A language that is interpreted is reading its specification in real time. A forward reference is to something that does not exist at the time the specification is made. Since machines have not (yet) been endowed with the facility of precognition or time travel (i.e. "time loop logic"), then such references are inherently unresolvable.
If such a level is defined as a mandatory part of the language, then the language may be said to be interpreted; otherwise, it may be said to be compiled. BASIC is interpreted, as some of its commands make direct reference to this layer (e.g. the "list" command). Similarly, the high-level AI language, Prolog, is - by this criterion - an interpreted language, since it also possesses commands that make direct reference to this layer. The "?-" command, itself, is an actual prompt, for instance; but its database commands also refer to and maintain the current state of the command-level layer.
However, this does not preclude parts of an interpreted language from being subject to compilation or to the methods used by compilers, or a compiled language from being run at a command mode level. In effect, that's what a debugger for a language like C or C++ already is, just to give an example.
Most languages that are defined to have a command level layer, normally have to compile to something. In particular, if the language satisfies the following condition, then it is almost mandatory that at least parts of it compile into something:
Does the language possess a facility for user-defined codelets,
for instance: subroutines, functions, lambdas, etc.?
The reason is simple: where are you going to put that code, after it's defined before it's used, and in what format? It is extremely inefficient to save and run it verbatim, so normally it will be translated into another form that is either: (a) a language-internal normal form (which which case, the rest of the language may be considered as "syntactic sugar" for the reduced subset language that the normal forms reside in), (b) into a language-external normal form (i.e. "byte-code"), or (c) a combination of both - it may do language-internal normalization first, before translating it into byte code.
So, most "interpreted" languages are compiled - into something. The only real question is: (1) what they are compiled into, and (2) when/how does the code that it is compiled into run - which is connected to the issue of the above-mentioned "command level" mode.
If the codelets are being compiled into a target-independent form - which is what is normally what is referred to when speaking of "byte code" - then it is not "compiled" in the sense the term is normally taken to refer to. The term compiled normally refers to translation into the language that is native to the machine that the language is being run on. In that case, there will be as many translators are there are types of machines that the language may run on - the translator is inherently machine-dependent.
The two cases are not mutually exclusive. So, a byte-code translator may appear as a stage for native-code compilation, whereby the codelets of an interpreted language are translated and stored directly in the native language of the machine that the language is being run on. That's called "Just In Time" compilation (or JIT).
The distinction is a bit blurry. Even compiled languages, like C or C++, may run on systems that have codelets that are either compiled or even pre-compiled that are loaded while the program is running.
I don't know enough about JS (yet) to say anything definitive about it - other than what can be inferred from observation.
First, since JS code is stored as codelets and is normally run in web clients on a need-to-use basis, it is likely that an implementation of will compile (or pre-compile) the codelets into an intermediate byte-code form.
Second, for reasons of security, it is unlikely that it will compile directly into the native code of the machine it is running on, since this may compromise the security of the machine by providing leaks through which malicious code can be sneaked into and through. That's the "sandbox" feature that browsers are supposed to adhere to.
Third, it is not normally used directly by a person on the other end as a language like Basic or even Prolog is used. However, in many (or even most) implementations it does have a "debug" mode. The browser, for instance, may allow even an ordinary user to both view and edit/debug JS code. Notwithstanding that, there really isn't a command-layer, per se, other than what appears in a web browser itself. Unresolved here is the question of whether the browser allows forward references in JS code. If it does, then it's not really a command level environment. But it may be browser-dependent. It might, for instance, load in an entire web page before ever starting up any JS code, rather than trying to run the JS in real time while a page is loading, in which case forward references would be possible.
Fourth, if the language wants to be efficient in terms of its execution speed, it will have some form of JIT - but this would require stringent validation of the JS compiler itself to ensure that nothing can slip out of the "sandbox" through the JIT into forbidden code on the host machine.
I'm pretty sure there are JS editors/interpreters out there, simply to have a way to develop JS. But I don't know if any references to a command-layer are a mandatory part of the specification for JS. If such specifications exist, then we can call it a bona fide interpreted language. Otherwise, it straddles the border line between the two language types as a language meant to be run in real time like an interpreted language, but which permits compilation directly to the native code of the machine it is running on.
The issue came to a head, for me, recently when I tried to directly translate an old stand-by text-based game (lunar lander) directly from the (interpreted) language FOCAL into C-BC (a C-like extension to POSIX BC whose source is located on GitHub here https://github.com/RockBrentwood/CBC). C-BC, like POSIX BC, is interpreted but allows user-defined codelets, so that implementations of BC normally define a "byte code" language to go with it (historically: this was "dc").
The FOCAL language has a run-time language - which theoretically could be compiled, but also a command-layer subset (e.g. the "library" or "erase" commands) which does not permit forward references that haven't yet been defined, though the run-time language permits forward references.
Unlike GNU-BC, C-BC has goto statements and labels, so it is possible to directly translate the game. However, at the command level (which in a BC file is the top level in the file's scope), this is not possible, since the the top-level of a file's code is - as far as a BC interpreter is concerned - making reference to things that might not yet exist, since the program could just as well have been being entered by a user in real-time. Instead, the entire source would have to be enclosed into { ... } brackets - which gets compiled, in its entirety, to byte-code first, before being executed. So, that's an example of a user-defined codelet, and a text-book example of why most interpreted languages have to have some facility for compiling into something.