Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript组合函数_Javascript_Function Composition - Fatal编程技术网

JavaScript组合函数

JavaScript组合函数,javascript,function-composition,Javascript,Function Composition,我正在读一本书,其中包含以下示例: var composition1 = function(f, g) { return function(x) { return f(g(x)); } }; 然后作者写道:“……合成的天真实现,因为它没有考虑执行上下文……” 因此,首选函数是: var composition2 = function(f, g) { return function() { return f.call(this, g.apply(this, argum

我正在读一本书,其中包含以下示例:

var composition1 = function(f, g) {
  return function(x) {
    return f(g(x));
  }
};
然后作者写道:“……合成的天真实现,因为它没有考虑执行上下文……”

因此,首选函数是:

var composition2 = function(f, g) {
  return function() {
    return f.call(this, g.apply(this, arguments));
  }
}; 
下面是一个完整的示例:

var composition2 = function composition2(f, g) {
    return function() {
        return f.call(this, g.apply(this, arguments));
    }
};

var addFour = function addFour(x) {
    return x + 4;
};

var timesSeven = function timesSeven(x) {
    return x * 7;
};

var addFourtimesSeven2 = composition2(timesSeven, addFour);
var result2 = addFourtimesSeven2(2);
console.log(result2);
有人能给我解释一下为什么composition2函数是首选函数吗

编辑:

在此期间,我尝试使用方法作为建议的参数,但不起作用。结果是:

var composition1 = function composition1(f, g) {
    return function(x) {
        return f(g(x));
    };
};

var composition2 = function composition2(f, g) {
    return function() {
        return f.call(this, g.apply(this, arguments));
    }
};

var addFour = {
    myMethod: function addFour(x) {
        return x + this.number;
    },
    number: 4
};

var timesSeven = {
    myMethod: function timesSeven(x) {
        return x * this.number;
    },
    number: 7
};

var addFourtimesSeven1 = composition1(timesSeven.myMethod, addFour.myMethod);
var result1 = addFourtimesSeven1(2);
console.log(result1);

var addFourtimesSeven2 = composition2(timesSeven.myMethod, addFour.myMethod);
var result2 = addFourtimesSeven2(2);
console.log(result2);

composition1不会将第一个参数以外的参数传递给g()

如果您这样做:

var composition1 = function(f, g) {
  return function(x1, x2, x3) {
    return f(g(x1, x2, x3));
  }
};
该函数适用于前三个参数。但是,如果您希望它适用于任意数字,则需要使用


f.call(…)
用于设置
,如Caramiriel的回答所示。

这只回答了
合成2的实际功能:

composition2
用于将
保留为函数本身的上下文。下面的示例显示,通过使用
data.a
data.b
,结果是
60

'use strict';

var multiply = function(value) {
    return value * this.a;
}
var add = function(value) {
    return value + this.b;
}

var data = {
    a: 10,
    b: 4,
    func: composition2(multiply, add)
};

var result = data.func(2);
// uses 'data' as 'this' inside the 'add' and 'multiply' functions
// (2 + 4) * 10 = 60
但是,它仍然打破了以下示例(不幸):

由于
composition2
this
)的上下文未定义(并且未以任何其他方式调用,例如
.apply
.call
obj.func()
),因此,函数中的
this
也未定义

另一方面,我们可以使用以下代码为其提供另一个上下文:

'use strict';
var foo = new Foo();

var data = {
    a: 20,
    b: 8,
    func: composition2(foo.multiply, foo.add)
}

var result = data.func(2); 
// uses 'data' as 'this'
// (2 + 8) * 10 = 200 :)
或者通过显式设置上下文:

'use strict';

var multiply = function(value) {
    return value * this.a;
};
var add = function(value) {
    return value + this.b;
};


var a = 20;
var b = 8;

var func = composition2(multiply, add);

// All the same
var result1 = this.func(2);
var result2 = func.call(this, 2);
var result3 = func.apply(this, [2]);

我不同意作者的观点

想想函数组合的用例。大多数情况下,我利用函数组合来实现变换器函数(纯函数;参数输入、结果输出和
这与
无关)

第二。使用
arguments
的方式会导致错误的做法/死胡同,因为这意味着函数
g()
可能依赖于多个参数

这意味着,我创建的组合不再是可组合的,因为它可能无法获得所需的所有参数
阻止合成的合成;失败

(还有一个副作用:将arguments对象传递给任何其他函数都是性能问题,因为JS引擎无法再对此进行优化)

看看
部分应用程序
的主题,在JS中通常被错误地引用为
currying
,其基本内容是:除非传递所有参数,否则该函数返回另一个接受其余参数的函数;在我得到所有的论点之前,我需要处理它们

然后,您应该重新考虑实现参数顺序的方式,因为当您将它们定义为先配置,后数据时,效果最佳。
示例:

//a transformer: value in, lowercased string out
var toLowerCase = function(str){
    return String(str).toLowerCase();
}

//the original function expects 3 arguments, 
//two configs and the data to process.
var replace = curry(function(needle, heystack, str){
    return String(str).replace(needle, heystack);
});

//now I pass a partially applied function to map() that only 
//needs the data to process; this is really composable
arr.map( replace(/\s[A-Z]/g, toLowerCase) );

//or I create another utility by only applying the first argument
var replaceWhitespaceWith = replace(/\s+/g);
//and pass the remaining configs later
arr.map( replaceWhitespaceWith("-") );
另一种稍有不同的方法是创建函数,根据设计,这些函数不打算在一个步骤中传递所有参数,而是一个接一个地传递(或在有意义的组中传递)

我不打算用所有参数调用此类函数,我只想传递它们的配置,并获取一个对传递的数据/值执行任务的函数


我总是写
someString.substr(0,5)
,而不是
substr(0,5)
,所以为什么要在第一次调用中使用最后一个参数(数据)?

这实际上与咖喱无关。你说得对,我更改了措辞。它被称为函数合成!看在上帝的份上,你为什么要写方法?函数组合是指以无点形式组合纯函数而不产生副作用:
const compose=f=>g=>x=>f(g(x))
。Curried函数,除了一个参数(作为我们的
compose
函数)。函数构图只适用于CurrId函数,因为函数只返回一个值。然后作者写道:“……天真的实现构图,因为它不考虑执行上下文……”我认为作者是天真的。我希望这是有意义的,如果它不让我知道的话。如果需要的话,我会尝试重新措辞。好吧,你可以这样做,但是你会积极地反对你正在使用的语言。看看我的答案,为什么这样做毫无意义;虽然你能做到。我将把这个答案作为
组合2
的实际功能的参考,但我同意你的看法。:@Caramiriel:我通过以下方式理解了您的答案,希望这是正确的:)您的第一个示例:composition2是通过对象调用的,因此this=object(在本例中为“data”)。您的第二个示例:composition2是直接调用的,因此this=window对象(在本例中,由于严格模式的原因,未定义)您的第三个示例:composition2再次通过对象调用,因此this=object(在本例中为'data')您的第四个示例:composition2直接调用,因此this=window对象,并且由于'a'和'b'是window对象的属性,因此works@JShinigami正是:)
//a transformer: value in, lowercased string out
var toLowerCase = function(str){
    return String(str).toLowerCase();
}

//the original function expects 3 arguments, 
//two configs and the data to process.
var replace = curry(function(needle, heystack, str){
    return String(str).replace(needle, heystack);
});

//now I pass a partially applied function to map() that only 
//needs the data to process; this is really composable
arr.map( replace(/\s[A-Z]/g, toLowerCase) );

//or I create another utility by only applying the first argument
var replaceWhitespaceWith = replace(/\s+/g);
//and pass the remaining configs later
arr.map( replaceWhitespaceWith("-") );
var prepend = a => b => String(a) + String(b);  //one by one
var substr = (from, to) => value => String(str).substr(from, to);  //or grouped

arr.map( compose( prepend("foo"), substr(0, 5) ) );
arr.map( compose( prepend("bar"), substr(5) ) );
//and the `to`-argument is undefined; by intent