Whoa, hadn't heard that term for some years.
Forget about that strange name and let's call it "Changing the behavior of the original code". The name Monkey-patching basically comes from older times where you needed to do "hot patches (fixes)" or change/inject new functionality, especially into 3rd party code which you depended on, but couldn't change the original. So, you just applied a patch right on the original API and thus changed the behavior of the whole 3rd party code in your codebase.
Monkey-patching is a bad practice and was used also because design patterns like Dependency Injection weren't well known, or even didn't exist.
You can read more about Dependency Injection, in one of my earlier answers:
It is like, in JavaScript, to change or even remove native prototypes or properties on the window object.
The only difference between monkey-patching and overriding; is that in overriding you are making a subclass which doesn't affect the main class and any code using the original code is also not affected. Today you usually make a subclass and just inject it via DI, replacing the framework service with a custom solution for example. In monkey-patching you are changing the original.
Simple example in JS:
const Calc = {
add(a, b) {
return a + b;
}
}
Calc.add(1, 2); // 3
// Monkey-patching
Calc.add = (a, b) => {
return a - b;
}
Calc.add(1, 2); // -1, ow, totally unexpected for other devs
// now also imagine that this Calc.add() has been used
// all around your app, many things might get broken
// Overriding (Which means extending in the first place)
const MyCalc = Object.assign({}, Calc, {
add(a, b) {
return a - b;
}
});
MyCalc.add(1, 2); // -1, ok, this is what we wanted
Calc.add(1, 2); // 3, while the original still works the same way