Pense nas variáveis livroAtual e livroMenor como uma cópia dos dados da array de objetos, dessa forma quando você atribui livros[i] = livroMenor essa informação não é perdida porque você já salvou este dado na variável livroAtual que será utilizada na atribuição livros[menorValor] = livroAtual.
for (let atual = 0; atual < livros.length; atual++) {
let menor = menorValor(livros, atual);
let livroAtual = livros[atual];
// livroAtual = livros[atual] = {nome: "JavaScript, preco: 25}
let livroMenorPreco = livros[menor];
// livroMenorPreco = livros[menor] = {nome: "PHP", preco: 15}
livros[atual] = livroMenorPreco;
// livros[atual] = livroMenorPreco = {nome: "PHP", preco: 15}
livros[menor] = livroAtual;
// livros[menorValor] = livroAtual = {nome: "JavaScript", preco: 25}
}
Dessa forma você consegue trocar a posição dos dados sem perdê-los ou sobrescrevê-los.
No primeiro loop com atual = 0, o livro de PHP é colocado no índice 0 e o JavaScript no índice 1, e no próximo loop do for ele começará no índice 1, que é exatamente onde está o livro de JavaScript.
Faz sentido?