Здесь, на мой взгляд, стоит понять следующее:
let o = {
message: 'Начальное значение'
};
Это создание объекта в памяти и переменной, которая на этот объект ссылается.
f(o);
Здесь мы передаем в метод именно ссылку на объект.
function f(o) { ... }
Ссылка, которую мы передали продублировалась параметром. Т.е. снаружи метода, у нас есть переменная и внутри метода у нас есть параметр, которые ссылаются на один и тот же объект. Но, это две независимых ссылки, просто в примере они названы одинаково, что может сбить с толку. И при этом объект в памяти как был один, так и остался
o.message = "Изменено в f";
Тут мы, используя ссылку-параметр, меняем значение поля объекта.
o = {
message: "Новый объект!"
};
Здесь мы создали второй объъект и присвоили ссылку на него нашему параметру "о". Т.е. теперь у нас 2 объекта в памяти, ссылка-параметр ссылается на новый(второй) объект, ссылка-переменная снаружи, не менялась и ссылается на старый(первый) объект.
Теперь, когда вы в методе обращаетесь к объекту через параметр, вы будете работать со вторым объектом, никак не влияя на первый. А когда вы после метода обращаетесь к объекту через ссылку-переменную, вы работаете с первым объектом.