Referential Transparency means that you can replace a function application with its result (or more generally, an expression with its evaluation) anywhere and/or everywhere in the program, without changing its result.
Here is an example of a program with a function that only reads but does not modify a global variable:
let global = 0;
function foo(i) {
return i + global;
}
const one = foo(1);
// foo(1) == 1
global = 100;
const two = foo(1);
// I should be able to replace this with const two = 1, since foo(1) was 1 above
console.log(two);
// 101
This prints 101.
If foo were referentially transparent, I should be able to replace any occurrence of foo(1) with 1. And vice versa, I should be able to replace any occurrence of 1 with foo(1).
Let's try that:
let global = 0;
function foo(i) {
return i + global;
}
const one = foo(1);
global = 100;
const two = 1;
console.log(two);
// 1
// Oops!
As you can see, replacing foo(1) with its result changes the meaning of the program. Ergo, foo is not referentially transparent.
There is another important lesson here: if global were a constant instead of a variable, then foo would be referentially transparent. foo is not referentially transparent because of some completely different piece of code somewhere else. Side-effects are infectious and can act across large distances!
foo.bar.baz = 42are so complicated that there's academic research into workarounds. – amon Jul 22 '18 at 16:27