Basically, safe code is automatically managed to get rid of memory leaks [0], dangling pointers [1], null pointer dereferencing [2], race conditions [3], and many other memory management bugs.
You don't encounter any of these in JavaScript because it's a managed language, meaning there's a garbage collector [4] that looks after all your memory allocations.
Contrary to the managed languages, C & C++ are unsafe and "native" (meaning that they're very close to the hardware level) - it's a wild land where you manage memory manually yourself. If you miss a single deallocation, you're left with a memory leak. If you deallocate a memory region twice, you have a double free situation [5]. So you have to be very cautious when writing code in C & C++. There are many techniques to make it easier (e.g. smart pointers [6]), but not all developers use them.
Rust takes the middle ground: it combines safety with unsafety by using a know-how affine type system with a borrow checker, which allows values/variables to have only one owner. This system has properties of both managed and unmanaged code. "Unsafe" code in the context of Rust means that you consciously turn off the borrow checker, leaving on your own and managing memory deallocations manually, as in C. That makes it possible to interface your Rust code with the native code, at the cost of making you prone to all errors and bugs that are listed above. So it's a good thing to minimize usage of unsafe code, to allow the Rust compiler to check your code for safety.
[0] https://en.wikipedia.org/wiki/Memory_leak
[1] https://en.wikipedia.org/wiki/Dangling_pointer
[2] https://en.wikipedia.org/wiki/Null_pointer#Dereferencing
[3] https://en.wikipedia.org/wiki/Race_condition
[4] https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...
[5] http://stackoverflow.com/questions/21057393/what-does-double...