Heim  >  Artikel  >  Web-Frontend  >  Lassen Sie uns über das Currying von JavaScript-Funktionen sprechen

Lassen Sie uns über das Currying von JavaScript-Funktionen sprechen

WBOY
WBOYnach vorne
2022-03-04 18:16:101986Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über Javascript, das hauptsächlich die Probleme im Zusammenhang mit dem Funktions-Currying in JavaScript vorstellt. Beim Currying geht es darum, eine Funktion, die mehrere Parameter akzeptiert, in eine Funktion umzuwandeln, die eine einzelne Parameterfunktion akzeptiert akzeptiert die restlichen Parameter und gibt das Ergebnis zurück. Ich hoffe, dass es für alle hilfreich ist. Verwandte Empfehlungen:

JavaScript-Tutorial Zeiger davon innerhalb des Funktionskörpers.

Lassen Sie uns über das Currying von JavaScript-Funktionen sprechen

call und apply haben genau die gleiche Funktion, aber die Art und Weise, wie sie Parameter akzeptieren, ist unterschiedlich. call ist eigentlich eine Art syntaktischer Zucker für apply.

Format: apply(context,[arguments]), call(context,param1,param2,...).

    2. Was ist Funktionscurry?
  • Currying ist die Technik, eine Funktion, die mehrere Parameter akzeptiert, in eine Funktion umzuwandeln, die einen einzelnen Parameter (den ersten Parameter der ursprünglichen Funktion) akzeptiert und eine neue Funktion zurückgibt, die die verbleibenden Parameter akzeptiert und das Ergebnis zurückgibt.
    Als Beispiel gibt es hier die Funktion add(), eine Funktion, die zum Verarbeiten der Addition und Summe der Parameter (param1, params2,...) verwendet wird, die wir an sie übergeben.
  • // 在这里第一个具有两个参数`x`、`y`的`add(x , y)`函数
    function add(x , y){
    	return x + y;
    }
    
    // 调用`add()`函数,并给定两个参数`4`和`6`
    add(4,6);
    
    // 模拟计算机操作,第一步 传入第一个参数 4
    function add(4 , y){
    	return 4 + y;
    }
    
    // 模拟计算机操作,第二步 传入第一个参数 6
    function add(4 , 6){
    	return 4 + 6;
    }
  • Wie würde es aussehen, wenn wir die Funktion add() ausführen würden? Hier ist eine einfache Implementierung:
// 柯里化过的add()函数,可以接受部分参数
function add(x ,y){
	if (typeof y === 'undefined') {
		return function (newy){
			return x + newy;
		}
	}
	// 完整应用
	return x + y;
}

// 测试调用
console.log(typeof add(4)); // [Function]
console.log(add(4)(6)); // 10

// 可以创建保存函数
let saveAdd = add(4);
console.log(saveAdd(6)); // 10
    Wie aus der obigen einfachen Curry-Funktion add() ersichtlich ist, kann die Funktion einige Funktionen akzeptieren und dann eine neue Funktion zurückgeben, um mit der Verarbeitung der verbleibenden Funktionen fortzufahren unten.
  • apply(context,[arguments]),call(context,param1,param2,...)

二、什么是函数柯里化?

柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

在这里举个例子,有一个add()函数,它是用来处理我们传给它的参数(param1,params2,…)相加求和的一个函数。

// 定义一个createCurry的函数function createCurry(fn){
	var slice = Array.prototype.slice,
	stored_args = slice.call(arguments,1);
	
	return function () {
		let new_args = slice.call(arguments),
		args = stored_args.concat(new_args);
		return fn.apply(null,args);
	}}

如果我们将add()函数柯里化,是什么样子呢?在这里简单的实现一下:

// 普通函数add()
function add(x , y){
	return x + y;
}

// 柯里化得到一个新的函数
var newAdd = createCurry(add,4);
console.log(newAdd(6)); // 10


//另一种简便方式
console.log(createCurry(add,4)(6));// 10

从以上简单柯里化的add()函数可以看出,函数可以接受部分函数,然后返回一个新的函数,使其继续处理剩下的函数。

三、写一个公共的柯里化函数

在这里我们创建一个公共的柯里化函数,那样我们就不必每次写一个函数都要在其内部实现复杂的柯里化过程。

// 多个参数的普通函数
function add(a,b,c,d){
	return a + b + c + d;
}

// 柯里化函数得到新函数,多个参数可以随意分割
console.log(createCurry(add,4,5)(5,6)); // 20

// 两步柯里化
let add_one = createCurry(add,5);
console.log(add_one(5,5,5));// 20
let add_two = createCurry(add_one,4,6);
console.log(add_two(6)); // 21

在以上公共的柯里化函数中:

  • arguments,并不是一个真的数组,只是一个具有length属性的对象,所以我们从Array.prototype中借用slice方法帮我们把arguments转为一个真正的数组,方便我们更好的操作。
  • 当我们第一次调用函数createCurry的时候,其中变量stored_args 是保持了除去第一个参数以外的参数,因为第一个参数是我们需要柯里化的函数。
  • 当我们执行createCurry函数中返回的函数时,变量new_args获取参数并转为数组。
  • 内部返回的函数通过闭包访问变量stored_args中存储的值和变量new_args的值合并为一个新的数组,并赋值给变量args
  • 最后调用fn.apply(null,args)方法,执行被柯里化的函数。

现在我们来测试公共的柯里化函数

// 创建一个可以多步执行的柯里化函数,当参数满足数量时就去执行它:
// 函数公式:fn(x,y,z,w) ==> fn(x)(y)(z)(w);
let createCurry = (fn,...params)=> {
	let args = parsms || [];
	let fnLen = fn.length; // 指定柯里化函数的参数长度
	
	return (...res)=> {
		// 通过作用域链获取上一次的所有参数
		let allArgs = args.slice(0);
		// 深度拷贝闭包共用的args参数,避免后续操作影响(引用类型)
		allArgs.push(...res);
		if(allArgs.length < fnLen){
		   // 当参数数量小于原函数的参数长度时,递归调用createCurry函数
		   return createCurry.call(this,fn,...allArgs);
		}else{
		  // 当参数数量满足时,触发函数执行
		  return fn.apply(this,allArgs);
		}
	}
}


// 多个参数的普通函数
function add(a,b,c,d){
	return a + b + c + d;
}

// 测试柯里化函数

let curryAdd = createCurry(add,1);
console.log(curryAdd(2)(3)(4)); // 10

当然这里并不局限于两个参数的柯里化,也可以多个参数:

let createCurry = (fn,...params)=> {
	let args = parsms || [];
	let fnLen = fn.length; // 指定柯里化函数的参数长度
	
	if(length === _args.length){
	   // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果
           return fn.apply(this,args);
        }
	return (...res)=> {
		let allArgs = args.slice(0);
		allArgs.push(...res);
		if(allArgs.length < fnLen){
		   return createCurry.call(this,fn,...allArgs);
		}else{
		  return fn.apply(this,allArgs);
		}
	}}

通过以上的例子,我们可以发现一个局限,那就是不管是两个参数还是多个参数,它只能分两步执行,如以下公式:

  • fn(x,y) ==> fn(x)(y);
  • fn(x,y,z,w) ==> fn(x)(y,z,w) || fn(x,y)(z,w)||…
  • 如果我们想更灵活一点:

    • fn(x,y) ==> fn(x)(y);
    • fn(x,y,z) ==> fn(x,y)(z) || fn(x)(y)(z);
    • fn(x,y,z,w) ==> fn(x,y)(z)(w) || fn(x)(y)(z)(w) || …;

    我们该怎么实现呢?

    四、创建一个灵活的柯里化函数

    经过以上练习,我们发现我们创建的柯里化函数存在一定局限性,我们希望函数可以分为多步执行:

    // 当参数满足,再次执行时调用函数
    let createCurry = (fn,...params)=> {
    	let args = parsms || [];
    	let fnLen = fn.length; // 指定柯里化函数的参数长度
    	
    	//当然这里的判断需要注释掉,不然当它第一次参数数量足够时就直接执行结果了
    	//if(length === _args.length){
    	   // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果
               //return fn.apply(this,args);
            //}
    	return (...res)=> {
    		let allArgs = args.slice(0);
    		allArgs.push(...res);
    		// 在这里判断输入的参数是否大于0,如果大于0在判断参数数量是否足够,
    		// 这里不能用 && ,如果用&& 也是参数数量足够时就执行结果了。
    		if(res.length > 0 || allArgs.length < fnLen){
    		   return createCurry.call(this,fn,...allArgs);
    		}else{
    		  return fn.apply(this,allArgs);
    		}
    	}
    }
    
    
    // 多个参数的普通函数
    function add(a,b,c,d){
    	return a + b + c + d;
    }
    
    // 测试可控制的柯里化函数
    
    let curryAdd = createCurry(add,1);
    console.log(curryAdd(2)(3)(4)); // function
    console.log(curryAdd(2)(3)(4)()); // 10
    console.log(curryAdd(2)(3)()); // 当参数不足够时返回 NaN

    以上我们已经实现了灵活的柯里化函数,但是这里我们又发现了一个问题:

    • 如果我第一次就把参数全部传入,但是它并没有返回结果,而是一个函数(function)。
    • 只有我们再次将返回的函数调用一次才能返回结果:curryAdd(add,1,2,3,4)();
    • 可能有人说如果是全部传参,就调用原来的add()3. Schreiben Sie eine öffentliche Currying-Funktion
    Hier erstellen wir eine öffentliche Currying-Funktion, damit wir nicht jedes Mal, wenn wir eine Funktion schreiben, den darin enthaltenen komplexen Currying-Prozess implementieren müssen.

    rrreee

    In der obigen öffentlichen Curry-Funktion:

    arguments ist kein echtes Array, sondern nur ein Objekt mit dem Attribut length, also beginnen wir mit Array.prototype leiht sich die Methode slice aus, um uns bei der Konvertierung von Argumenten in ein echtes Array zu helfen und so unsere besseren Operationen zu ermöglichen.

    Wenn wir die Funktion createCurry zum ersten Mal aufrufen, enthält die Variable stored_args die Parameter mit Ausnahme des ersten Parameters, da der erste Parameter das ist, was wir für Curry-Funktionen benötigen.

    🎜Wenn wir die in der Funktion createCurry zurückgegebene Funktion ausführen, ruft die Variable new_args die Parameter ab und wandelt sie in ein Array um. 🎜🎜Die zurückgegebene Funktion greift intern durch den Abschluss auf den in der Variablen stored_args gespeicherten Wert zu und führt den Wert der Variablen new_args in einem neuen Array zusammen und weist ihn der Variablen < zu code>args . 🎜🎜Rufen Sie abschließend die Methode fn.apply(null,args) auf, um die Curry-Funktion auszuführen. 🎜🎜🎜Jetzt testen wir die öffentliche Currying-Funktion🎜rrreee🎜Natürlich ist dies nicht auf das Currying von zwei Parametern beschränkt, sondern kann auch mehrere Parameter haben: 🎜rrreee🎜Durch das obige Beispiel können wir das Finden Sie eine Einschränkung, das heißt, unabhängig davon, ob es sich um zwei Parameter oder mehrere Parameter handelt, kann sie nur in zwei Schritten ausgeführt werden, z. B. in der folgenden Formel: 🎜🎜🎜fn(x,y) ==> );🎜🎜fn(x,y,z,w) ==> fn(x)(y,z,w) || Möchten Sie flexibler sein: 🎜🎜🎜fn(x,y) ==> fn(x)(y);🎜🎜fn(x,y,z) ==> |. |. fn(x)(y)(z);🎜🎜fn(x,y,z,w) ==> ( z)(w) ||. …;🎜🎜🎜Wie setzen wir es um? 🎜🎜4. Erstellen Sie eine flexible Curry-Funktion🎜🎜Nach den obigen Übungen haben wir festgestellt, dass die von uns erstellte Curry-Funktion bestimmte Einschränkungen aufweist: 🎜rrreee🎜Wir haben das oben genannte flexible Curry erreicht Funktion, aber hier finden wir ein anderes Problem: 🎜🎜🎜Wenn ich zum ersten Mal alle Parameter übergebe, gibt es kein Ergebnis, sondern eine Funktion zurück. 🎜🎜Das Ergebnis kann nur zurückgegeben werden, wenn wir die zurückgegebene Funktion noch einmal aufrufen: curryAdd(add,1,2,3,4)();🎜🎜Manche Leute sagen das vielleicht, wenn alle Parameter vorhanden sind bestanden, rufen Sie einfach auf Die ursprüngliche Funktion add() reicht aus, und dies ist auch eine Methode, aber da wir hier auf die Anzahl der Parameter stoßen, beschäftigen wir uns immer noch mit dieser Situation. 🎜🎜🎜Hier müssen wir nur ein Urteil fällen, bevor wir die Funktion zurückgeben: 🎜rrreee🎜Das Obige kann als Abschluss einer flexiblen Curry-Funktion angesehen werden, ist hier jedoch nicht sehr flexibel, da wir es nicht kontrollieren können automatisch ausgeführt, solange die Anzahl der Parameter ausreicht. Was sollten wir tun, wenn wir ein Timing implementieren möchten, das seine Ausführung steuern kann? 🎜🎜5. Schreiben Sie eine Curry-Funktion mit kontrollierbarer Ausführungszeit🎜🎜Lassen Sie uns die Funktionsformel hier direkt erklären:🎜
    • fn(a,b,c) ==> fn(a)(b)(c )();
    • fn(a,b,c) ==> fn(a);fn(b);fn(c );fn();
    • 当我们参数足够时它并不会执行,只有我们再次调用一次函数它才会执行并返回结果。在这里我们在以上例子中加一个小小的条件就可以实现。
    // 当参数满足,再次执行时调用函数
    let createCurry = (fn,...params)=> {
    	let args = parsms || [];
    	let fnLen = fn.length; // 指定柯里化函数的参数长度
    	
    	//当然这里的判断需要注释掉,不然当它第一次参数数量足够时就直接执行结果了
    	//if(length === _args.length){
    	   // 加入判断,如果第一次参数数量以经足够时就直接调用函数获取结果
               //return fn.apply(this,args);
            //}
    	return (...res)=> {
    		let allArgs = args.slice(0);
    		allArgs.push(...res);
    		// 在这里判断输入的参数是否大于0,如果大于0在判断参数数量是否足够,
    		// 这里不能用 && ,如果用&& 也是参数数量足够时就执行结果了。
    		if(res.length > 0 || allArgs.length < fnLen){
    		   return createCurry.call(this,fn,...allArgs);
    		}else{
    		  return fn.apply(this,allArgs);
    		}
    	}
    }
    
    
    // 多个参数的普通函数
    function add(a,b,c,d){
    	return a + b + c + d;
    }
    
    // 测试可控制的柯里化函数
    
    let curryAdd = createCurry(add,1);
    console.log(curryAdd(2)(3)(4)); // function
    console.log(curryAdd(2)(3)(4)()); // 10
    console.log(curryAdd(2)(3)()); // 当参数不足够时返回 NaN

    相关推荐:javascript学习教程

    Das obige ist der detaillierte Inhalt vonLassen Sie uns über das Currying von JavaScript-Funktionen sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen