extends and YAML anchors both reuse configuration and combine differently. extends merges hash keys recursively, so a job extending a base that defines variables: A: 1 and adding variables: B: 2 ends up with both. A YAML anchor with a merge key replaces the entire variables hash, keeping only what the job wrote.
Arrays are never merged by either mechanism. A job that extends a base defining script and then defines its own script replaces it completely; there is no append. The same is true for before_script, rules, and only.
extends supports up to eleven levels of inheritance and can name multiple parents, with later parents winning on conflict. It is also resolved after include, so a job can extend a template pulled from another project, which anchors cannot do because anchors are file-scoped. Verify the merged result with the CI Lint page's merged YAML view rather than reasoning about it, since the precedence rules interact with variable precedence in ways that are hard to predict.