Table des matières
definePropety
Setters et Getters
watch API
proxy
watch API 优化
Maison interface Web js tutoriel Introduction détaillée à DefineProperty et proxy dans ES6 (exemple de code)

Introduction détaillée à DefineProperty et proxy dans ES6 (exemple de code)

Nov 15, 2018 pm 04:59 PM
handler javascript 交互设计 函数 前端

Cet article vous apporte une introduction détaillée (exemple de code) sur DefineProperty et proxy dans ES6. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Nous avons tous plus ou moins entendu le mot « liaison de données ». La clé de la « liaison de données » est de surveiller les changements dans les données, mais pour un tel objet : var obj = {value: 1}, comment savons-nous obj Quoi ? a changé ?

definePropety

ES5 fournit la méthode Object.defineProperty, qui peut définir une nouvelle propriété sur un objet, ou modifier une propriété existante d'un objet et renvoyer l'objet.

Syntaxe

Object.defineProperty(obj, prop, descriptor)
Copier après la connexion

Paramètres

obj: 要在其上定义属性的对象。
prop:  要定义或修改的属性的名称。
descriptor: 将被定义或修改的属性的描述符。
Copier après la connexion

Par exemple :

var obj = {};
Object.defineProperty(obj, "num", {
    value : 1,
    writable : true,
    enumerable : true,
    configurable : true
});
//  对象 obj 拥有属性 num,值为 1
Copier après la connexion

Bien que nous puissions ajouter des propriétés et des valeurs directement, en utilisant cette méthode, nous pouvons effectuer davantage de configuration. Le descripteur d'attribut représenté par le troisième descripteur de paramètre de la fonction

a deux formes : descripteur de données et descripteur d'accès .

Les deux ont les deux valeurs clés suivantes  :

configurable

si et seulement si l'attribut configurable est Quand vrai, le descripteur de propriété peut être modifié ou supprimé. La valeur par défaut est fausse.

enumerable

Si et seulement si l'énumérable de l'attribut est vrai, l'attribut peut apparaître dans l'attribut d'énumération de l'objet. La valeur par défaut est fausse.

Le descripteur de données possède également les valeurs clés facultatives suivantes  :

valeur

La valeur correspondant à cet attribut. Il peut s'agir de n'importe quelle valeur JavaScript valide (nombre, objet, fonction, etc.). La valeur par défaut n'est pas définie.

writable

Cette propriété peut être modifiée par l'opérateur d'affectation si et seulement si l'écriture de la propriété est vraie. La valeur par défaut est fausse.

Le descripteur d'accès a également les valeurs de clés facultatives suivantes  :

get

celle fournie pour la méthode Getter d'attribut, s'il n'y a pas de getter, il n'est pas défini. La valeur de retour de cette méthode est utilisée comme valeur d'attribut. La valeur par défaut n'est pas définie.

set

Une méthode qui fournit un setter pour une propriété. S'il n'y a pas de setter, elle n'est pas définie. . Cette méthode acceptera un paramètre unique et attribuera la nouvelle valeur du paramètre à la propriété. La valeur par défaut n'est pas définie.

Il convient de noter :

Les descripteurs d'attribut doivent être soit des descripteurs de données, soit des descripteurs d'accès, pas les deux en même temps. Cela signifie que vous pouvez :

Object.defineProperty({}, "num", {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
});
Copier après la connexion

Également :

var value = 1;
Object.defineProperty({}, "num", {
    get : function(){
      return value;
    },
    set : function(newValue){
      value = newValue;
    },
    enumerable : true,
    configurable : true
});
Copier après la connexion

Mais pas :

// 报错
Object.defineProperty({}, "num", {
    value: 1,
    get: function() {
        return 1;
    }
});
Copier après la connexion

De plus, toutes les descriptions d'attributs Les descripteurs ne sont pas obligatoires , mais le champ descripteur est obligatoire. Si vous n'effectuez aucune configuration, vous pouvez faire ceci :

var obj = Object.defineProperty({}, "num", {});
console.log(obj.num); // undefined
Copier après la connexion

Setters et Getters

La raison pour laquelle nous parlons de DefineProperty est parce que nous en avons besoin. pour utiliser get et set dans le descripteur d'accès. Ces deux méthodes sont également appelées getters et setters. Les propriétés définies par les getters et les setters sont appelées « propriétés d'accesseur ».

Lorsqu'un programme interroge la valeur d'une propriété d'accesseur, JavaScript appelle la méthode getter. La valeur de retour de cette méthode est la valeur de l'expression d'accès à l'attribut. Lorsqu'un programme définit la valeur d'une propriété d'accesseur, JavaScript appelle la méthode setter, en transmettant la valeur située à droite de l'expression d'affectation en tant que paramètre au setter. Dans un sens, cette méthode est chargée de « définir » la valeur de la propriété. La valeur de retour de la méthode setter peut être ignorée.

Par exemple :

var obj = {}, value = null;
Object.defineProperty(obj, "num", {
    get: function(){
        console.log('执行了 get 操作')
        return value;
    },
    set: function(newValue) {
        console.log('执行了 set 操作')
        value = newValue;
    }
})

obj.value = 1 // 执行了 set 操作

console.log(obj.value); // 执行了 get 操作 // 1
Copier après la connexion

N'est-ce pas la méthode avec laquelle nous souhaitons surveiller les modifications des données ? Encapsulons-le à nouveau :

function Archiver() {
    var value = null;
    // archive n. 档案
    var archive = [];

    Object.defineProperty(this, 'num', {
        get: function() {
            console.log('执行了 get 操作')
            return value;
        },
        set: function(value) {
            console.log('执行了 set 操作')
            value = value;
            archive.push({ val: value });
        }
    });

    this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.num; // 执行了 get 操作
arc.num = 11; // 执行了 set 操作
arc.num = 13; // 执行了 set 操作
console.log(arc.getArchive()); // [{ val: 11 }, { val: 13 }]
Copier après la connexion

watch API

Étant donné que les modifications des données peuvent être surveillées, je peux imaginer que lorsque les données changent, le travail de rendu sera automatiquement effectué. Par exemple :

Il y a une balise span et une balise bouton en HTML

<span id="container">1</span>
<button id="button">点击加 1</button>
Copier après la connexion

Lorsque l'on clique sur le bouton, la valeur de la balise span est augmentée de 1.

L'approche traditionnelle est :

document.getElementById(&#39;button&#39;).addEventListener("click", function(){
    var container = document.getElementById("container");
    container.innerHTML = Number(container.innerHTML) + 1;
});
Copier après la connexion

Si DefineProperty est utilisé :

var obj = {
    value: 1
}

// 储存 obj.value 的值
var value = 1;

Object.defineProperty(obj, "value", {
    get: function() {
        return value;
    },
    set: function(newValue) {
        value = newValue;
        document.getElementById(&#39;container&#39;).innerHTML = newValue;
    }
});

document.getElementById(&#39;button&#39;).addEventListener("click", function() {
    obj.value += 1;
});
Copier après la connexion

Le code semble augmenter, mais lorsque nous devons changer la valeur dans le span tagQuand, modifiez simplement la valeur de obj.value directement.

Cependant, avec la façon actuelle d'écrire, nous devons toujours déclarer une variable distincte pour stocker la valeur de obj.value, car si vous obj.value = newValue directement dans set, vous tomberez dans une boucle infinie. De plus, nous devrons peut-être surveiller les changements dans de nombreuses valeurs d'attributs. Il serait fastidieux de les écrire une par une, nous écrivons donc simplement une fonction de surveillance. L'effet d'utilisation est le suivant :

var obj = {
    value: 1
}

watch(obj, "num", function(newvalue){
    document.getElementById(&#39;container&#39;).innerHTML = newvalue;
})

document.getElementById(&#39;button&#39;).addEventListener("click", function(){
    obj.value += 1
});
Copier après la connexion

Écrivons cette fonction de surveillance :

(function(){
    var root = this;
    function watch(obj, name, func){
        var value = obj[name];

        Object.defineProperty(obj, name, {
            get: function() {
                return value;
            },
            set: function(newValue) {
                value = newValue;
                func(value)
            }
        });

        if (value) obj[name] = value
    }

    this.watch = watch;
})()
Copier après la connexion

Nous pouvons maintenant surveiller les changements dans les valeurs d'attribut de l'objet, et en fonction des changements dans le valeurs d'attribut, ajoutez une fonction de rappel, génial ~

proxy

L'utilisation de definitionProperty ne peut redéfinir que les comportements de lecture (get) et de définition (set) des propriétés Dans ES6, le proxy est fourni et peut être. redéfini. Plus de comportements, tels que l'entrée, la suppression, les appels de fonction et plus encore.

Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。我们来看看它的语法:

var proxy = new Proxy(target, handler);
Copier après la connexion

proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

var proxy = new Proxy({}, {
    get: function(obj, prop) {
        console.log(&#39;设置 get 操作&#39;)
        return obj[prop];
    },
    set: function(obj, prop, value) {
        console.log(&#39;设置 set 操作&#39;)
        obj[prop] = value;
    }
});

proxy.time = 35; // 设置 set 操作

console.log(proxy.time); // 设置 get 操作 // 35
Copier après la connexion

除了 get 和 set 之外,proxy 可以拦截多达 13 种操作,比如 has(target, propKey),可以拦截 propKey in proxy 的操作,返回一个布尔值。

// 使用 has 方法隐藏某些属性,不被 in 运算符发现
var handler = {
  has (target, key) {
    if (key[0] === &#39;_&#39;) {
      return false;
    }
    return key in target;
  }
};
var target = { _prop: &#39;foo&#39;, prop: &#39;foo&#39; };
var proxy = new Proxy(target, handler);
console.log(&#39;_prop&#39; in proxy); // false
Copier après la connexion

又比如说 apply 方法拦截函数的调用、call 和 apply 操作。

apply 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组,不过这里我们简单演示一下:

var target = function () { return &#39;I am the target&#39;; };
var handler = {
  apply: function () {
    return &#39;I am the proxy&#39;;
  }
};

var p = new Proxy(target, handler);

p();
// "I am the proxy"
Copier après la connexion

又比如说 ownKeys 方法可以拦截对象自身属性的读取操作。具体来说,拦截以下操作:

  • Object.getOwnPropertyNames()

  • Object.getOwnPropertySymbols()

  • Object.keys()

下面的例子是拦截第一个字符为下划线的属性名,不让它被 for of 遍历到。

let target = {
  _bar: &#39;foo&#39;,
  _prop: &#39;bar&#39;,
  prop: &#39;baz&#39;
};

let handler = {
  ownKeys (target) {
    return Reflect.ownKeys(target).filter(key => key[0] !== &#39;_&#39;);
  }
};

let proxy = new Proxy(target, handler);
for (let key of Object.keys(proxy)) {
  console.log(target[key]);
}
// "baz"
Copier après la connexion

更多的拦截行为可以查看阮一峰老师的 《ECMAScript 6 入门》

值得注意的是,proxy 的最大问题在于浏览器支持度不够,而且很多效果无法使用 poilyfill 来弥补。

watch API 优化

我们使用 proxy 再来写一下 watch 函数。使用效果如下:

(function() {
    var root = this;

    function watch(target, func) {

        var proxy = new Proxy(target, {
            get: function(target, prop) {
                return target[prop];
            },
            set: function(target, prop, value) {
                target[prop] = value;
                func(prop, value);
            }
        });

        if(target[name]) proxy[name] = value;
        return proxy;
    }

    this.watch = watch;
})()

var obj = {
    value: 1
}

var newObj = watch(obj, function(key, newvalue) {
    if (key == &#39;value&#39;) document.getElementById(&#39;container&#39;).innerHTML = newvalue;
})

document.getElementById(&#39;button&#39;).addEventListener("click", function() {
    newObj.value += 1
});
Copier après la connexion

我们也可以发现,使用 defineProperty 和 proxy 的区别,当使用 defineProperty,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截。

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 de ce site Web
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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Conseils pour créer dynamiquement de nouvelles fonctions dans les fonctions Golang Conseils pour créer dynamiquement de nouvelles fonctions dans les fonctions Golang Apr 25, 2024 pm 02:39 PM

Le langage Go propose deux technologies de création de fonctions dynamiques : la fermeture et la réflexion. les fermetures permettent d'accéder aux variables dans la portée de la fermeture, et la réflexion peut créer de nouvelles fonctions à l'aide de la fonction FuncOf. Ces technologies sont utiles pour personnaliser les routeurs HTTP, mettre en œuvre des systèmes hautement personnalisables et créer des composants enfichables.

Considérations relatives à l'ordre des paramètres dans la dénomination des fonctions C++ Considérations relatives à l'ordre des paramètres dans la dénomination des fonctions C++ Apr 24, 2024 pm 04:21 PM

Dans la dénomination des fonctions C++, il est crucial de prendre en compte l’ordre des paramètres pour améliorer la lisibilité, réduire les erreurs et faciliter la refactorisation. Les conventions courantes d'ordre des paramètres incluent : action-objet, objet-action, signification sémantique et conformité de la bibliothèque standard. L'ordre optimal dépend de l'objectif de la fonction, des types de paramètres, de la confusion potentielle et des conventions du langage.

Comment écrire des fonctions efficaces et maintenables en Java ? Comment écrire des fonctions efficaces et maintenables en Java ? Apr 24, 2024 am 11:33 AM

La clé pour écrire des fonctions Java efficaces et maintenables est la suivante : restez simple. Utilisez un nom significatif. Gérer des situations particulières. Utilisez une visibilité appropriée.

Collection complète de formules de fonctions Excel Collection complète de formules de fonctions Excel May 07, 2024 pm 12:04 PM

1. La fonction SOMME permet de sommer les nombres d'une colonne ou d'un groupe de cellules, par exemple : =SOMME(A1:J10). 2. La fonction MOYENNE permet de calculer la moyenne des nombres dans une colonne ou un groupe de cellules, par exemple : =AVERAGE(A1:A10). 3. Fonction COUNT, utilisée pour compter le nombre de nombres ou de texte dans une colonne ou un groupe de cellules, par exemple : =COUNT(A1:A10) 4. Fonction IF, utilisée pour effectuer des jugements logiques basés sur des conditions spécifiées et renvoyer le résultat correspondant.

Comparaison des avantages et des inconvénients des paramètres par défaut et des paramètres variables des fonctions C++ Comparaison des avantages et des inconvénients des paramètres par défaut et des paramètres variables des fonctions C++ Apr 21, 2024 am 10:21 AM

Les avantages des paramètres par défaut dans les fonctions C++ incluent la simplification des appels, l’amélioration de la lisibilité et l’évitement des erreurs. Les inconvénients sont une flexibilité limitée et des restrictions de dénomination. Les avantages des paramètres variadiques incluent une flexibilité illimitée et une liaison dynamique. Les inconvénients incluent une plus grande complexité, des conversions de types implicites et des difficultés de débogage.

Quels sont les avantages des fonctions C++ renvoyant des types référence ? Quels sont les avantages des fonctions C++ renvoyant des types référence ? Apr 20, 2024 pm 09:12 PM

Les avantages des fonctions renvoyant des types référence en C++ incluent : Améliorations des performances : le passage par référence évite la copie d'objets, économisant ainsi de la mémoire et du temps. Modification directe : L'appelant peut modifier directement l'objet de référence renvoyé sans le réaffecter. Simplicité du code : le passage par référence simplifie le code et ne nécessite aucune opération d'affectation supplémentaire.

Quelle est la différence entre les fonctions PHP personnalisées et les fonctions prédéfinies ? Quelle est la différence entre les fonctions PHP personnalisées et les fonctions prédéfinies ? Apr 22, 2024 pm 02:21 PM

La différence entre les fonctions PHP personnalisées et les fonctions prédéfinies est la suivante : Portée : les fonctions personnalisées sont limitées à la portée de leur définition, tandis que les fonctions prédéfinies sont accessibles tout au long du script. Comment définir : les fonctions personnalisées sont définies à l'aide du mot-clé function, tandis que les fonctions prédéfinies sont définies par le noyau PHP. Passage de paramètres : les fonctions personnalisées reçoivent des paramètres, tandis que les fonctions prédéfinies peuvent ne pas nécessiter de paramètres. Extensibilité : des fonctions personnalisées peuvent être créées selon les besoins, tandis que les fonctions prédéfinies sont intégrées et ne peuvent pas être modifiées.

Exception de fonction C++ avancée : gestion personnalisée des erreurs Exception de fonction C++ avancée : gestion personnalisée des erreurs May 01, 2024 pm 06:39 PM

La gestion des exceptions en C++ peut être améliorée grâce à des classes d'exceptions personnalisées qui fournissent des messages d'erreur spécifiques, des informations contextuelles et effectuent des actions personnalisées en fonction du type d'erreur. Définissez une classe d'exception héritée de std::exception pour fournir des informations d'erreur spécifiques. Utilisez le mot-clé throw pour lancer une exception personnalisée. Utilisez Dynamic_cast dans un bloc try-catch pour convertir l'exception interceptée en un type d'exception personnalisé. Dans le cas réel, la fonction open_file lève une exception FileNotFoundException. La capture et la gestion de l'exception peuvent fournir un message d'erreur plus spécifique.

See all articles