Vorwort
Schließlich geht die Underscore-Analyse des Posters zu Ende. Wenn Sie auf die Zeitleiste achten, werden Sie feststellen, dass das Poster die Interpretationsgeschwindigkeit kürzlich beschleunigt hat . Der November ist ein ereignisreicher Monat, da in letzter Zeit viel passiert ist. Er möchte diese Serie auch so schnell wie möglich beenden, aber er hat nur eines im Kopf.
Dieser Artikel wird voraussichtlich der vorletzte Artikel in der Interpretationsreihe sein, und der letzte Artikel ist offensichtlich die Zusammenfassung. Die vollständige Version der Interpretation der Underscore-Serie des Posters finden Sie unter https://github.com/hanzichi/u...
Regelmäßige Anrufe
In den zuvor geschriebenen Artikeln liegt der Schwerpunkt größtenteils auf Einige Leser haben auch eine Nachricht hinterlassen, die darauf hindeutet, dass der Poster über die Gesamtarchitektur spricht. Dies ist etwas, das gelehrt werden muss, aber der Poster hat es am Ende, also in diesem Artikel, arrangiert, weil der Poster das Gefühl hat, dass wenn Er beherrscht die Gesamtarchitektur nicht, er wird kein großes Verständnis für die spezifischen Methoden haben.
Unterstrich wird am häufigsten in der Form _.funcName(xx, xx) aufgerufen, was auch die aufrufende Methode im Dokument ist.
_.each([1, 2, 3], alert);
Der einfachste Weg, dies zu implementieren, besteht darin, dass wir _ als einfaches Objekt betrachten können:
var _ = {}; _.each = function() { // ... };
In JavaScript ist tatsächlich alles ein Objekt Code Eine Variable ist eine Methode:
var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; };
Warum ist es eine Methode?
OOP
Underscore unterstützt die OOP-Aufrufform:
_([1, 2, 3]).each(alert);
Dies ist eigentlich eine sehr klassische „keine neue Konstruktion“, _ ist eigentlich ein Konstruktor, _( [ 1, 2, 3]) Das Ergebnis ist eine Objektinstanz, die ein _wrapped-Attribut hat und der Attributwert [1, 2, 3] ist. Die Instanz muss jede Methode aufrufen, sie sollte aus der Prototypenkette stammen, das heißt, es sollte diese Methode auf _.prototype geben >
Methodenmontage Jetzt haben wir folgende zwei Punkte klargestellt:_ 是一个函数(支持无 new 调用的构造函数) _ 的属性有很多方法,比如 _.each,_.template 等等
// Add your own custom functions to the Underscore object. // 可向 underscore 函数库扩展自己的方法 // obj 参数必须是一个对象(JavaScript 中一切皆对象) // 且自己的方法定义在 obj 的属性上 // 如 obj.myFunc = function() {...} // 形如 {myFunc: function(){}} // 之后便可使用如下: _.myFunc(..) 或者 OOP _(..).myFunc(..) _.mixin = function(obj) { // 遍历 obj 的 key,将方法挂载到 Underscore 上 // 其实是将方法浅拷贝到 _.prototype 上 _.each(_.functions(obj), function(name) { // 直接把方法挂载到 _[name] 上 // 调用类似 _.myFunc([1, 2, 3], ..) var func = _[name] = obj[name]; // 浅拷贝 // 将 name 方法挂载到 _ 对象的原型链上,使之能 OOP 调用 _.prototype[name] = function() { // 第一个参数 var args = [this._wrapped]; // arguments 为 name 方法需要的其他参数 push.apply(args, arguments); // 执行 func 方法 // 支持链式操作 return result(this, func.apply(_, args)); }; }); }; // Add all of the Underscore functions to the wrapper object. // 将前面定义的 underscore 方法添加给包装过的对象 // 即添加到 _.prototype 中 // 使 underscore 支持面向对象形式的调用 _.mixin(_);
_.mixin({ capitalize: function(string) { return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); } }); _("fabio").capitalize(); => "Fabio"
// Add all mutator Array functions to the wrapper. // 将 Array 原型链上有的方法都添加到 underscore 中 _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; // 支持链式操作 return result(this, obj); }; }); // Add all accessor Array functions to the wrapper. // 添加 concat、join、slice 等数组原生方法给 Underscore _.each(['concat', 'join', 'slice'], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { return result(this, method.apply(this._wrapped, arguments)); }; });
// 非 OOP 链式调用 _.chain([1, 2, 3]) .map(function(a) {return a * 2;}) .reverse() .value(); // [6, 4, 2] // OOP 链式调用 _([1, 2, 3]) .chain() .map(function(a){return a * 2;}) .first() .value(); // 2
_.chain = function(obj) { // 无论是否 OOP 调用,都会转为 OOP 形式 // 并且给新的构造对象添加了一个 _chain 属性 var instance = _(obj); // 标记是否使用链式操作 instance._chain = true; // 返回 OOP 对象 // 可以看到该 instance 对象除了多了个 _chain 属性 // 其他的和直接 _(obj) 的结果一样 return instance; };
_([1, 2, 3]) .chain() .map(function(a){return a * 2;}) .first() .value(); // 2
// 执行 func 方法 // 支持链式操作 return result(this, func.apply(_, args));
// Helper function to continue chaining intermediate results. // 一个帮助方法(Helper function) var result = function(instance, obj) { // 如果需要链式操作,则对 obj 运行 chain 方法,使得可以继续后续的链式操作 // 如果不需要,直接返回 obj return instance._chain ? _(obj).chain() : obj; };