Inhaltsverzeichnis
1. Ergänzende Wissenspunkte zur impliziten Konvertierung von Funktionen
Im Front-End-Interview gibt es eine Interviewfrage zum Currying, die weit verbreitet ist.
四、柯里化通用式
五、柯里化与bind
Heim Web-Frontend js-Tutorial Front-End-Fortschritt (8): Detailliertes Currying von Funktionen

Front-End-Fortschritt (8): Detailliertes Currying von Funktionen

Apr 04, 2017 pm 05:56 PM

Front-End-Fortschritt (8): Detailliertes Currying von Funktionen

Das Bild hat nichts mit diesem Artikel zu tun

Currying ist eine relativ fortgeschrittene Anwendung der Funktion. Es ist nicht einfach um es zu verstehen. Deshalb habe ich darüber nachgedacht, wie ich mich besser ausdrücken sollte, damit es für alle verständlicher ist. Nachdem ich lange darüber nachgedacht hatte, beschloss ich, das Konzept des Currys beiseite zu legen und zwei wichtige, aber leicht übersehene Wissenspunkte hinzuzufügen.

1. Ergänzende Wissenspunkte zur impliziten Konvertierung von Funktionen

JavaScriptAls schwach typisierte Sprache ist ihre implizite Konvertierung sehr flexibel und interessant. Wenn wir kein tiefes Verständnis der impliziten Konvertierung haben, sind wir möglicherweise durch die Ergebnisse einiger Operationen verwirrt, z. B. 4 + true = 5. Wenn Sie über ein ausreichend tiefes Verständnis der impliziten Konvertierung verfügen, können Sie Ihre Fähigkeiten im Umgang mit js natürlich erheblich verbessern. Ich habe nur nicht vor, alle impliziten Konvertierungsregeln mit Ihnen zu teilen. Hier werde ich nur einige Regeln für die implizite Konvertierung von Funktionen teilen.

Stellen wir eine einfache Frage.

function fn() {
    return 20;
}

console.log(fn + 10); // 输出结果是多少?
Nach dem Login kopieren

Ändern Sie es leicht und überlegen Sie, wie das Ergebnis aussehen wird?

function fn() {
    return 20;
}

fn.toString = function() {
    return 10;
}

console.log(fn + 10);  // 输出结果是多少?
Nach dem Login kopieren

Sie können es weiterhin ändern.

function fn() {
    return 20;
}

fn.toString = function() {
    return 10;
}

fn.valueOf = function() {
    return 5;
}

console.log(fn + 10); // 输出结果是多少?
Nach dem Login kopieren
// 输出结果分别为
function fn() {
    return 20;
}10

20

15
Nach dem Login kopieren

Bei der Verwendung von console.log oder der Ausführung von Vorgängen kann es zu einer impliziten Konvertierung kommen. Aus den oben genannten drei Beispielen können wir einige Schlussfolgerungen zur impliziten Konvertierung von Funktionen ziehen.

Wenn wir toString und valueOf nicht neu definieren, ruft die implizite Konvertierung der Funktion die Standardmethode toString auf, die den Definitionsinhalt der Funktion als String zurückgibt. Wenn wir die Methode toString/vauleOf aktiv definieren, wird das Rückgabeergebnis der impliziten Konvertierung von uns selbst gesteuert. Unter diesen wird valueOf

nach toString ausführen, sodass die Schlussfolgerung des obigen Beispiels leicht zu verstehen ist. Ich schlage vor, dass Sie es versuchen.

2. Ergänzende Wissenspunkte mit call/apply zur Versiegelung der map-Methode
map(): Führt die angegebene Funktion für jedes Element im Array aus und gibt ein Array der Ergebnisse jedes Funktionsaufrufs zurück.

Laienhaft ausgedrückt bedeutet dies,
jedes Element des Arrays zu durchlaufen

und Operationen im ersten Parameter der Karte auszuführen (Rückruffunktion ) und dann die Berechnung zurückzugeben Ergebnis. Gibt ein neues Array zurück, das aus allen Berechnungsergebnissen besteht.

Die Details der Kartenmethode werden im
// 回调函数中有三个参数
// 第一个参数表示newArr的每一项,第二个参数表示该项在数组中的索引值
// 第三个表示数组本身
// 除此之外,回调函数中的this,当map不存在第二参数时,this指向丢失,当存在第二个参数时,指向改参数所设定的对象
var newArr = [1, 2, 3, 4].map(function(item, i, arr) {
    console.log(item, i, arr, this);  // 可运行试试看
    return item + 1;  // 每一项加1
}, { a: 1 })

console.log(newArr); // [2, 3, 4, 5]
Nach dem Login kopieren
Kommentar

des obigen Beispiels erläutert. Jetzt müssen wir uns einem Problem stellen, nämlich der Kapselung der Karte. Sie können zuerst über eine

for-Schleife

nachdenken. Wir können eine for-Schleife verwenden, um eine Karte zu implementieren, aber beim Kapseln müssen wir einige Probleme berücksichtigen. Wenn wir eine for-Schleife verwenden, ist es zwar einfach, einen Schleifenprozess zu kapseln, aber es ist schwierig, ihn mit einer festen Sache für das zu kapseln, was wir für jedes Element in der for-Schleife tun müssen. Denn in jedem Szenario ist die Verarbeitung der Daten in der for-Schleife definitiv anders. Jeder hat sich also eine gute Möglichkeit ausgedacht, diese verschiedenen Vorgänge mit einer separaten Funktion zu verarbeiten und diese Funktion zum ersten Parameter der Kartenmethode zu machen. Konkret: Was wird in dieser Rückruffunktion enthalten sein? wenn man es benutzt. Daher ist die auf dieser Idee basierende Kapselungsimplementierung wie folgt.

Im obigen Paket habe ich zunächst ein leeres temporäres Array definiert, das zum Speichern des endgültigen Rückgabeergebnisses verwendet wird. In der for-Schleife wird bei jeder Schleife die Parameter-FN-Funktion ausgeführt und die Parameter von FN mithilfe der Aufrufmethode übergeben.
Array.prototype._map = function(fn, context) {
    var temp = [];
    if(typeof fn == 'function') {
        var k = 0;
        var len = this.length;
        // 封装for循环过程
        for(; k < len; k++) {
            // 将每一项的运算操作丢进fn里,利用call方法指定fn的this指向与具体参数
            temp.push(fn.call(context, this[k], k, this))
        }
    } else {
        console.error('TypeError: '+ fn +' is not a function.');
    }

    // 返回每一项运算结果组成的新数组
    return temp;
}

var newArr = [1, 2, 3, 4]._map(function(item) {
    return item + 1;
})
// [2, 3, 4, 5]
Nach dem Login kopieren

Nachdem wir den Kapselungsprozess von Map verstanden haben, können wir verstehen, warum wir bei der Verwendung von Map immer einen Rückgabewert in der ersten Rückruffunktion erwarten. Wenn wir in den Regeln von eslint bei der Verwendung von Map keinen Rückgabewert festlegen, wird dies als Fehler gewertet.

ok, da wir nun die impliziten Konvertierungsregeln von Funktionen verstehen und wissen, wie call/apply in diesem Szenario verwendet wird, können wir versuchen, Currying anhand eines einfachen Beispiels zu verstehen.

3. Currying von Easy bis Deep

Im Front-End-Interview gibt es eine Interviewfrage zum Currying, die weit verbreitet ist.

Implementieren Sie eine Additionsmethode, damit die Berechnungsergebnisse die folgenden Erwartungen erfüllen können:


add(1)(2)(3) = 6
add(1, 2, 3)(4) = 10
add(1)(2)(3)(4)(5) = 15

Sehr offensichtlich ist das Berechnungsergebnis die Summe aller Parameter. Jedes Mal, wenn die Add-Methode ausgeführt wird, muss sie dieselbe Funktion zurückgeben und die verbleibenden Parameter weiter berechnen.

Anhand der einfachsten Beispiele können wir Schritt für Schritt Lösungen finden.

当我们只调用两次时,可以这样封装。

function add(a) {
    return function(b) {
        return a + b;
    }
}

console.log(add(1)(2));  // 3
Nach dem Login kopieren

如果只调用三次:

function add(a) {
    return function(b) {
        return function (c) {
            return a + b + c;
        }
    }
}

console.log(add(1)(2)(3)); // 6
Nach dem Login kopieren

上面的封装看上去跟我们想要的结果有点类似,但是参数的使用被限制得很死,因此并不是我们想要的最终结果,我们需要通用的封装。应该怎么办?总结一下上面2个例子,其实我们是利用闭包的特性,将所有的参数,集中到最后返回的函数里进行计算并返回结果。因此我们在封装时,主要的目的,就是将参数集中起来计算。

来看看具体实现。

function add() {
    // 第一次执行时,定义一个数组专门用来存储所有的参数
    var _args = [].slice.call(arguments);

    // 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
    var adder = function () {
        var _adder = function() {
            [].push.apply(_args, [].slice.call(arguments));
            return _adder;
        };

        // 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
        _adder.toString = function () {
            return _args.reduce(function (a, b) {
                return a + b;
            });
        }

        return _adder;
    }
    return adder.apply(null, [].slice.call(arguments));
}

// 输出结果,可自由组合的参数
console.log(add(1, 2, 3, 4, 5));  // 15
console.log(add(1, 2, 3, 4)(5));  // 15
console.log(add(1)(2)(3)(4)(5));  // 15
Nach dem Login kopieren

上面的实现,利用闭包的特性,主要目的是想通过一些巧妙的方法将所有的参数收集在一个数组里,并在最终隐式转换时将数组里的所有项加起来。因此我们在调用add方法的时候,参数就显得非常灵活。当然,也就很轻松的满足了我们的需求。

那么读懂了上面的demo,然后我们再来看看柯里化的定义,相信大家就会更加容易理解了。

柯里化(英语:Currying),又称为部分求值,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回一个新的函数的技术,新函数接受余下参数并返回运算结果。

  • 接收单一参数,因为要携带不少信息,因此常常以回调函数的理由来解决。

  • 将部分参数通过回调函数等方式传入函数中

  • 返回一个新函数,用于处理所有的想要传入的参数

在上面的例子中,我们可以将add(1, 2, 3, 4)转换为add(1)(2)(3)(4)。这就是部分求值。每次传入的参数都只是我们想要传入的所有参数中的一部分。当然实际应用中,并不会常常这么复杂的去处理参数,很多时候也仅仅只是分成两部分而已。

咱们再来一起思考一个与柯里化相关的问题。

假如有一个计算要求,需要我们将数组里面的每一项用我们自己想要的字符给连起来。我们应该怎么做?想到使用join方法,就很简单。

var arr = [1, 2, 3, 4, 5];

// 实际开发中并不建议直接给Array扩展新的方法
// 只是用这种方式演示能够更加清晰一点
Array.prototype.merge = function(chars) {
    return this.join(chars);
}

var string = arr.merge('-')

console.log(string);  // 1-2-3-4-5
Nach dem Login kopieren

增加难度,将每一项加一个数后再连起来。那么这里就需要map来帮助我们对每一项进行特殊的运算处理,生成新的数组然后用字符连接起来了。实现如下:

var arr = [1, 2, 3, 4, 5];

Array.prototype.merge = function(chars, number) {
    return this.map(function(item) {
        return item + number;
    }).join(chars);
}

var string = arr.merge('-', 1);

console.log(string); // 2-3-4-5-6
Nach dem Login kopieren

但是如果我们又想要让数组每一项都减去一个数之后再连起来呢?当然和上面的加法操作一样的实现。

var arr = [1, 2, 3, 4, 5];

Array.prototype.merge = function(chars, number) {
    return this.map(function(item) {
        return item - number;
    }).join(chars);
}

var string = arr.merge('~', 1);

console.log(string); // 0~1~2~3~4
Nach dem Login kopieren

机智的小伙伴肯定发现困惑所在了。我们期望封装一个函数,能同时处理不同的运算过程,但是我们并不能使用一个固定的套路将对每一项的操作都封装起来。于是问题就变成了和封装map的时候所面临的问题一样了。我们可以借助柯里化来搞定。

与map封装同样的道理,既然我们事先并不确定我们将要对每一项数据进行怎么样的处理,我只是知道我们需要将他们处理之后然后用字符连起来,所以不妨将处理内容保存在一个函数里。而仅仅固定封装连起来的这一部分需求。

于是我们就有了以下的封装。

// 封装很简单,一句话搞定
Array.prototype.merge = function(fn, chars) {
    return this.map(fn).join(chars);
}

var arr = [1, 2, 3, 4];

// 难点在于,在实际使用的时候,操作怎么来定义,利用闭包保存于传递num参数
var add = function(num) {
    return function(item) {
        return item + num;
    }
}

var red = function(num) {
    return function(item) {
        return item - num;
    }
}

// 每一项加2后合并
var res1 = arr.merge(add(2), '-');

// 每一项减2后合并
var res2 = arr.merge(red(1), '-');

// 也可以直接使用回调函数,每一项乘2后合并
var res3 = arr.merge((function(num) {
    return function(item) {
        return item * num
    }
})(2), '-')

console.log(res1); // 3-4-5-6
console.log(res2); // 0-1-2-3
console.log(res3); // 2-4-6-8
Nach dem Login kopieren

大家能从上面的例子,发现柯里化的特征吗?

四、柯里化通用式

通用的柯里化写法其实比我们上边封装的add方法要简单许多。

var currying = function(fn) {
    var args = [].slice.call(arguments, 1);

    return function() {
        // 主要还是收集所有需要的参数到一个数组中,便于统一计算
        var _args = args.concat([].slice.call(arguments));
        return fn.apply(null, _args);
    }
}

var sum = currying(function() {
    var args = [].slice.call(arguments);
    return args.reduce(function(a, b) {
        return a + b;
    })
}, 10)

console.log(sum(20, 10));  // 40
console.log(sum(10, 5));   // 25
Nach dem Login kopieren
五、柯里化与bind
Object.prototype.bind = function(context) {
    var _this = this;
    var args = [].slice.call(arguments, 1);

    return function() {
        return _this.apply(context, args)
    }
}
Nach dem Login kopieren

这个例子利用call与apply的灵活运用,实现了bind的功能。

在前面的几个例子中,我们可以总结一下柯里化的特点:

  • 接收单一参数,将更多的参数通过回调函数来搞定?

  • 返回一个新函数,用于处理所有的想要传入的参数;

  • 需要利用call/apply与arguments对象收集参数;

  • 返回的这个函数正是用来处理收集起来的参数。

希望大家读完之后都能够大概明白柯里化的概念,如果想要熟练使用它,就需要我们掌握更多的实际经验才行。


Das obige ist der detaillierte Inhalt vonFront-End-Fortschritt (8): Detailliertes Currying von Funktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat -Befehle und wie man sie benutzt
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie erstelle ich meine eigenen JavaScript -Bibliotheken? Wie erstelle ich meine eigenen JavaScript -Bibliotheken? Mar 18, 2025 pm 03:12 PM

In Artikel werden JavaScript -Bibliotheken erstellt, veröffentlicht und aufrechterhalten und konzentriert sich auf Planung, Entwicklung, Testen, Dokumentation und Werbestrategien.

Wie optimiere ich den JavaScript -Code für die Leistung im Browser? Wie optimiere ich den JavaScript -Code für die Leistung im Browser? Mar 18, 2025 pm 03:14 PM

In dem Artikel werden Strategien zur Optimierung der JavaScript -Leistung in Browsern erörtert, wobei der Schwerpunkt auf die Reduzierung der Ausführungszeit und die Minimierung der Auswirkungen auf die Lastgeschwindigkeit der Seite wird.

Was soll ich tun, wenn ich auf den Codendruck auf Kleidungsstücke für Front-End-Thermalpapier-Quittungen stoße? Was soll ich tun, wenn ich auf den Codendruck auf Kleidungsstücke für Front-End-Thermalpapier-Quittungen stoße? Apr 04, 2025 pm 02:42 PM

Häufig gestellte Fragen und Lösungen für das Ticket-Ticket-Ticket-Ticket in Front-End im Front-End-Entwicklungsdruck ist der Ticketdruck eine häufige Voraussetzung. Viele Entwickler implementieren jedoch ...

Wie debugge ich den JavaScript -Code effektiv mithilfe von Browser -Entwickler -Tools? Wie debugge ich den JavaScript -Code effektiv mithilfe von Browser -Entwickler -Tools? Mar 18, 2025 pm 03:16 PM

In dem Artikel werden effektives JavaScript -Debuggen mithilfe von Browser -Entwickler -Tools, der Schwerpunkt auf dem Festlegen von Haltepunkten, der Konsole und der Analyse der Leistung erörtert.

Wer bekommt mehr Python oder JavaScript bezahlt? Wer bekommt mehr Python oder JavaScript bezahlt? Apr 04, 2025 am 12:09 AM

Es gibt kein absolutes Gehalt für Python- und JavaScript -Entwickler, je nach Fähigkeiten und Branchenbedürfnissen. 1. Python kann mehr in Datenwissenschaft und maschinellem Lernen bezahlt werden. 2. JavaScript hat eine große Nachfrage in der Entwicklung von Front-End- und Full-Stack-Entwicklung, und sein Gehalt ist auch beträchtlich. 3. Einflussfaktoren umfassen Erfahrung, geografische Standort, Unternehmensgröße und spezifische Fähigkeiten.

Wie verwende ich Quellkarten zum Debuggen, um den JavaScript -Code zu debuggen? Wie verwende ich Quellkarten zum Debuggen, um den JavaScript -Code zu debuggen? Mar 18, 2025 pm 03:17 PM

In dem Artikel wird erläutert, wie Quellkarten zum Debuggen von JavaScript verwendet werden, indem er auf den ursprünglichen Code zurückgegeben wird. Es wird erläutert, dass Quellenkarten aktiviert, Breakpoints eingestellt und Tools wie Chrome Devtools und WebPack verwendet werden.

Der Unterschied in der Konsole.log -Ausgabeergebnis: Warum unterscheiden sich die beiden Anrufe? Der Unterschied in der Konsole.log -Ausgabeergebnis: Warum unterscheiden sich die beiden Anrufe? Apr 04, 2025 pm 05:12 PM

Eingehende Diskussion der Ursachen des Unterschieds in der Konsole.log-Ausgabe. In diesem Artikel wird die Unterschiede in den Ausgabeergebnissen der Konsolenfunktion in einem Code analysiert und die Gründe dafür erläutert. � ...

TypeScript für Anfänger, Teil 2: Grundlegende Datentypen TypeScript für Anfänger, Teil 2: Grundlegende Datentypen Mar 19, 2025 am 09:10 AM

Sobald Sie das Typscript-Tutorial für Einstiegsklasse gemeistert haben, sollten Sie in der Lage sein, Ihren eigenen Code in eine IDE zu schreiben, die TypeScript unterstützt und in JavaScript zusammenfasst. Dieses Tutorial wird in verschiedenen Datentypen in TypeScript eingetaucht. JavaScript hat sieben Datentypen: NULL, UNDEFINED, BOOLEAN, NUMMER, STRING, SYMBOL (durch ES6 eingeführt) und Objekt. TypeScript definiert mehr Typen auf dieser Grundlage, und dieses Tutorial wird alle ausführlich behandelt. Null -Datentyp Wie JavaScript, null in TypeScript

See all articles