Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Analyse der Gesamtarchitektur von Underscore

Eine kurze Analyse der Gesamtarchitektur von Underscore

高洛峰
高洛峰Original
2016-11-05 09:23:511096Durchsuche

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 等等
Unser Ziel ist es, die konstruierte Instanz von _ auch in die Lage zu versetzen, diese Methoden aufzurufen. Wenn Sie sorgfältig darüber nachdenken, ist es eigentlich nicht schwierig, die Attribute auf _ zu durchlaufen. Wenn der Attributwerttyp eine Funktion ist, hängen Sie die Funktion an die Prototypenkette von _.

Die _.mixin-Methode, die dazu im Quellcode verwendet wird:

// 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(_);
Die _.mixin-Methode kann Ihre eigenen definierten Methoden zur Underscore-Bibliothek hinzufügen:

_.mixin({ 
  capitalize: function(string) { 
    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); 
  } 
}); 
_("fabio").capitalize(); 
=> "Fabio"
Gleichzeitig fügt Underscore auch einige native Array-Methoden hinzu:

// 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)); 
  }; 
});
Kettenaufruf

Underscore unterstützt auch Kettenaufrufe:

// 非 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
Zha Auf den ersten Blick scheint es zwei Formen des Kettenaufrufs zu geben: OOP und Nicht-OOP. Tatsächlich gibt es nur eine Form. Die Ergebnisse von _.chain([1, 2, 3]) und _([1 , 2, 3]).chain() sind gleich. Wie implementiert man es? Schauen wir uns die Kettenmethode genauer an.

_.chain = function(obj) {

_.chain = function(obj) { 
  // 无论是否 OOP 调用,都会转为 OOP 形式 
  // 并且给新的构造对象添加了一个 _chain 属性 
  var instance = _(obj); 
 
  // 标记是否使用链式操作 
  instance._chain = true; 
 
  // 返回 OOP 对象 
  // 可以看到该 instance 对象除了多了个 _chain 属性 
  // 其他的和直接 _(obj) 的结果一样 
  return instance; 
};
Sehen wir uns das Ergebnis von _.chain([1, 2, 3]) an und ersetzen die Parameter in der Funktion. Konstruieren Sie tatsächlich die Parameter ohne neue und geben Sie dann die Instanz zurück, mit der Ausnahme, dass die Instanz ein zusätzliches _chain-Attribut hat und der Rest genau derselbe ist wie direkt _([1, 2, 3]). Schauen wir uns _([1, 2, 3]).chain() an. _([1, 2, 3]) gibt eine konstruierte Instanz zurück. Rufen Sie die Methode auf und fügen Sie das _chain-Attribut hinzu Instanz und geben Sie das Objekt zurück. Daher sind die Auswirkungen der beiden konsistent und die Ergebnisse werden in OOP konvertiert.

Nachdem wir so viel gesagt haben, scheinen wir noch nicht auf den Punkt gekommen zu sein. Wie wird es „verkettet“? Nehmen wir den folgenden Code als Beispiel:

_([1, 2, 3]) 
  .chain() 
  .map(function(a){return a * 2;}) 
  .first() 
  .value(); // 2
Wann Die Map-Methode wird aufgerufen. Möglicherweise gibt es tatsächlich einen Rückgabewert. Werfen wir einen Blick auf den _.mixin-Quellcode:

// 执行 func 方法 
// 支持链式操作 
return result(this, func.apply(_, args));
Ergebnis ist eine wichtige interne Hilfsfunktion:

// Helper function to continue chaining intermediate results. 
// 一个帮助方法(Helper function) 
var result = function(instance, obj) { 
// 如果需要链式操作,则对 obj 运行 chain 方法,使得可以继续后续的链式操作 
// 如果不需要,直接返回 obj 
return instance._chain ? _(obj).chain() : obj; 
};
Wenn Kettenoperationen erforderlich sind (die Instanz verfügt über das _chain-Attribut). ) wird die Kettenfunktion für das Operationsergebnis aufgerufen, sodass sie weiterhin in der Kette aufgerufen werden kann.



Stellungnahme:
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