Closed Lomacar closed 8 years ago
The line nativeRandom = Math.random;
takes a reference to whichever PRNG lives at Math.random
at the time when the reference is taken. If you load Lodash before you replace the JavaScript native Math.random()
, then its reference will be to the native—even if you later replace what Math.random
refers to. That said, creating a fresh Lodash context should fix the issue, as the new context will grab a new reference to Math.random()
—YMMV.
AFAIK, replacing Math.random
before loading Lodash should get you the results you seem to want. I'm unsure why doing so didn't seem to work for you. Have you tried creating a new context (see: _.runInContext())?
Underscore works as expected because it never takes a reference to Math.random
, instead calling it directly, so replacing it later replaces the PRNG it calls.
Regardless, this isn't something that seedrandom has any control over.
So doing
lodash = _.runInContext();
Math.seedrandom("hey");
lodash.random(999)
should produce consistent results? Because it doesn't.
I figured I have a better chance asking here about using lodash than asking somewhere else about using seedrandom.
No. You're doing it backwards again. When invoked, Lodash's runInContext
method captures a reference to whichever PRNG is currently referred to by Math.random
. So, creating the new Lodash context before replacing Math.random
still captures a reference to JavaScript's native PRNG.
To have Lodash capture seedrandom's PRNG, you need to initially load/require Lodash after altering Math.random
. If that's not feasible with your setup, or working for you as you claim, then you'll need to replace the current Lodash context, which captured the native PRNG, with a new context after you replace Math.random
.
For example, and without altering the default Lodash instance (_
):
/* Alter Math.random to refer to seedrandom's PRNG. */
Math.seedrandom("hey");
/* Assign a new Lodash context to a separate variable AFTER altering Math.random. */
var lodash = _.runInContext();
/* Should use seedrandom's PRNG. */
lodash.random(999);
AFAIK, you should even be able to replace the default Lodash instance, if you'd prefer. For example:
/* Alter Math.random to refer to seedrandom's PRNG. */
Math.seedrandom("hey");
/* Assign a new Lodash context to _ AFTER altering Math.random. */
_ = _.runInContext();
/* Should use seedrandom's PRNG. */
_.random(999);
Ah, now I get it. Thanks, that does work.
@Lomacar @tmedwards
I discovered another workaround for lodash;
your solution requires writing _ = _.runInContext();
after each Math.seedrandom
but I have another which requires changes only in one place
const _ = require('lodash');
require('seedrandom');
function sample(array) {
const length = array == null ? 0 : array.length
return length ? array[Math.floor(Math.random() * length)] : undefined
}
_.sample = sample;
// also copy other lodash methods which you use
Math.seedrandom('foo');
console.log(_.sample(_.range(100))); // always 46
Math.seedrandom('bar');
console.log(_.sample(_.range(100))); // always 37
// seeding lodash methods also works in the required files which only require lodash and call Math.seedrandom
If I do a simple test like
It ends up producing different numbers every time. Whereas if I use underscore or just Math.random it produces a consistent number, as expected. Lodash simply says
nativeRandom = Math.random;
and then uses nativeRandom throughout for its randomness. I call Math.seedrandom before loading lodash and it still produces inconsistent results.