我正在尝试理解Javascript中的功能组合,并遵循talk which describes the compose function
我尝试了以下程序,它将接受一个句子,将其分解成碎片(用空格分隔)并在每个单词上使用大写并返回一个单词数组。
function compose(f, g) {
"use strict";
return function() {
return f.call(this, g.apply(this,arguments));
}
}
var split = function (string, delim) {
"use strict";
return string.split(delim);
};
var uppercase = function (string) {
"use strict";
if (string instanceof Array) {
return string.map(function (x) {
return x.toString().toUpperCase();
});
} else {
return string.toString().toUpperCase();
}
//return string.toString().toUpperCase();
};
var myfunc = compose(uppercase,split);
var data = myfunc("Elementary! My dear Watson",/\s+/);
console.log(data);
虽然我得到了我想要的东西,但代码在以下方面很难看:
如何将代码即兴创作以具有“功能管道”即。拆分 - >地图 - >大写?
答案 0 :(得分:2)
这是你所拥有的相同类型的代码,它已被简化了一点。如果这是您想要使用编码的方向,我不能推荐使用Reg Braithwait的Javascript Allonge,这完全改变了我编写代码的方式。
希望这个小例子展示了如何编写函数以及函数js的有用性。另一个很大的好处是,如果您使用的是不看外部范围的纯函数,则可以轻松调试问题,因为您可以遵循可靠的函数调用流。
学习功能足以理解它的基本概念花了我大约6个月并不断练习。但值得付出努力。
"use strict"; // you just need one use strict on the hholee file
// for compose you shouldn't really need to call or apply as this is always the window for a pure function
function compose(a, b) {
return function( c ) {
return a( b( c ) );
}
}
// split is now a simple function that takes a delimeter and returns a function that splits the string
function split(delim) {
return function( string ){
return string.split(delim);
}
};
// if you add a function mapper you can remove some of the complexity in uppercase
// and compose map with uppercase
function map( fn ){
return function( arr ){
return Array.prototype.map.call( arr, fn );
}
}
// this is now a very simple single responsibility function that can be composed
function uppercase(string) {
return string.toUpperCase();
};
var
splitBySpace = split(/\s+/),
arrToUpper = map(uppercase),
myfunc = compose(arrToUpper,splitBySpace);
console.log( arrToUpper(['one', 'two']) );
console.log( myfunc("Elementary! My dear Watson") );
// if you want to split on a different character you will need to create a new split function by currying a different delimeter
var
splitByChar = split(''),
splitByBang = split('!');
// you also don't have to compose the functions you can write them out normally but it is much harder to follow eg.
console.log( map(uppercase)(split('')("Elementary! My dear Watson") ) );
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
答案 1 :(得分:0)
这是一个小例子,说明如何使用流畅的界面启动和运行,涵盖问题的第三部分。要带走的关键是你用new Obj
创建一个对象,并在return this
所需的方法中允许方法链接。
功能Javascript不允许链接方法,因为它没有内部状态,你使用函数js来装饰和混合可以返回值或其他函数的其他函数。
// MyObj is declared within a module to make the internals private
var myObj = (function() {
// Constructor function
function MyObj(string, delim) {
this.input = string;
this.delim = delim;
}
// create the MyObj methods on it's prototype
// all methods have been decorated with the fluent function
MyObj.prototype = {
// split the input
split: fluent(function(delim) {
if( ! Array.isArray( this.input ) ){
this.input = this.input.split( delim != null ? delim : this.delim);
}
}),
// convert the text to uppercase
uppercase: fluent(function() {
if (Array.isArray(this.input)) {
this.input = this.input.map(function(string) {
return string.toUpperCase();
});
} else {
this.input = this.input.toUpperCase();
}
}),
// reverse the array
reverse: fluent(function(){
if( Array.isArray( this.input ) ){
this.input = this.input.reverse();
}
else {
this.input = this.input.split('').reverse().join('');
}
}),
// you will need a getter if you are using a fluent interface or decide what your end points will be
get: function() {
return this.input;
}
}
return function constructor(string, delim) {
return new MyObj(string, delim);
}
})();
// myObj is the function to create a MyObj
console.log( myObj );
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split().uppercase().get() );
// with the code you can override the default delimeter
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split('').uppercase().get() );
// run different methods
console.log( myObj("Elementary! My dear Watson", /\s+/ ).split().uppercase().reverse().get() );
// order no longer matters
console.log( myObj("Elementary! My dear Watson", /\s+/ ).reverse().uppercase().split().get() );
// MyObj also has an internal state so you can do
// functional decorator - this will make the prototype methods return a value or this
function fluent(method) {
return function() {
var ret = method.apply(this, arguments);
return ret != null
? ret
: this;
}
}
&#13;
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
&#13;
答案 2 :(得分:0)
功能组合就是您使用两个或多个功能,并将其中一个功能制成一个功能。我写了一个非常容易理解的explanation of composing functions,我认为它将为您解决很多问题。
但是,您想要的是非常不同的东西,并且在javascript中非常简单
"Elementary! My dear Watson".split(/\s+/).map(val => val.toUpperCase());
或者如果您真的想要像上面一样的功能...
function myFunct(str, delim) {
str.split(delim).map(val => val.toUpperCase());
}
答案 3 :(得分:0)
合成功能允许功能的可重用性。您可以应用javascript reduce方法将一组功能应用于数据。
让我们从一个基本的reduce样本开始。以下是计算销售价格的函数集。
public static void TakeInAFunc<T>(T aFuncOrAction)
{
if (typeof(T) == typeof(Func<>))
{
// some value returned.
}
else if (typeof(T) == typeof(Action<>))
{
// it returns void.
}
}
我可以如下创建一个构图
const SALES_TAX = 0.08;
const COUPON_CODES = {
AAAA: 0.1,
BBBB: 0.07,
CCCC: 0.15,
};
const shoppingtotal = shoppingCart =>
shoppingCart.reduce((acc, item) => {
acc += item.price * item.qty;
return acc;
}, 0);
const discount = couponCode => amount =>
amount * (1 - COUPON_CODES[couponCode]);
const tax = amt => amt * (1 + SALES_TAX);
现在可以计算价格了,我可以叫calculatePayment。
const compose = fns => input => fns.reduce((acc, fn) => fn(acc), input);
const calculatePayment = compose([shoppingtotal, discount('AAAA'), tax]);
这是一个示例。这样,您可以轻松地组合多个函数并创建新的函数定义。