En parlant du mot-clé with en js, la première impression de nombreux amis peut être que la fonction du mot-clé with est de changer la portée, et le point le plus important est que l'utilisation du mot-clé with n'est pas recommandée. Après avoir entendu que le mot-clé with n'est pas recommandé, beaucoup d'entre nous ignoreront le mot-clé with, pensant que nous pouvons simplement l'ignorer et simplement l'utiliser. Mais parfois, lorsque nous examinons certaines questions de code ou d'entretien, il y aura des questions liées au mot-clé with. Il existe de nombreux pièges auxquels vous n'avez jamais été exposé, il est donc toujours nécessaire de parler du mot-clé with.
1. Instructions de base
Le mot-clé with est décrit dans la programmation avancée js comme ceci : La fonction de l'instruction with est de définir la portée du code sur une portée spécifique. La syntaxe de base est la suivante :
with (expression) statement;
Le but de l'utilisation du mot-clé with est de simplifier le travail d'écriture et d'accès multiple au même objet, comme dans l'exemple suivant :
var qs = location.search.substring(1); var hostName = location.hostname; var url = location.href;
Ces lignes de code accèdent aux propriétés de l'objet location. Si vous utilisez le mot-clé with, le code peut être simplifié comme suit :
with (location){ var qs = search.substring(1); var hostName = hostname; var url = href; }
Dans ce code, l'instruction with est utilisée pour associer l'objet location. Cela signifie que dans le bloc de code with, chaque variable est d'abord considérée comme une variable locale si la variable locale a le même nom qu'une propriété de l'emplacement. object, , alors cette variable locale pointera vers l'attribut de l'objet location.
Remarque : L'instruction with ne peut pas être utilisée en mode strict.
2. Inconvénients du mot-clé with
Dans la description de base précédente, nous pouvons voir que l'une des fonctions de with est de simplifier le code. Mais pourquoi n’est-ce pas recommandé ? Parlons des défauts de with :
1. Problèmes de performances
2. Sémantique peu claire et difficile à déboguer
3. Problèmes de performances
Parlons d’abord des problèmes de performances. Concernant les problèmes de performances liés à l’utilisation du mot-clé with, examinons d’abord deux morceaux de code :
Le premier morceau de code n'utilise pas le mot-clé with :
function func() { console.time("func"); var obj = { a: [1, 2, 3] }; for (var i = 0; i < 100000; i++) { var v = obj.a[0]; } console.timeEnd("func");//0.847ms } func();
Le deuxième morceau de code utilise le mot-clé with :
function funcWith() { console.time("funcWith"); var obj = { a: [1, 2, 3] }; var obj2 = { x: 2 }; with (obj2) { console.log(x); for (var i = 0; i < 100000; i++) { var v = obj.a[0]; } } console.timeEnd("funcWith");//84.808ms } funcWith();
Après avoir utilisé le mot-clé with, les performances du code sont considérablement réduites. L'instruction with dans le deuxième morceau de code agit sur l'objet obj2, puis l'objet obj est accessible dans le bloc with. Il existe une vue selon laquelle après avoir utilisé le mot-clé with, lors de l'accès à une variable dans le bloc with, il recherchera d'abord s'il existe un attribut nommé obj sur obj2. Sinon, passera à la recherche suivante. Ce processus entraîne une diminution. en performances. Mais est-ce vraiment la raison pour laquelle les performances du programme se dégradent réellement ?
Modifions le deuxième morceau de code comme suit :
function funcWith() { console.time("funcWith"); var obj = { a: [1, 2, 3] }; with (obj) { for (var i = 0; i < 100000; i++) { var v = a[0]; } } console.timeEnd("funcWith");//88.260ms } funcWith();
Ce code applique l'instruction with à l'objet obj, puis utilise directement a pour accéder à l'attribut a de obj. Selon le point de vue mentionné précédemment, lors de l'accès à l'attribut a, l'attribut peut être trouvé sur obj dans. une seule fois. Mais pourquoi les performances du code sont-elles encore réduites ?
La vraie raison est la suivante : après avoir utilisé le mot-clé with, le moteur JS ne peut pas optimiser ce code.
Le moteur JS a une phase de compilation avant l'exécution du code. Lorsque le mot-clé with n'est pas utilisé, le moteur JS sait que a est un attribut sur obj, et il peut analyser statiquement le code pour améliorer l'analyse des identifiants, optimisant ainsi l'analyse. code.Par conséquent, l'efficacité de l'exécution du code est améliorée. Après avoir utilisé le mot-clé with, le moteur js ne peut pas dire si la variable a est une variable locale ou un attribut d'obj. Par conséquent, une fois que le moteur js a rencontré le mot-clé with, il renoncera à optimiser ce code, ce qui réduit l'efficacité de l'exécution. .
Un autre impact de l'utilisation du mot-clé with sur les performances est l'outil de compression js, qui ne peut pas compresser ce code, ce qui est également un facteur affectant les performances.
4. Sémantique peu claire et difficile à déboguer
Comme mentionné précédemment, en plus des problèmes de performances, cela présente également l'inconvénient d'une sémantique peu claire et d'une difficulté de débogage, ce qui rend le code difficile à lire et peut provoquer des bugs potentiels.
function foo(obj) { with (obj) { a = 2; } } var o1 = { a: 3 }; var o2 = { b: 3 }; foo(o1); console.log(o1.a); // 2 foo(o2); console.log( o2.a ); // undefined console.log( a ); // 2
Ce code est facile à comprendre. Dans la fonction foo, le mot-clé with est utilisé pour accéder à l'objet obj passé, puis modifier l'attribut a. Lorsque l'objet o1 est transmis, parce que l'objet o1 a un attribut a, il n'y a pas de problème. Lorsque l'objet o2 est transmis, lorsque l'attribut a est modifié, puisque l'objet o2 n'a pas l'attribut a, l'attribut a modifié devient une variable globale. Cela crée des bugs potentiels.
5. Analyse étendue
Cela dit, je pense que tout le monde a compris pourquoi il n'est pas recommandé d'utiliser le mot-clé with et les problèmes possibles. Jetons un coup d'œil à quelques situations plus complexes, regardez le code suivant :
var obj = { x: 10, foo: function () { with (this) { var x = 20; var y = 30; console.log(y);//30 } } }; obj.foo(); console.log(obj.x);//20 console.log(obj.y);//undefined
在这段代码中,分别输出30,20,undefined的。涉及的知识点也比较多:with关键字,this关键字,变量提升等等,我们来一一解释一下。
1、this关键字
关于this关键字的文章google上面相当多,这里不再赘述,我们只需记住一点:this关键字始终指向调用函数的对象。在这里,foo函数中,this指向的就是obj对象。因此在with(this)语句块里面,可以直接通过x变量来访问obj的x属性。
2、变量提升
js中的变量提升也是一个经常遇到的问题,我们可以简单理解成在js中,变量声明会被提升到函数的顶部,尽管有的时候,它是在后面声明的。
所以上面的代码可以解析为:
var obj = { x: 10, foo: function () { var x;//声明局部变量x var y;//声明局部变量y with (obj) { x = 20;//访问变量x,在obj上找到x,则修改为20 y = 30;//访问变量y,在bojg上找不到y,则进一步查找,找到局部变量y,修改为30 console.log(y);//30//直接输出局部变量y, } } }; obj.foo(); console.log(obj.x);//20,obj.x已被修改为20 console.log(obj.y);//undefined,obj不存在y属性,则为undefined
上面的注释中,解释了代码的执行过程,相信大家已经理解了为什么会出处30,20,undefined的原因。
有兴趣的同学可以看看下面这段代码:
({ x: 10, foo: function () { function bar() { console.log(x); console.log(y); console.log(this.x); } with (this) { var x = 20; var y = 30; bar.call(this); } } }).foo();
这段代码会输出什么?为什么呢?
总结
本文总结了with语句的特点和弊端,总的来说,强烈不推荐使用with关键字。其实在日常编码中,我们只需要知道不去使用with就可以了,但是有的时候我们可能会遇到一些关于with的奇奇怪怪的问题,想要找出真正的原因,就要深入理解with关键字,这有助于我们去深入学习JS这门语言,同时也是学习JS的一个乐趣。