Maison  >  Article  >  interface Web  >  10 points difficiles à maîtriser en JavaScript (à lire absolument)

10 points difficiles à maîtriser en JavaScript (à lire absolument)

黄舟
黄舟original
2018-05-11 11:13:517234parcourir

Vous ne connaissez peut-être pas encore 10 difficultés JavaScript, ne vous inquiétez pas, cet article les répertorie une par une pour vous et peut les surmonter une par une. Les amis intéressés peuvent se référer à

pour comprendre ce blog JavaScript. les développeurs n'auront pas de malchance...

1. Exécutez immédiatement la fonction

Exécutez immédiatement la fonction, c'est-à-dire l'expression de fonction immédiatement invoquée (IIFE), comme c'est Le nom signifie que la fonction est exécutée immédiatement lors de sa création. Il ne lie aucun événement et n'a pas besoin d'attendre des opérations asynchrones :

(function() {
 // 代码
 // ...
})();

function(){…} est une fonction anonyme, et une paire de parenthèses qui l'entourent la convertit en une expression, suivi de La paire de parenthèses suivante appelle cette fonction. L'exécution immédiate d'une fonction peut également être comprise comme l'appel immédiat d'une fonction anonyme. Le scénario d'application le plus courant pour l'exécution immédiate d'une fonction consiste à limiter la portée de la variable var à votre fonction, afin d'éviter les conflits de noms.

2. Fermeture

Pour la fermeture, après le retour de la fonction externe, la fonction interne peut toujours accéder aux variables de la fonction externe.

function f1()
{
 var N = 0; // N是f1函数的局部变量
 function f2() // f2是f1函数的内部函数,是闭包
 {
 N += 1; // 内部函数f2中使用了外部函数f1中的变量N
 console.log(N);
 }
 return f2;
}
var result = f1();
result(); // 输出1
result(); // 输出2
result(); // 输出3

Dans le code, la fonction externe f1 n'est exécutée qu'une seule fois, la variable N est mise à 0 et la fonction interne f2 est affectée à la variable result. Puisque la fonction externe f1 a été exécutée, sa variable interne N devrait être effacée de la mémoire. Cependant, ce n'est pas le cas : à chaque fois que nous appelons result, nous constatons que la variable N était en mémoire et s'accumule. Pourquoi? C'est la magie des fermetures !

3. Utilisez des fermetures pour définir des variables privées

Habituellement, les développeurs JavaScript utilisent un trait de soulignement comme préfixe pour les variables privées. Mais en fait, ces variables sont toujours accessibles et modifiables et ne sont pas de véritables variables privées. À l'heure actuelle, vous pouvez utiliser des fermetures pour définir de vraies variables privées :

function Product() {
 var name;
 this.setName = function(value) {
 name = value;
 };
 this.getName = function() {
 return name;
 };
}
var p = new Product();
p.setName("Fundebug");
console.log(p.name); // 输出undefined
console.log(p.getName()); // 输出Fundebug

Dans le code, l'attribut name de l'objet p est un attribut privé et n'est pas accessible directement à l'aide de p.name.

4. prototype

Chaque constructeur JavaScript possède un attribut de prototype, qui est utilisé pour définir les propriétés et les méthodes que tous les objets d'instance doivent partager. La propriété prototype ne peut pas être énumérée. JavaScript prend uniquement en charge l'héritage des propriétés et des méthodes via l'attribut prototype.

function Rectangle(x, y)
{
 this._length = x;
 this._breadth = y;
}
Rectangle.prototype.getDimensions = function()
{
 return {
 length: this._length,
 breadth: this._breadth
 };
};
var x = new Rectangle(3, 4);
var y = new Rectangle(4, 3);
console.log(x.getDimensions()); // { length: 3, breadth: 4 }
console.log(y.getDimensions()); // { length: 4, breadth: 3 }

Dans le code, x et y sont tous deux des instances d'objet créées par le constructeur Rectangle, et ils héritent de la méthode getDimensions via le prototype.

5. Modularité

JavaScript n'est pas un langage de programmation modulaire, du moins pas jusqu'à ce que ES6 soit implémenté. Cependant, pour une application Web complexe, la programmation modulaire constitue l’exigence la plus fondamentale. À l'heure actuelle, vous pouvez utiliser des fonctions d'exécution immédiate pour obtenir la modularité, tout comme de nombreuses bibliothèques JS telles que jQuery et notre Fundebug sont implémentées de cette manière.

var module = (function() {
 var N = 5;
 function print(x) {
 console.log("The result is: " + x);
 }
 function add(a) {
 var x = a + N;
 print(x);
 }
 return {
 description: "This is description",
 add: add
 };
})();
console.log(module.description); // 输出"this is description" 
module.add(5); // 输出“The result is: 10”

La soi-disant modularisation consiste à contrôler l'accessibilité des attributs et des méthodes au sein du module en fonction des besoins, c'est-à-dire privés ou publics. Dans le code, module est un module indépendant, N est sa propriété privée, print est sa méthode privée, description est sa propriété publique et add est sa méthode publique.

6. Levage de variables

JavaScript déplacera toutes les déclarations de variables et de fonctions au premier plan de sa portée, ce qui est appelé levage de variables (Hoisting). Autrement dit, peu importe où vous déclarez des variables et des fonctions, l'interpréteur les déplacera au premier plan de la portée. Nous pouvons donc d’abord utiliser des variables et des fonctions, puis les déclarer.

Cependant, seules les déclarations de variables sont promues, tandis que les affectations de variables ne le seront pas. Si vous ne comprenez pas cela, une erreur se produira parfois :

console.log(y); // 输出undefined
y = 2; // 初始化y

Le code ci-dessus est équivalent au code suivant :

var y; // 声明y
console.log(y); // 输出undefined
y = 2; // 初始化y

Pour éviter les bugs, les développeurs doivent variables et les fonctions sont déclarées au début de la portée.

7. Currying

Currying, c'est-à-dire Currying, peut rendre les fonctions plus flexibles. Nous pouvons l'appeler en transmettant plusieurs paramètres à la fois ; nous pouvons également l'appeler en transmettant seulement une partie des paramètres et le laisser renvoyer une fonction pour traiter les paramètres restants.

var add = function(x) {
 return function(y) {
 return x + y;
 };
};
console.log(add(1)(1)); // 输出2
var add1 = add(1);
console.log(add1(1)); // 输出2
var add10 = add(10);
console.log(add10(1)); // 输出11

Dans le code, nous pouvons passer deux 1 comme paramètres add(1)(1) en même temps, ou nous pouvons passer 1 paramètre puis obtenir les fonctions add1 et add10, ce qui est très flexible à utiliser.

8. Méthodes d'application, d'appel et de liaison

Les développeurs JavaScript doivent comprendre les différences entre les méthodes d'application, d'appel et de liaison. Ce qu'ils ont en commun, c'est que le premier paramètre est celui-ci, qui est le contexte dont dépend la fonction lors de son exécution.

Parmi les trois, la méthode call est la plus simple. Elle équivaut à appeler une fonction en précisant cette valeur :

var user = {
 name: "Rahul Mhatre",
 whatIsYourName: function() {
 console.log(this.name);
 }
};
user.whatIsYourName(); // 输出"Rahul Mhatre",
var user2 = {
 name: "Neha Sampat"
};
user.whatIsYourName.call(user2); // 输出"Neha Sampat"

La méthode apply est similaire à la méthode call. La seule différence entre les deux est que la méthode apply utilise un tableau pour spécifier les paramètres, tandis que chaque paramètre de la méthode d'appel doit être spécifié individuellement :

apply(thisArg, [argsArray])
call(thisArg, arg1, arg2, …)
var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greet1 = {
 greet: "Hola"
};
user.greetUser.call(greet1, "Rahul"); // 输出"Hola Rahul"
user.greetUser.apply(greet1, ["Rahul"]); // 输出"Hola Rahul"

En utilisant la méthode bind, vous pouvez lier cette valeur à la fonction, puis utilisez-la comme une nouvelle La fonction renvoie :

var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greetHola = user.greetUser.bind({greet: "Hola"});
var greetBonjour = user.greetUser.bind({greet: "Bonjour"});
greetHola("Rahul") // 输出"Hola Rahul"
greetBonjour("Rahul") // 输出"Bonjour Rahul"

9. Mémoisation

La mémoisation est utilisée pour optimiser les calculs fastidieux par la mise en cache. les résultats du calcul sont stockés en mémoire, de sorte que pour la même valeur, la valeur d'entrée ne devra être lue que dans la mémoire la prochaine fois.

function memoizeFunction(func)
{
 var cache = {};
 return function()
 {
 var key = arguments[0];
 if (cache[key])
 {
  return cache[key];
 }
 else
 {
  var val = func.apply(this, arguments);
  cache[key] = val;
  return val;
 }
 };
}
var fibonacci = memoizeFunction(function(n)
{
 return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(100)); // 输出354224848179262000000
console.log(fibonacci(100)); // 输出354224848179262000000

Dans le code, le deuxième calcul de fibonacci(100) n'a besoin que de lire le résultat directement depuis la mémoire.

10. Surcharge de fonctions

所谓函数重载(method overloading),就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,返回不同的结果。凭直觉,函数重载可以通过if…else或者switch实现,这就不去管它了。jQuery之父John Resig提出了一个非常巧(bian)妙(tai)的方法,利用了闭包。

从效果上来说,people对象的find方法允许3种不同的输入: 0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。

难点在于,people.find只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数find0,find1与find2啊!这里的关键在于old属性。

由addMethod函数的调用顺序可知,people.find最终绑定的是find2函数。然而,在绑定find2时,old为find1;同理,绑定find1时,old为find0。3个函数find0,find1与find2就这样通过闭包链接起来了。

根据addMethod的逻辑,当f.length与arguments.length不匹配时,就会去调用old,直到匹配为止。

function addMethod(object, name, f)
{  
 var old = object[name];  
 object[name] = function()
 {
 // f.length为函数定义时的参数个数
 // arguments.length为函数调用时的参数个数    
 if (f.length === arguments.length)
 {  
  return f.apply(this, arguments);    
 }
 else if (typeof old === "function")
 {
  return old.apply(this, arguments);    
 }  
 };
}
// 不传参数时,返回所有name
function find0()
{  
 return this.names;
}
// 传一个参数时,返回firstName匹配的name
function find1(firstName)
{  
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i].indexOf(firstName) === 0)
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
// 传两个参数时,返回firstName和lastName都匹配的name
function find2(firstName, lastName)
{ 
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i] === (firstName + " " + lastName))
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
var people = {  
 names: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
addMethod(people, "find", find0);
addMethod(people, "find", find1);
addMethod(people, "find", find2);
console.log(people.find()); // 输出["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); // 输出["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean", "Edwards")); // 输出["Dean Edwards"]

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