8 questions pour tester vos bases JavaScript
JavaScript est un langage amusant que nous aimons tous en raison de sa nature. Le navigateur est l'endroit où JavaScript s'exécute principalement, et les deux fonctionnent ensemble dans nos services. JS comporte certains concepts que les gens ont tendance à prendre à la légère et peuvent parfois les ignorer. Des concepts tels que les prototypes, les fermetures et les boucles d'événements font toujours partie de ces domaines obscurs par lesquels la plupart des développeurs JS font un détour. Comme nous le savons, l’ignorance est une chose dangereuse et peut conduire à des erreurs.
Si vous souhaitez lire plus d'articles de haute qualité, veuillez cliquer sur le blog GitHub. Des centaines d'articles de haute qualité vous attendent chaque année !
Ensuite, examinons quelques questions. Vous pouvez également essayer d'y réfléchir et d'y répondre.
Question 1 : Qu'est-ce qui sera imprimé sur la console du navigateur ?
var a = 10; function foo() { console.log(a); // ?? var a = 20; } foo();
Question 2 : Si nous utilisons let ou const au lieu de var, le résultat est-il le même
var a = 10; function foo() { console.log(a); // ?? let a = 20; } foo();
Question 3 : Qu'est-ce que dans l'élément "newArray" ?
var array = []; for(var i = 0; i <3; i++) { array.push(() => i); } var newArray = array.map(el => el()); console.log(newArray); // ??
Question 4 : Si nous exécutons la fonction 'foo' dans la console du navigateur, cela provoquera-t-il une erreur de débordement de pile ?
function foo() { setTimeout(foo, 0); // 是否存在堆栈溢出错误? };
Question 5 : Si vous exécutez la fonction suivante dans la console, l'interface utilisateur de la page (onglet) est-elle toujours réactive
function foo() { return Promise.resolve().then(foo); };
Question 6 : Pouvons-nous d'une manière ou d'une autre utiliser l'opération de propagation pour l'instruction suivante sans provoquer d'erreur de type var obj = { x: 1, y: 2, z: 3 };
[...obj]; // TypeError
Copier après la connexion
var obj = { x: 1, y: 2, z: 3 }; [...obj]; // TypeError
Question 7 : Lors de l'exécution de l'extrait de code suivant, qu'est-ce qui sera imprimé sur la console ? var obj = { a: 1, b: 2 };
Object.setPrototypeOf(obj, {c: 3});
Object.defineProperty(obj, 'd', { value: 4, enumerable: false });
// what properties will be printed when we run the for-in loop?
for(let prop in obj) {
console.log(prop);
}
Copier après la connexion
var obj = { a: 1, b: 2 }; Object.setPrototypeOf(obj, {c: 3}); Object.defineProperty(obj, 'd', { value: 4, enumerable: false }); // what properties will be printed when we run the for-in loop? for(let prop in obj) { console.log(prop); }
Question 8 : Quelle valeur xGetter() imprimera-t-il ? var x = 10;
var foo = {
x: 90,
getX: function() {
return this.x;
}
};
foo.getX(); // prints 90
var xGetter = foo.getX;
xGetter(); // prints ??
Copier après la connexion
var x = 10; var foo = { x: 90, getX: function() { return this.x; } }; foo.getX(); // prints 90 var xGetter = foo.getX; xGetter(); // prints ??
Réponses
Maintenant, répondons à chaque question du début à la fin. Je vais vous donner une brève explication en essayant de démystifier ces comportements et vous fournir quelques références. Question 1 :undefined
Analyse : Les variables déclarées à l'aide du mot-clé seront promues en JavaScript et la valeur sera allouée en mémoirevar
. Mais l'initialisation se produit exactement là où vous attribuez une valeur à la variable. De plus, les variables déclarées par undefined
sont de portée fonction, tandis que var
et let
sont de portée bloc. Voici donc à quoi ressemble le processus : const
var a = 10; // 全局使用域 function foo() { // var a 的声明将被提升到到函数的顶部。 // 比如:var a console.log(a); // 打印 undefined // 实际初始化值20只发生在这里 var a = 20; // local scope }
Question 2 :
. ReferenceError:a undefined
Analyse : les déclarations
et let
permettent à une variable de limiter sa portée au bloc, à l'instruction ou à l'expression dans laquelle elle est utilisée. Contrairement à const
, ces variables ne sont pas promues et ont ce qu'on appelle une var
Zone morte temporaire (TDZ) . Tenter d'accéder à ces variables dans TDZ augmentera car elles ne sont accessibles que lorsque l'exécution atteint la déclaration. ReferenceError
var a = 10; // 全局使用域 function foo() { // TDZ 开始 // 创建了未初始化的'a' console.log(a); // ReferenceError // TDZ结束,'a'仅在此处初始化,值为20 let a = 20; }
Question 3 :
[3, 3, 3]
Analyse : Déclarer une variable avec le mot-clé en tête de la boucle for
sera Cette variable crée une seule liaison (espace de stockage). En savoir plus sur les fermetures. Regardons à nouveau la boucle for. var
// 误解作用域:认为存在块级作用域 var array = []; for (var i = 0; i < 3; i++) { // 三个箭头函数体中的每个`'i'`都指向相同的绑定, // 这就是为什么它们在循环结束时返回相同的值'3'。 array.push(() => i); } var newArray = array.map(el => el()); console.log(newArray); // [3, 3, 3]
pour déclarer une variable avec une portée de bloc, une nouvelle liaison est créée pour chaque itération de boucle. let
// 使用ES6块级作用域 var array = []; for (let i = 0; i < 3; i++) { // 这一次,每个'i'指的是一个新的的绑定,并保留当前的值。 // 因此,每个箭头函数返回一个不同的值。 array.push(() => i); } var newArray = array.map(el => el()); console.log(newArray); // [0, 1, 2]
let array = []; for (var i = 0; i < 3; i++) { array[i] = (function(x) { return function() { return x; }; })(i); } const newArray = array.map(el => el()); console.log(newArray); // [0, 1, 2]
Problème 4 : Pas de débordementAnalyse : Le modèle de concurrence JavaScript est basé sur la "boucle d'événement". Lorsque nous disons « le navigateur est la maison de JS », ce que je veux vraiment dire, c'est que le navigateur fournit l'environnement d'exécution pour exécuter notre code JS. Les principaux composants du navigateur incluent
Call Stack, Event Loop, Task Queue et Web API. Les fonctions globales comme , setTimeout
et setInterval
ne font pas partie de JavaScript mais de l'API Web. Promise
, il le remet à setTimeout
(flèche 1). Ainsi, chaque fois que l'événement est déclenché, Web API
sera envoyé dans la file d'attente des tâches (flèche 2). callback
La boucle d'événements surveille en permanence la file d'attente des tâches et gère les rappels un par un dans l'ordre dans lequel ils sont mis en file d'attente. Chaque fois que la pile d'appels est vide, la boucle d'événement récupère le rappel et le place dans la pile (flèche 3) pour traitement. N'oubliez pas que si la pile d'appels n'est pas vide, la boucle d'événements ne poussera aucun rappel sur la pile .
Maintenant, armés de ces connaissances, répondons à la question mentionnée précédemment :步骤
- 调用
foo()
会将foo
函数放入调用堆栈(call stack)。 - 在处理内部代码时,JS引擎遇到
setTimeout
。 - 然后将
foo
回调函数传递给WebAPIs(箭头1)并从函数返回,调用堆栈再次为空 - 计时器被设置为0,因此
foo
将被发送到任务队列(箭头2)。 - 由于调用堆栈是空的,事件循环将选择
foo
回调并将其推入调用堆栈进行处理。 - 进程再次重复,堆栈不会溢出。
问题5 : 不会响应
解析:
大多数时候,开发人员假设在事件循环
在底层来看,JavaScript中有宏任务和微任务。setTimeout
回调是宏任务,而Promise
回调是微任务。
主要的区别在于他们的执行方式。宏任务在单个循环周期中一次一个地推入堆栈,但是微任务队列总是在执行后返回到事件循环之前清空。因此,如果你以处理条目的速度向这个队列添加条目,那么你就永远在处理微任务。只有当微任务队列为空时,事件循环才会重新渲染页面、
现在,当你在控制台中运行以下代码段
function foo() { return Promise.resolve().then(foo); };
每次调用'foo
'都会继续在微任务队列上添加另一个'foo
'回调,因此事件循环无法继续处理其他事件(滚动,单击等),直到该队列完全清空为止。 因此,它会阻止渲染。
问题6 : 会导致TypeError错误
解析:
展开语法 和 for-of 语句遍历iterable
对象定义要遍历的数据。Array
或Map
是具有默认迭代行为的内置迭代器。对象不是可迭代的,但是可以通过使用iterable和iterator协议使它们可迭代。
在Mozilla文档中,如果一个对象实现了@@iterator
方法,那么它就是可迭代的,这意味着这个对象(或者它原型链上的一个对象)必须有一个带有@@iterator
键的属性,这个键可以通过常量Symbol.iterator
获得。
上述语句可能看起来有点冗长,但是下面的示例将更有意义:
var obj = { x: 1, y: 2, z: 3 }; obj[Symbol.iterator] = function() { // iterator 是一个具有 next 方法的对象, // 它的返回至少有一个对象 // 两个属性:value&done。 // 返回一个 iterator 对象 return { next: function() { if (this._countDown === 3) { const lastValue = this._countDown; return { value: this._countDown, done: true }; } this._countDown = this._countDown + 1; return { value: this._countDown, done: false }; }, _countDown: 0 }; }; [...obj]; // 打印 [1, 2, 3]
还可以使用 generator 函数来定制对象的迭代行为:
var obj = {x:1, y:2, z: 3} obj[Symbol.iterator] = function*() { yield 1; yield 2; yield 3; } [...obj]; // 打印 [1, 2, 3]
问题7 : a, b, c
解析:
for-in
循环遍历对象本身的可枚举属性以及对象从其原型继承的属性。 可枚举属性是可以在for-in
循环期间包含和访问的属性。
var obj = { a: 1, b: 2 }; var descriptor = Object.getOwnPropertyDescriptor(obj, "a"); console.log(descriptor.enumerable); // true console.log(descriptor); // { value: 1, writable: true, enumerable: true, configurable: true }
现在你已经掌握了这些知识,应该很容易理解为什么我们的代码要打印这些特定的属性
var obj = { a: 1, b: 2 }; //a,b 都是 enumerables 属性 // 将{c:3}设置为'obj'的原型,并且我们知道 // for-in 循环也迭代 obj 继承的属性 // 从它的原型,'c'也可以被访问。 Object.setPrototypeOf(obj, { c: 3 }); // 我们在'obj'中定义了另外一个属性'd',但是 // 将'enumerable'设置为false。 这意味着'd'将被忽略。 Object.defineProperty(obj, "d", { value: 4, enumerable: false }); for (let prop in obj) { console.log(prop); } // 打印 // a // b // c
问题8 : 10
解析:
在全局范围内初始化x
时,它成为window对象的属性(不是严格的模式)。看看下面的代码:
var x = 10; // global scope var foo = { x: 90, getX: function() { return this.x; } }; foo.getX(); // prints 90 let xGetter = foo.getX; xGetter(); // prints 10
咱们可以断言:
window.x === 10; // true
this
始终指向调用方法的对象。因此,在foo.getx()
的例子中,它指向foo
对象,返回90
的值。而在xGetter()
的情况下,this
指向 window对象, 返回 window 中的x
的值,即10
。
要获取 foo.x
的值,可以通过使用Function.prototype.bind
将this
的值绑定到foo
对象来创建新函数。
let getFooX = foo.getX.bind(foo); getFooX(); // 90
就这样! 如果你的所有答案都正确,那么干漂亮。 咱们都是通过犯错来学习的。 这一切都是为了了解背后的“原因”。
推荐教程:《JS教程》
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!

Outils d'IA chauds

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

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

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

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 !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

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

Sujets chauds





Guide de la bordure de tableau en HTML. Nous discutons ici de plusieurs façons de définir une bordure de tableau avec des exemples de bordure de tableau en HTML.

Ceci est un guide des tableaux imbriqués en HTML. Nous discutons ici de la façon de créer un tableau dans le tableau ainsi que des exemples respectifs.

Guide de la marge HTML gauche. Nous discutons ici d'un bref aperçu de la marge gauche HTML et de ses exemples ainsi que de son implémentation de code.

Guide de mise en page des tableaux HTML. Nous discutons ici des valeurs de la mise en page des tableaux HTML ainsi que des exemples et des résultats en détail.

Guide de l'espace réservé de saisie HTML. Nous discutons ici des exemples d'espace réservé d'entrée HTML ainsi que des codes et des sorties.

Guide pour déplacer du texte en HTML. Nous discutons ici d'une introduction, du fonctionnement des balises de sélection avec la syntaxe et des exemples à implémenter.

Guide de la liste ordonnée HTML. Ici, nous discutons également de l'introduction de la liste et des types HTML ordonnés ainsi que de leur exemple respectivement.

Guide du bouton HTML onclick. Nous discutons ici de leur introduction, de leur fonctionnement, des exemples et de l'événement onclick dans divers événements respectivement.
