多くの純粋関数とそれらに副作用がないことを見て、不安定で主要なエラーの原因として常に拮抗されている不純な関数の例は何でしょうか?
たとえば、それ自体のスコープ外の変数に副作用がある不純な関数:
var count = 0;
function increaseCount(val) {
count += val;
}
または、パラメーターとして指定されていない変数を評価するため、同じ入力に対して異なる値を返す関数:
var count = 0;
function getSomething() {
return count > 0;
}
純粋関数は、その範囲外の変数の状態に依存せず、変数の状態を変更しません。
具体的には、純粋関数は同じパラメーターを指定すると常に同じ結果を返すことを意味します。その実行は、システムの状態に依存しません。
var values = { a: 1 };
function impureFunction ( items ) {
var b = 1;
items.a = items.a * b + 2;
return items.a;
}
var c = impureFunction( values );
// Now `values.a` is 3, the impure function modifies it.
ここでは、指定されたオブジェクトの属性を変更します。したがって、関数のスコープ外にあるオブジェクトを変更します。関数は不純です。
var values = { a: 1 };
function pureFunction ( a ) {
var b = 1;
a = a * b + 2;
return a;
}
var c = pureFunction( values.a );
関数のスコープ内にあるパラメーターを変更するだけで、外部では何も変更されません。
var values = { a: 1 };
var b = 1;
function impureFunction ( a ) {
a = a * b + 2;
return a;
}
var c = impureFunction( values.a );
// Actually, the value of `c` will depend on the value of `b`.
// In a bigger codebase, you may forget about that, which may
// surprise you because the result can vary implicitly.
ここで、bは関数の範囲内にありません。結果は状況によって異なります。驚きが予想されます。
var values = { a: 1 };
var b = 1;
function pureFunction ( a, c ) {
a = a * c + 2;
return a;
}
var c = pureFunction( values.a, b );
// Here it's made clear that the value of `c` will depend on
// the value of `b`.
Math.random()
は不純な関数です。 Math
オブジェクトの内部状態を変更するため、連続する呼び出しで異なる値を取得できます。 console.log()
とalert()
は副作用があるため、不純な関数です(ただし、同じ動作を生成し、同じ呼び出しに対して常に同じ値を返します)。
引数の1つの内部状態または外部変数の値を変更する関数は、不純な関数です。これには、メソッドを呼び出すとクロージャー自体の内部状態が変更されるクロージャーが含まれます。
let nextInt = (function() {
var i = 0;
return function() {
return i++;
};
})();
let a = nextInt(); // sets a to 0
let b = nextInt(); // sets b to 1
// etc.
不純な関数は常に悪いことだと考えられているという考えはどこで得られましたか?
例:
1)
var toggled = false; /* state */
/*impure function*/
function impureFn(number){
if(number%2 == 0)
toggled = true;
return toggled;
}
/*Execute this in order */
impureFn(5) // returns false
impureFn(2) //returns true
impureFn(5) // now returns true
私が考えることができる例(それは確かにかなり混乱しています)は Array#reverse()
です。新しい配列を返す代わりに、元の配列を返すときにその場で変更します。
splice
、Push
、shift
、pop
、unshift
など、他のいくつかの配列関数もこれを行います。
pure
関数(引数を取得して新しい値を返します):
function (objectArgument) {
return {
value: objectArgument.value + 123,
// other arguments
};
}
impure
関数(引数を取得して変更し、変更されたオブジェクトを返します):
function (objectArgument) {
objectArgument.value += 123;
return objectArgument;
}