Maison  >  Article  >  interface Web  >  Exemple de méthode de suivi des modifications des variables JS

Exemple de méthode de suivi des modifications des variables JS

小云云
小云云original
2018-03-06 14:24:472090parcourir

J'ai maintenant une telle exigence. Je dois surveiller les changements d'une certaine variable dans js. Si la variable change, certains événements seront déclenchés. Je ne peux pas utiliser de méthodes de surveillance de synchronisation telles que timeinterval. il existe une meilleure solution.

La caractéristique commune des bibliothèques/frameworks MVVM JS populaires est la liaison de données, qui effectue automatiquement des calculs pertinents et modifie l'affichage DOM de manière réactive après les modifications des données. Cette question peut donc également être comprise comme comment implémenter la liaison de données de la bibliothèque/du framework MVVM.

Les implémentations courantes de liaison de données incluent la détection de valeurs sales, les getters et setters basés sur ES5, Object.observe abandonné d'ES et le proxy ajouté dans ES6.

Détection de valeur sale

angular utilise la détection de valeur sale, le principe est de comparer la nouvelle valeur et l'ancienne valeur, puis de changer le DOM lorsque la valeur change vraiment, il y a donc un $. dans un résumé angulaire. Alors pourquoi les instructions intégrées comme ng-click changent-elles automatiquement après avoir été déclenchées ? Le principe est également très simple, $digest est ajouté aux instructions intégrées telles que ng-click à la fin.

Mise en œuvre facile d'une détection de valeur sale :

<!DOCTYPE html><html>
    <head>
        <meta charset="utf-8" />
        <title>two-way binding</title>
    </head>
    <body onload="init()">
        <button ng-click="inc">
            Increase        </button>
        <button ng-click="reset">
            Reset        </button>
        <span style="color:red" ng-bind="counter"></span>
        <span style="color:blue" ng-bind="counter"></span>
        <span style="color:green" ng-bind="counter"></span>
        <script type="text/javascript">
            /* 数据模型区开始 */
            var counter = 0;            function inc() {
                counter++;
            }            function reset() {
                counter = 0;
            }            /* 数据模型区结束 */
            /* 绑定关系区开始 */
            function init() {
                bind();
            }            function bind() {                var list = document.querySelectorAll("[ng-click]");                for (var i=0; i<list.length; i++) {
                    list[i].onclick = (function(index) {                        return function() {                            window[list[index].getAttribute("ng-click")]();
                            apply();
                        };
                    })(i);
                }
            }            function apply() {                var list = document.querySelectorAll("[ng-bind=&#39;counter&#39;]");                for (var i=0; i<list.length; i++) {                    if (list[i].innerHTML != counter) {
                        list[i].innerHTML = counter;
                    }
                }
            }            /* 绑定关系区结束 */
        </script>
    </body></html>

L'inconvénient est qu'après avoir modifié les données, vous ne pouvez pas modifier automatiquement le DOM. Vous devez trouver un moyen de déclencher l'application (. ), vous ne pouvez donc utiliser que l'emballage de ng-click pour inclure la surveillance des événements de clic réel et ajouter une détection de valeurs sales pour déterminer s'il convient de mettre à jour le DOM.

Un autre inconvénient est que si vous ne faites pas attention, chaque détection de valeur sale détectera une grande quantité de données, et beaucoup de données ne sont pas nécessaires pour la détection, ce qui peut facilement affecter les performances.

Concernant la façon d'implémenter une détection de valeur sale comme Angular, après avoir connu le principe, il reste encore beaucoup de travail à faire, ainsi que la façon d'optimiser et ainsi de suite. Si vous êtes intéressé, vous pouvez lire « Build Your Own Angular.js » que Migong Shu a déjà recommandé. Le premier chapitre, Scope, explique comment implémenter la portée d'Angular et la détection des valeurs sales. À propos, l'exemple ci-dessus est également légèrement modifié à partir du blog de l'oncle travailleur migrant. Il est recommandé de lire le texte original à la fin. Le lien se trouve dans les documents de référence.

Les getters et setters ES5

Un nouveau Object.defineProperty est ajouté dans ES5, qui peut définir directement une nouvelle propriété sur un objet, ou modifier une propriété existante et renvoyer l'objet.

Object.defineProperty(obj, prop, descriptor)

Le troisième paramètre qu'il accepte peut être get et set et chacun correspond à une méthode getter et setter :

var a = { zhihu:0 };Object.defineProperty(a, &#39;zhihu&#39;, {  get: function() {    console.log(&#39;get:&#39; + zhihu);    return zhihu;
  },  set: function(value) {
    zhihu = value;    console.log(&#39;set:&#39; + zhihu);
  }
});
a.zhihu = 2; // set:2console.log(a.zhihu); // get:2
                      // 2

Le getter et le setter basés sur ES5 peuvent être considérés comme étant presque parfait demandé. Pourquoi dire presque ?

Tout d'abord, IE8 et les versions inférieures d'IE ne peuvent pas être utilisées, et cette fonctionnalité n'a pas de polyfill et ne peut pas être implémentée sur des plates-formes non prises en charge. C'est pourquoi Vue.js basé sur les getters et setters ES5 ne le fait pas. prend en charge IE8 et supérieur. La raison est la version inférieure d'IE. Peut-être que quelqu'un mentionnera qu'Avalon utilise un peu de magie noire de vbscript pour réaliser des fonctions similaires dans les versions inférieures d'IE.

De plus, un autre problème est que la modification de la longueur du tableau, la définition directe des éléments avec des index tels que items[0] = {}, et les méthodes de mutation telles que le push du tableau ne peuvent pas déclencher le setter. Si vous souhaitez résoudre ce problème, vous pouvez vous référer à l'approche de Vue. Dans observer/array.js de Vue, Vue modifie directement la méthode prototype du tableau :

const arrayProto = Array.prototypeexport const arrayMethods = Object.create(arrayProto)/**
 * Intercept mutating methods and emit events
 */;[  &#39;push&#39;,  &#39;pop&#39;,  &#39;shift&#39;,  &#39;unshift&#39;,  &#39;splice&#39;,  &#39;sort&#39;,  &#39;reverse&#39;]
.forEach(function (method) {  // cache original method
  var original = arrayProto[method]
  def(arrayMethods, method, function mutator () {    // avoid leaking arguments:
    // http://jsperf.com/closure-with-arguments
    var i = arguments.length    var args = new Array(i)    while (i--) {
      args[i] = arguments[i]
    }    var result = original.apply(this, args)    var ob = this.__ob__    var inserted    switch (method) {      case &#39;push&#39;:
        inserted = args        break
      case &#39;unshift&#39;:
        inserted = args        break
      case &#39;splice&#39;:
        inserted = args.slice(2)        break
    }    if (inserted) ob.observeArray(inserted)    // notify change
    ob.dep.notify()    return result
  })
});

De cette façon, la méthode prototype est réécrit et le tableau est exécuté. La mise à jour de la vue peut toujours être déclenchée après la mutation de la méthode.

Mais cela ne peut toujours pas résoudre le problème de la modification de la longueur du tableau et de l'utilisation directe de l'index pour définir des éléments tels que items[0] = {}. Si vous souhaitez résoudre le problème, vous pouvez toujours vous référer. à l'approche de Vue : pour le premier problème, vous pouvez directement utiliser new Array pour remplacer l'ancien tableau ; ce dernier problème peut être étendu par une méthode $set pour le tableau, qui déclenche la mise à jour de la vue après la modification.

Object.observe obsolète

Object.observe était dans le brouillon d'ES7 et a progressé jusqu'à l'étape 2 de la proposition, mais a finalement été abandonné. Voici juste un exemple de MDN :

// 一个数据模型var user = {  id: 0,  name: &#39;Brendan Eich&#39;,  title: &#39;Mr.&#39;};// 创建用户的greetingfunction updateGreeting() {
  user.greeting = &#39;Hello, &#39; + user.title + &#39; &#39; + user.name + &#39;!&#39;;
}
updateGreeting();Object.observe(user, function(changes) {
  changes.forEach(function(change) {    // 当name或title属性改变时, 更新greeting
    if (change.name === &#39;name&#39; || change.name === &#39;title&#39;) {
      updateGreeting();
    }
  });
});

Parce qu'il s'agit d'une fonctionnalité obsolète, bien que Chrome l'ait déjà prise en charge, il a également rendu le support obsolète, je n'entrerai pas dans plus de détails ici. Si vous êtes intéressé, vous pouvez le rechercher. Article précédent, C'était une fonctionnalité prometteuse (la révolution de la liaison de données provoquée par Object.observe()). Bien sûr, il existe des alternatives à Polymer/observe-js.

Le Proxy apporté par ES6

est comme son nom l'indique, similaire au proxy en HTTP :

var p = new Proxy(target, handler);

target est l'objet cible, qui peut être de n'importe quel type d'objet, tel qu'un tableau, une fonction ou même un autre objet proxy. Handler est un objet processeur qui contient un ensemble de méthodes proxy pour contrôler divers comportements des objets proxy générés.

Par exemple :

let a = new Proxy({}, {  set: function(obj, prop, value) {
    obj[prop] = value;    if (prop === &#39;zhihu&#39;) {      console.log("set " + prop + ": " + obj[prop]);
    }    return true;
  }
});
a.zhihu = 100;

Bien sûr, les capacités du proxy vont bien au-delà et peuvent également implémenter le transfert de proxy, etc.

Mais il convient de noter qu'actuellement, seul Firefox 18 prend en charge cette fonctionnalité, et babel déclare officiellement qu'il ne prend pas en charge cette fonctionnalité :

Unsupported feature
Due to the limitations of ES5, Proxies cannot be transpiled or polyfilled.

Il existe actuellement des plug-ins babel qui peuvent mettre en œuvre, mais on dit que la mise en œuvre est plus compliquée. S'il s'agit de Node, vous devriez pouvoir l'utiliser après la mise à niveau vers la dernière version. L'environnement de test pour l'exemple ci-dessus est Node v6.4.0.

Recommandations associées :

Explication détaillée de la promotion des variables js

Introduction aux variables JS et à leurs points de connaissance sur la portée

Explication détaillée des exemples de promotion de variable js et de déclaration de fonction avant l'analyse

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn