Je ne le saurai pas non plus, rentrez chez moi et cultivez.
La copie de code est la suivante:
Supprimer ceiSobject [clé]
ou
supprimer ceiSobject.key
Au fait, parlons de l'utilisation de Supprimer
Il y a quelques semaines, j'ai eu la chance de lire le livre JavaScript orienté objet de Stoyan Stefanov. Ce livre est très bien évalué sur Amazon (12 critiques, 5 étoiles), donc j'étais curieux de voir si c'était un livre tel recommandé, alors j'ai commencé à lire le chapitre des fonctions. J'apprécie vraiment la façon dont ce livre explique les choses, et les exemples sont organisés d'une manière très belle et progressive, et il semble que même les débutants puissent facilement maîtriser ces connaissances. Cependant, presque immédiatement, j'ai découvert un malentendu intéressant tout au long du chapitre - supprimant les fonctions fonctionnelles. Il existe également d'autres erreurs (telles que la différence entre les déclarations de fonction et les expressions de fonction), mais nous n'en discuterons pas pour le moment.
Le livre affirme:
"La fonction est traitée comme une variable normale - elle peut être copiée dans différentes variables, ou même supprimé". Un exemple est attaché à cette explication:
La copie de code est la suivante:
var sum = fonction (a, b) {return a + b;}
var add = sum;
Supprimer la somme
vrai
type de somme;
"indéfini"
Ignorez certains demi-colons manquants, pouvez-vous voir où sont les erreurs de ces codes? De toute évidence, l'erreur est que le fonctionnement de la suppression de la variable de somme ne réussira pas. L'expression de suppression ne doit pas retourner True et le type de somme ne doit pas retourner "Undefined". Tout cela est parce qu'il est impossible de supprimer les variables en JavaScript. Du moins, il est impossible de cette manière de déclarer.
Alors, que s'est-il passé exactement dans cet exemple? Est-ce un bug? Ou une utilisation spéciale? Probablement pas. Ce code est en fait la sortie réelle de la console Firebug, et Stoyan doit l'avoir utilisé comme outil pour des tests rapides. C'est presque comme si Firebug suit d'autres règles de suppression. C'est Firebug qui a fait égarer Stoyan! Alors, que s'est-il passé exactement ici?
Avant de répondre à cette question, nous devons d'abord comprendre comment l'opérateur de suppression fonctionne en JavaScript: que peut être supprimé exactement et qu'est-ce qui ne peut pas être supprimé? Aujourd'hui, je vais essayer d'expliquer cela en détail. Nous examinerons le comportement "étrange" de Firebug et nous réaliserons que ce n'est pas si bizarre. Nous allons approfondir ce qui est caché dans les coulisses où les variables, les fonctions, attribuer des valeurs aux attributs et les supprimer. Nous examinerons la compatibilité du navigateur et certains des bugs les plus notoires. Nous discuterons également du modèle strict d'ES5 et de la façon dont il modifie le comportement des opérateurs de suppression.
Je vais échanger JavaScript et Ecmascript, qui signifient tous les deux ECMascript (à moins qu'il ne soit évident que l'implémentation JavaScript de Mozilla)
Comme prévu, sur Internet, les explications de la suppression sont assez rares. L'article MDC est probablement la meilleure ressource à comprendre, mais, malheureusement, il manque des détails intéressants sur le sujet. Étrangement, l'une des choses oubliées est la raison de l'étrange manifestation de Firebug. Et la référence MSDN est presque inutile dans ces aspects.
Théorie
Alors, pourquoi pouvons-nous supprimer les propriétés d'un objet:
La copie de code est la suivante:
var o = {x: 1};
supprimer le bœuf; // vrai
bœuf; // indéfini
Mais l'objet déclaré comme celui-ci ne peut pas être supprimé:
La copie de code est la suivante:
var x = 1;
supprimer x; // FAUX
x; // 1
Ou la fonction:
La copie de code est la suivante:
fonction x () {}
supprimer x; // FAUX
typeof x; // "fonction"
Remarque: Lorsqu'une propriété ne peut pas être supprimée, l'opérateur de suppression ne rendra que faux.
Pour comprendre cela, nous devons d'abord maîtriser ces concepts sur les instances variables et les propriétés d'attribut - ces concepts sont malheureusement mentionnés dans les livres JavaScript. Je vais essayer de passer brièvement ces concepts dans les prochains paragraphes. Ces concepts sont difficiles à comprendre! Si vous ne vous souciez pas de "pourquoi ces choses fonctionnent de cette façon", sautez ce chapitre.
Type de code:
Dans ECMAScript, il existe 3 types différents de code exécutable: code global, code de fonction et code EVAL. Ces types sont plus ou moins explicites en termes de nom, voici un bref aperçu:
Lorsqu'un code source est considéré comme un programme, il sera exécuté dans un environnement mondial et est considéré comme du code global. Dans un environnement de navigateur, le contenu des éléments de script est généralement interprété comme des programmes et est donc exécuté comme du code global.
Tout code exécuté directement dans une fonction est évidemment considéré comme un code de fonction. Dans un navigateur, le contenu des propriétés des événements (tels que <p onclick = "...">) est généralement interprété comme un code de fonction.
Enfin, le texte de code appliqué à la fonction intégrée EVAL est interprété comme le code EVAL. Bientôt, nous découvrirons pourquoi ce type est spécial.
Contexte d'exécution:
Lorsque le code ECMAScript est exécuté, il se produit généralement dans un contexte d'exécution spécifique. Le contexte d'exécution est un concept d'entité quelque peu abstrait, qui peut aider à comprendre comment fonctionne la portée et les instances variables. Pour chacun des trois codes exécutables, il existe un contexte d'exécution qui lui correspond. Lorsqu'une fonction est exécutée, nous disons que "le contrôle du programme entre dans le contexte d'exécution du code de fonction"; Lorsqu'un morceau de code global est exécuté, le contrôle du programme entre dans le contexte d'exécution du code global, etc.
Comme vous pouvez le voir, le contexte d'exécution peut logiquement former une pile. Tout d'abord, il peut y avoir un morceau de code global et son propre contexte d'exécution, puis ce morceau de code peut appeler une fonction avec son contexte d'exécution (fonction). Ce morceau de fonction peut appeler une autre fonction, etc. Même si la fonction est appelée récursive, elle sera entrée dans un nouveau contexte d'exécution à chaque fois qu'il est appelé.
Objet actif (objet d'activation) / objet variable:
Chaque contexte d'exécution a un soi-disant objet variable qui lui est associé. Semblable au contexte d'exécution, un objet variable est une entité abstraite, un mécanisme utilisé pour décrire des instances variables. Fait intéressant, les variables et les fonctions déclarées dans le code source sont généralement ajoutées à cet objet variable en tant que propriétés.
Lorsque le contrôle du programme entre dans le contexte d'exécution du code global, un objet global est utilisé comme objet variable. C'est exactement pourquoi les variables de fonction déclarées globales deviennent des propriétés globales d'objets.
La copie de code est la suivante:
/ * N'oubliez pas que «cela» fait référence à l'objet global lorsqu'il est dans la portée globale * /
var global_object = this;
var foo = 1;
Global_object.foo; // 1
foo === global_object.foo; // vrai
Fonction Bar () {}
typeof global_object.bar; // "fonction"
Global_object.bar === bar; // vrai
OK, donc les variables globales deviendront les propriétés des objets globaux, mais qu'arrive-t-il aux variables locales (celles définies dans le code de la fonction)? En fait, ils se comportent de manière très similaire: ils deviendront des propriétés d'objets variables (objets variables). La seule différence est que lorsque dans le code de fonction, un objet variable n'est pas un objet global, mais un objet soi-disant activation. L'objet actif est créé chaque fois qu'il entre dans le contexte d'exécution du code de fonction.
Non seulement les variables et les fonctions déclarées dans le code de fonction deviendront les propriétés de l'objet actif; Cela se produira également sur chaque paramètre de fonction (le nom correspondant au paramètre formel correspondant) et un objet d'arguments spéciaux (le nom des arguments). Notez que l'objet actif est un mécanisme de description interne et n'est pas accessible dans le code du programme.
La copie de code est la suivante:
(fonction (foo) {
var bar = 2;
fonction baz () {}
/ *
En termes abstraits,
L'objet «Arguments» spécial devient une propriété de l'objet d'activation de la fonction contenant:
Activation_object.arguments; // Objet d'arguments
... ainsi que l'argument `foo`:
Activation_object.foo; // 1
... ainsi que la variable `bar»:
Activation_object.bar; // 2
... ainsi que la fonction déclarée localement:
typeof activation_object.baz; // "fonction"
* /
}) (1);
Enfin, les variables déclarées dans le code d'évaluation deviennent les propriétés des objets variables dans le contexte de l'appelant. EVAL Code utilise simplement des objets variables dans le contexte d'exécution du code qui l'appelle.
La copie de code est la suivante:
var global_object = this;
/ * `foo` est créé comme une propriété d'appeler l'objet variable de contexte,
qui dans ce cas est un objet global * /
eval ('var foo = 1;');
Global_object.foo; // 1
(fonction(){
/ * `Bar` est créé comme une propriété d'appeler l'objet variable de contexte,
qui, dans ce cas, est un objet d'activation de contenir la fonction * /
eval ('var bar = 1;');
/ *
En termes abstraits,
Activation_object.bar; // 1
* /
}) ();
Attributs de la propriété
Nous sommes presque là. Maintenant que nous sommes bien conscients de ce qui se passe avec les variables (ils deviennent des propriétés), le seul concept restant à comprendre est les attributs de propriété. Chaque attribut peut avoir 0 ou plusieurs propriétés, qui sont sélectionnées dans les ensembles suivants: ReadOnly, Dontenum, Dontdelete et Internal. Vous pouvez les considérer comme des drapeaux - une fonctionnalité qui peut exister ou non dans les propriétés. Pour notre discussion aujourd'hui, nous ne sommes intéressés que par DoTdelete.
Lorsque des variables et des fonctions déclarées deviennent des attributs d'objets variables (ou des objets actifs du code de fonction ou des objets globaux du code global), ces attributs sont créés avec l'attribut d'attribut DontDelete. Cependant, tous les attributs explicites (ou implicites) ne seront pas inclus avec l'attribut DontDelete. C'est pourquoi nous pouvons supprimer certains attributs mais ne pouvons pas en supprimer d'autres.
La copie de code est la suivante:
var global_object = this;
/ * `foo` est une propriété d'un objet global.
Il est créé via une déclaration variable, tout comme l'attribut DontDelete.
C'est pourquoi il ne peut pas être supprimé. * /
var foo = 1;
supprimer foo; // FAUX
typeof foo; // "nombre"
/ * `Bar` est une propriété d'un objet global.
Il est créé via la déclaration de fonction, tout comme l'attribut DontDelete.
C'est pourquoi il ne peut pas non plus être supprimé. * /
Fonction Bar () {}
Supprimer la barre; // FAUX
Typeof Bar; // "fonction"
/ * `baz` est également une propriété d'un objet global.
Cependant, il est créé via une affectation de propriété et n'a donc pas d'attribut DontDelete.
C'est pourquoi il peut être supprimé. * /
Global_object.baz = 'blah';
supprimer global_object.baz; // vrai
typeof global_object.baz; // non défini "
Objets intégrés et netdelete
Donc, il s'agit de cela (Dontdelete): une propriété spéciale de la propriété qui contrôle si cette propriété peut être supprimée. Notez que certains objets intégrés sont spécifiés pour contenir netDelete, ils ne peuvent donc pas être supprimés. Par exemple, une variable d'argument spéciale (ou, comme nous le savons maintenant, la propriété d'un objet actif) a netdelete. La propriété de longueur d'une instance de fonction a également une propriété netDelete.
La copie de code est la suivante:
(fonction(){
/ * Impossible de supprimer des «arguments», car il a netdelete * /
supprimer des arguments; // FAUX
type de arguments; // "objet"
/ * Impossible de supprimer la `longueur '' de la fonction; il a aussi netdelete * /
fonction f () {}
supprimer f.length; // FAUX
typeof f.length; // "nombre"
}) ();
L'attribut correspondant au paramètre de fonction a également la fonctionnalité Dontdelete depuis son établissement, nous ne pouvons donc pas le supprimer.
La copie de code est la suivante:
(fonction (foo, bar) {
supprimer foo; // FAUX
foo; // 1
Supprimer la barre; // FAUX
bar; // 'blah'
}) (1, 'bla');
Affectation non déclarée:
Vous pouvez également vous rappeler qu'une affectation non déclarée crée une propriété sur l'objet global à moins que la propriété n'ait été trouvée ailleurs dans cette chaîne de portée avant l'objet global. Et maintenant, nous connaissons la différence entre l'affectation de la propriété et la déclaration variable - ce dernier définit la propriété DontDelete, mais le premier ne le fait pas. Nous devons être clairs pourquoi une affectation non déclarée crée une propriété supprimée.
La copie de code est la suivante:
var global_object = this;
/ * Créer une propriété globale via la déclaration variable; la propriété a netdelete * /
var foo = 1;
/ * Créer une propriété globale via une affectation non déclarée; la propriété n'a pas de netdelete * /
bar = 2;
supprimer foo; // FAUX
typeof foo; // "nombre"
Supprimer la barre; // vrai
Typeof Bar; // non défini "
Veuillez noter: les propriétés sont déterminées lorsque l'attribut est créé et les affectations ultérieures ne modifient pas les propriétés des attributs existants. Il est très important de comprendre cette différence.
La copie de code est la suivante:
/ * `foo` est créé comme une propriété avec Dontdelete * /
fonction foo () {}
/ * Les affectations ultérieures ne modifient pas les attributs. DoTdelete est toujours là! * /
foo = 1;
supprimer foo; // FAUX
typeof foo; // "nombre"
/ * Mais attribuer à une propriété qui n'existe pas,
crée cette propriété avec des attributs vides (et donc sans netdelete) * /
this.bar = 1;
Supprimer la barre; // vrai
Typeof Bar; // non défini "
Confusion de feu:
Que se passe-t-il dans Firebug? Pourquoi les variables déclarées dans la console peuvent être supprimées? Cela n'est-il pas contraire à ce que nous avons appris auparavant? Eh bien, comme je l'ai déjà dit, le code d'évaluation a des performances spéciales lorsqu'il est confronté à des déclarations variables. Les variables déclarées dans EVAL sont en fait créées comme des attributs sans l'attribut DontDelete.
La copie de code est la suivante:
eval ('var foo = 1;');
foo; // 1
supprimer foo; // vrai
typeof foo; // non défini "
De même, de même, lorsqu'il est appelé dans le code de fonction:
La copie de code est la suivante:
(fonction(){
eval ('var foo = 1;');
foo; // 1
supprimer foo; // vrai
typeof foo; // non défini "
}) ();
C'est la base d'un comportement anormal de Firebug. Tous les texte de la console seront analysés et exécutés sous forme de code EVAL, plutôt que de code global ou de fonction. De toute évidence, toutes les variables déclarées ici deviendront éventuellement des propriétés sans l'attribut DontDelete, afin qu'ils puissent tous être facilement supprimés. Nous devons comprendre la différence entre le code global et la console Firebug.
Supprimer les variables via l'évaluation:
Ce comportement d'évaluation intéressant, associé à un autre aspect de l'ECMAScript, peut techniquement nous permettre de supprimer les propriétés de "non-séquenable". Une chose à propos des déclarations de fonction est qu'elles sont en mesure de remplacer les variables avec le même nom dans le même contexte d'exécution.
La copie de code est la suivante:
fonction x () {}
var x;
typeof x; // "fonction"
Notez comment les déclarations de fonction obtiennent des variables prioritaires et écrasent avec le même nom (ou, en d'autres termes, les mêmes propriétés dans l'objet variable). En effet, les déclarations de fonction sont instanciées après la déclaration variable et sont autorisées à les écraser (déclarations variables). Les déclarations de fonction remplacent non seulement la valeur d'une propriété, mais remplacent également les propriétés de cette propriété. Si nous déclarons une fonction via EVAL, cette fonction doit remplacer les propriétés de la propriété d'origine (remplacée) par ses propres propriétés. Et, puisque les variables déclarées via EVAL Créer des propriétés sans l'attribut DontDelete, l'instanciation de cette nouvelle fonction supprimera en fait l'attribut DontDelete existant de la propriété, afin qu'une propriété puisse être supprimée (et, évidemment, pointe sa valeur à la fonction nouvellement créée).
La copie de code est la suivante:
var x = 1;
/ * Ne peut pas supprimer, `x` a netdelete * /
supprimer x; // FAUX
typeof x; // "nombre"
eval ('function x () {}');
/ * `x` La propriété fait désormais référence à la fonction et ne devrait pas n'avoir pas de netdelete * /
typeof x; // "fonction"
supprimer x; // devrait être «vrai»
typeof x; // devrait être "indéfini"
Malheureusement, cette «tromperie» ne fonctionne actuellement dans aucune mise en œuvre. Peut-être que je manque quelque chose ici, ou peut-être que le comportement est tout simplement trop obscur que l'implémenteur ne le remarque pas.
Compatibilité du navigateur:
Il est utile en théorie de comprendre comment les choses fonctionnent, mais la pratique est la chose la plus importante. Le navigateur suit-il les normes lorsqu'il s'agit de créer / supprimer des variables / propriétés? La réponse est: dans la plupart des cas, oui.
J'ai écrit un ensemble de tests simples pour tester la compatibilité du navigateur avec les opérateurs de suppression, y compris des tests sous code global, code de fonction et code d'évaluation. Le jeu de test vérifie si la valeur de retour et les valeurs d'attribut de l'opérateur de suppression (comme ils devraient se comporter) sont vraiment supprimées. La valeur de retour de Supprimer n'est pas aussi importante que son résultat réel. Si Delete renvoie True au lieu de False, ce n'est pas important, et ce qui est important, c'est que les attributs avec l'attribut DontDelete ne sont pas supprimés, et vice versa.
Les navigateurs modernes sont généralement assez compatibles. Outre les fonctionnalités d'évaluation que j'ai mentionnées précédemment, les navigateurs suivants ont passé tous les ensembles de tests: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+.
Safari 2.x et 3.0.4 ont des problèmes lors de la suppression des paramètres de fonction; Ces propriétés semblent être créées sans DoTdelete, elles peuvent donc être supprimées. Safari 2.x a plus de problèmes - la suppression des variables non référencées (telles que la suppression 1) lancera des exceptions; Les déclarations de fonction créent des propriétés supprimées (mais, étrangement, les déclarations variables ne le font pas); Les déclarations variables dans l'évaluation deviendront non-sulfues (mais les déclarations de fonctions sont entibles).
Semblable à Safari, Konqueror (3,5, pas 4.3) jette une exception lors de la suppression d'un type non référencé (tel que: Supprimer 1), et rend incorrectement les variables de fonction sont supprimées.
Note du traducteur:
J'ai testé les dernières versions de Chrome, Firefox et IE, et j'ai conservé la situation où toutes les autres passes sauf 23 et 24 échoueront. En même temps, j'ai testé UC et certains navigateurs mobiles. À l'exception du navigateur intégré du Nokia E72, qui a également échoué 15 et 16, les autres navigateurs intégrés sont pour la plupart les mêmes que les navigateurs de bureau. Mais il convient de mentionner que le navigateur intégré de BlackBerry Curve 8310/8900 peut passer 23, ce qui m'a surpris.
Gecko Dontdelete Bug:
Gecko 1.8.x Browser - Firefox 2.x, Camino 1.x, Seamonkey 1.x, etc. - Affiche un bogue très intéressant, une affectation explicite d'une propriété supprimera sa propriété DoTdelete, même si cette propriété est créée via des déclarations variables ou des déclarations de fonction.
La copie de code est la suivante:
fonction foo () {}
supprimer foo; // faux (comme prévu)
typeof foo; // "fonction" (comme prévu)
/ * Affectez maintenant explicitement une propriété * /
this.foo = 1; // efface à tort l'attribut Dontdelete
supprimer foo; // vrai
typeof foo; // non défini "
/ * Notez que cela ne se produit pas lors de l'attribution de la propriété implicitement * /
Fonction Bar () {}
bar = 1;
Supprimer la barre; // FAUX
Typeof Bar; // "Numéro" (bien que la propriété remplacée par affectation)
Étonnamment, Internet Explorer 5.5 - 8 a passé l'ensemble de test complet, sauf que la suppression des types non référencés (tels que la suppression 1) lancera des exceptions (tout comme l'ancien Safari). Cependant, il y a des bugs plus sérieux sous IE, ce qui n'est pas si évident. Ces bogues sont liés à l'objet global.
C'est-à-dire des bugs:
Tout ce chapitre parle des bogues d'Internet Explorer? Ouah! C'est incroyable!
Dans IE (au moins IE 6-8), l'expression suivante lance une exception (lorsqu'elle est exécutée dans le code global):
this.x = 1;
supprimer x; // TypeError: l'objet ne prend pas en charge cette action
Celui-ci le fera aussi, mais jettera des exceptions différentes, ce qui rend les choses encore plus intéressantes:
var x = 1;
Supprimer this.x; // TypeError: Impossible de supprimer «this.x»
Cela ressemble à IE, les déclarations de variables dans le code global ne créent pas d'attributs sur l'objet global. Création d'attributs par affectation (this.x = 1), puis la supprimer par Supprimer X lance ensuite une erreur. La création d'attributs par déclaration (var x = 1) et la supprimer ensuite lance une autre erreur.
Mais ce n'est pas tout. La création de propriétés par des affectations explicites provoquera toujours des exceptions de lancer une fois supprimées. Non seulement il y a des erreurs ici, mais les propriétés créées semblent avoir l'attribut DontDelete, ce qui ne devrait bien sûr pas être.
this.x = 1;
Supprimer this.x; // TypeError: l'objet ne prend pas en charge cette action
typeof x; // "numéro" (existe toujours, n'a pas été supprimé comme il aurait dû l'être!)
supprimer x; // TypeError: l'objet ne prend pas en charge cette action
typeof x; // "numéro" (n'a pas été supprimé)
Maintenant, nous pensons que sous IE, les affectations non déclarées (les propriétés doivent être créées sur des objets globaux) créent des propriétés délétables.
x = 1;
supprimer x; // vrai
typeof x; // non défini "
Cependant, si vous supprimez cette propriété via cette référence dans le code global (supprimez this.x), une erreur similaire apparaîtra.
x = 1;
Supprimer this.x; // TypeError: Impossible de supprimer «this.x»
Si nous voulons résumer ce comportement, il semble que l'utilisation de supprimer ce.x pour supprimer les variables du code global ne réussira jamais. Lorsque la propriété de la question est créée par une affectation explicite (this.x = 1), supprimez une erreur; Lorsque la propriété est créée par une affectation non déclarée (x = 1) ou par une déclaration (var x = 1), la suppression lance une autre erreur.
Supprimer x, en revanche, une erreur ne doit être lancée que lorsque la propriété est créée par affectation explicite - this.x = 1. Si une propriété est créée par déclaration (var x = 1), l'opération de suppression ne se produit jamais et l'opération de suppression renvoie correctement faux. Si une propriété est créée par affectation non déclaré (x = 1), l'opération de suppression fonctionne comme prévu.
J'ai encore réfléchi à ce problème en septembre. Garrett Smith a suggéré que sous IE,
"L'objet variable global est implémenté en tant qu'objet JScript, et l'objet global est implémenté par l'hôte."
Garrett a utilisé l'entrée du blog d'Eric Lippert comme référence.
Nous pouvons plus ou moins confirmer cette théorie en mettant en œuvre certains tests. Notez que cette fenêtre et la fenêtre semblent pointer vers le même objet (si nous pouvons faire confiance à l'opérateur ===), mais l'objet variable (l'objet où se trouve la déclaration de fonction) est différent de ce que cela pointe.
La copie de code est la suivante:
/ * dans le code global * /
fonction getBase () {renvoie ceci; }
getBase () === this.getBase (); // FAUX
this.getBase () === this.getBase (); // vrai
window.getBase () === this.getBase (); // vrai
window.getBase () === getBase (); // FAUX
malentendu:
La beauté de comprendre pourquoi les choses fonctionnent de cette façon ne consiste pas à être sous-estimée. J'ai vu des malentendus sur l'opérateur de suppression sur Internet. Par exemple, la réponse sur Stackoverflow (avec une note étonnamment élevée), explique en toute confiance
"Lorsque l'opérande cible n'est pas une propriété d'objet, la suppression doit être opérationnelle."
Maintenant que nous avons compris le noyau du comportement de fonctionnement de suppression, l'erreur dans cette réponse devient évidente. Delete ne fait pas de distinction entre les variables et les attributs (en fait, pour supprimer, ce sont les deux types de référence) et ne se soucient en fait que des attributs de DoTdelete (et si les attributs eux-mêmes existent).
Il est également très intéressant de voir divers malentendus se réfuter mutuellement. Dans un même sujet, une personne a d'abord suggéré de supprimer uniquement les variables (cela ne fonctionnera que si elle est déclarée dans EVAL), tandis qu'une autre personne a fourni une correction de bogue à la façon dont la suppression est utilisée pour supprimer les variables dans le code global, mais pas dans le code de la fonction.
Faites très attention à l'explication de JavaScript sur Internet. La méthode idéale est de toujours comprendre l'essence du problème. ;)
Supprimer et objet hôte (objet hôte):
L'algorithme de suppression est à peu près comme ceci:
Retour True si l'opérande n'est pas un type de référence
Si l'objet n'a pas d'attribut direct de ce nom, renvoyez True (comme nous le savons, l'objet peut être un objet actif ou un objet global)
Si la propriété existe mais a l'attribut DontDelete, retournez false
Dans d'autres cas, supprimez l'attribut et retournez vrai
Cependant, le comportement de l'opérateur de suppression de l'objet hôte est imprévisible. Et ce comportement n'est pas réellement faux: (selon la norme), l'objet hôte est autorisé à implémenter tout comportement pour plusieurs opérateurs tels que la méthode de lecture (interne [[GET]]), d'écriture (méthode interne [[put]]) et de supprimer (méthode interne [[delete]]). Ce comportement de grâce pour la coutume [[supprimer]] est ce qui rend l'objet hôte si déroutant.
Nous avons vu quelques bizarreries IE, où la suppression d'objets spécifiques (qui sont évidemment implémentés sous forme d'objets hôte) lancera des erreurs. Certaines versions de Firefox lanceront lors de la suppression de la fenêtre. Lorsque les opérandes sont des objets hôte, vous ne pouvez pas faire confiance à la valeur de retour de Supprimer. Voyons ce qui se passe dans Firefox:
La copie de code est la suivante:
/ * "Alert" est une propriété directe de «Window» (si nous devions croire «Hasownproperty») * /
window.hasownproperty ('alert'); // vrai
Supprimer la fenêtre.Alert; // vrai
typeof window. alert; // "fonction"
Supprimer Window.Alert Renvoie True, même s'il n'y a aucune raison pour que cette propriété entraîne un tel résultat du tout. Il se résoudra à une référence (il ne retournera donc pas vrai dans la première étape). Il s'agit d'une propriété directe d'un objet Window (donc il ne retournera pas vrai dans la deuxième étape). Ainsi, le seul cas où la suppression peut retourner True est d'atteindre la quatrième étape et de supprimer réellement cette propriété. Cependant, cette propriété n'est jamais supprimée.
La morale de cette histoire est: ne faites jamais confiance à l'objet hôte.
Mode strict ES5:
Alors, qu'est-ce que le mode strict Ecmascript5 nous apporte? Il introduit peu de limites. Lorsque l'expression de l'opérateur de suppression est une référence directe à une variable, un paramètre de fonction ou un identifiant de fonction, une erreur de syntaxe sera lancée. De plus, si la propriété a une propriété interne [[configurable]] == false, une erreur de type sera lancée.
La copie de code est la suivante:
(fonction (foo) {
"Utilisez strict"; // activer le mode strict dans cette fonction
Var Bar;
fonction baz () {}
supprimer foo; // syntaxerror (lors de la suppression de l'argument)
Supprimer la barre; // syntaxerror (lors de la suppression de la variable)
Supprimer Baz; // syntaxerror (lors de la suppression de la variable créée avec la déclaration de fonction)
/ * `longueur` des instances de fonction ont {[[configurable]]: false} * /
delete (function () {}). LONGUELLANT; // TypeError
}) ();
De plus, la suppression des variables non déclarées (ou des références non résolues) lancera également des erreurs de syntaxe:
"Utilisez strict";
supprimer i_dont_exist; // syntaxerror
L'attribution non déclarée se comporte de manière similaire aux variables non déclarées en mode strict (sauf cette fois, il soulève une erreur de devis au lieu d'une erreur de syntaxe):
"Utilisez strict";
i_dont_exist = 1; // référence
Comme vous le comprenez maintenant, toutes les restrictions ont un sens plus ou moins, car la suppression des variables, des déclarations de fonction et des paramètres peut provoquer autant de confusion. Au lieu d'ignorer silencieusement l'opération de suppression, le modèle strict prend une mesure plus radicale et descriptive.
Résumer:
Ce billet de blog a fini par être assez long, donc je ne vais pas parler de quelque chose comme utiliser Delete pour supprimer un objet de tableau ou ce que cela signifie. Vous pouvez vous référer à l'explication spéciale de l'article MDC (ou lire les normes et faire vos propres expériences).
Voici un bref résumé du fonctionnement des opérations de suppression en JavaScript:
Les variables et les déclarations de fonction sont des propriétés d'objets actifs ou d'objets globaux
Les attributs ont certaines caractéristiques, et le Dontdelete est l'attribut qui détermine si cet attribut peut être supprimé.
Les variables et les déclarations de fonction dans le code global ou de fonction créent toujours des attributs avec des attributs DontDelete.
Les paramètres de fonction sont toujours des attributs de l'objet actif et sont accompagnés de netDelete.
Les variables et fonctions déclarées dans le code EVAL créent toujours des propriétés sans DoTdelete.
Les nouvelles propriétés n'ont pas d'attributs lorsqu'ils sont créés (bien sûr, il n'y a pas non plus de Dontelete).
L'objet hôte est autorisé à décider de lui-même comment réagir à l'opération de suppression.
Si vous voulez être plus familier avec ce qui est décrit ici, voir la spécification ECMA-262 3e édition.
J'espère que vous pourrez profiter de cet article et apprendre quelque chose de nouveau. Toutes les questions, suggestions ou corrections sont les bienvenues.