◆ 複数監視している場合にどの監視対象の変更かを知るときは MutationRecord.target を見る
◆ IntersectionObserver などと違って unobserve がないので全解除+必要なものを再追加が必要

MutationObserver

<!doctype html>
<div id="a"><button>btn</button></div>
<div id="b"><button>btn</button></div>
<div id="c"><button>btn</button></div>

<script>
window.addEventListener("click", eve => {
if(eve.target.tagName === "BUTTON"){
eve.target.after("x")
}
})
</script>

<script>
const observer = new MutationObserver(function (...args) {
console.log(this, args)
})

const option = {
characterData: true,
subtree: true,
childList: true,
}

for(const selector of ["#a", "#b", "#c"]){
observer.observe(document.querySelector(selector, option))
}
</script>

という感じで使えます
2 つ目の script タグが MutationObserver を設定してる部分です
変更があったときに行う処理をコンストラクタに渡して 監視対象を observe メソッドで追加します
複数追加することもできます
対象ごとに監視ルールを変えることも出来ます
今回は #a, #b, #c それぞれの中での要素の追加削除などを監視するようにしてます

1 つ目の script タグではボタンを押したら要素を追加するようにしています
ボタンを押すと #a, #b, #c の内側の要素が更新されるので MutationObserver に渡した関数が呼び出されます

設定した関数が呼び出されるときの this は MutationObserver のインスタンスです
上の例では observer 変数に入ってるのと一緒です
引数は変更されたものの配列と MutationObserver のインスタンスです
2 つ目の引数でも参照できるのでアロー関数にして this を受け取れなくしても大丈夫です

どの監視対象が更新されたの?

本題の複数を監視対象にしたときについてです

this に bind されてるのかなと思ってたのですが this は MutationObserver のインスタンスなので わからないのかもと思いましたが 探しているとそれぞれの MutationRecord の target プロパティに入っていました
上のコードでいうと args[0] を console.log したものです

Array(1)
0:MutationRecord
addedNodes:NodeList [text]
attributeName:null
attributeNamespace:null
nextSibling:null
oldValue:null
previousSibling:button
removedNodes:NodeList []
target:div#c
type:"childList"

unobserve がない

IntersectionObserverResizeObserver には observe で追加したものを個別に解除する unobserve メソッドが用意されています

しかし MutationObserver にはありません
ついでに PerformanceObserver にもありません

disconnect メソッドがありますが 使うと全部を解除してしまいます

なので 解除が必要になると自力でやる必要が出てきます
一度全てを解除して 必要なものだけを再追加します

それも面倒なのでメソッドを作りました
登録済みの target と option を知るすべがないので observe メソッドも上書きしています

const original = MutationObserver.prototype.observe
MutationObserver.prototype.observe = function(target, option){
const result = original.call(this, target, option)
this.targets = this.targets || []
this.targets.push([target, option])
return result
}

MutationObserver.prototype.unobserve = function(target){
this.targets = this.targets || []
const idx = this.targets.findIndex(e => e[0] === target)
if(idx >= 0) this.targets.splice(idx, 1)
this.disconnect()
for(const [target, option] of this.targets){
original.call(this, target, option)
}
}

他には 登録するメソッド内で有効無効をチェックして内部の処理をするかを分岐させておいて 解除するときは unobserve の代わりにそのフラグを操作することもできます
ただこれだと登録されたものがずっと残り続けるので 大量に追加削除を繰り返すようなページだとメモリ消費が増えるのでやめたほうが良いと思います