Maison > interface Web > js tutoriel > Problèmes avec JavaScript facilement trompés

Problèmes avec JavaScript facilement trompés

hzc
Libérer: 2020-06-28 09:50:23
avant
2257 Les gens l'ont consulté

Avant-propos

Résumé : Il s'agit de la compréhension et de l'expérience de certains sujets JavaScript que j'ai accumulés et que je trouve plus intéressants ou difficiles, et qui seront tenus à jour pendant longtemps.

Ne vivez pas comme une femme, et votre bonheur et vos souffrances seront laissés aux autres pendant des centaines d'années.

Texte

1. Compréhension approfondie de setTimeout et setInterval

Dans la compréhension approfondie de setTimeout et setInterval, l'auteur a fait un résumé dans ce blog.Nous savons que les commandes d'essai JavaScript Les produits des threads, les deux fonctions utilisent la méthode d'insertion de code pour réaliser un pseudo-asynchrone, ce qui est en fait le même principe qu'AJAX. Jetons un coup d'œil à cet exemple :

console.log("1");
setTimeout(function(){        
    console.log("3")
},0);    console.log("2");
Copier après la connexion

Résultat : La console produit 1, 2, 3 dans l'ordre

function fn() {
    setTimeout(function(){alert('can you see me?');},1000);
    while(true) {}
}
Copier après la connexion

Quel est, selon vous, le résultat de l'exécution de ce code ? La réponse est que l'alerte n'apparaît jamais.
Pourquoi ça ? Étant donné que le code while n'a pas été exécuté, le code inséré ultérieurement ne sera jamais exécuté.
Pour résumer, en fait, JS est un produit monothread après tout. Aussi « asynchrone » soit-il, il est impossible de franchir la barrière du seul thread. Par conséquent, de nombreux « appels asynchrones » (y compris Ajax) sont en réalité simplement « pseudo-asynchrones ». Tant que vous comprenez un tel concept, il n'est peut-être pas difficile de comprendre setTimeout et setInterval.

2. Exploration préliminaire des fermetures

Dans ce blog, une exploration préliminaire des fermetures JavaScript, il y a quelques sujets qui me semblent assez intéressants :

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());//The Window
Copier après la connexion
   var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };  
  alert(object.getNameFunc()());//My Object
Copier après la connexion
function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
Copier après la connexion

//Q : Quelles sont les sorties des trois lignes a, b et c ?

Il s'agit d'un problème de fermeture JS très typique. Il contient trois niveaux de fonctions amusantes. Il est particulièrement important de déterminer à quelle fonction amusante correspond la fonction amusante de chaque niveau.

//Réponse :
//a : non défini,0,0,0
//b : non défini,0,1,2
//c : undefined,0,1,1

3. Array/map,Number/parseInt

["1", "2", "3"].map(parseInt)//求输出结果复制代码
Copier après la connexion

Tout d'abord, map accepte deux paramètres, une fonction de rappel et une fonction de rappel. this value
La fonction de rappel accepte trois paramètres currentValue, index, arrary ; et dans la question, map ne passe que dans la fonction de rappel --parseInt n'accepte que deux paramètres string, radix (radix La plage légale). de base est 2-36. 0 ou la valeur par défaut est 10. Donc cette question demande

parseInt('1', 0);parseInt('2', 1);parseInt('3', 2);复制代码
Copier après la connexion

Les deux derniers paramètres sont donc illégaux : [1, NaN, NaN] ;

4. 0.1+0.2!=0.3 et 9999999999999999 == 10000000000000000;

Selon la spécification du langage, JavaScript utilise le "format 64 bits double précision défini par la norme IEEE 754" (« valeurs IEEE 754 au format 64 bits double précision ») représente les nombres. De là, nous pouvons tirer une conclusion intéressante. Contrairement à d'autres langages de programmation (tels que C et Java), JavaScript ne fait pas de distinction entre les valeurs entières et les valeurs à virgule flottante. Tous les nombres sont représentés par des valeurs à virgule flottante en JavaScript. donc lorsque vous effectuez des opérations numériques, faites particulièrement attention lorsque vous le faites. Perte de précision Jetez un œil à l'exemple suivant :

0.1 + 0.2 = 0.30000000000000004复制代码
Copier après la connexion
Dans des implémentations spécifiques, les valeurs entières sont généralement traitées comme des variables entières de 32 bits, et dans des implémentations individuelles (comme certaines navigateurs) Stockée sous forme de variable entière de 32 bits jusqu'à ce qu'elle soit utilisée pour effectuer une opération non prise en charge par les entiers de 32 bits, ceci afin de faciliter la manipulation des bits. La précision des grands entiers ne sera pas perdue dans une plage de 2 à la puissance 53, ce qui signifie que le navigateur peut calculer avec précision tous les nombres dans Math.pow (2,53), lorsque le nombre fini est représenté par la représentation binaire d'un. décimal décimal n'est pas Lorsqu'il dépasse 52 bits, il peut également être stocké avec précision en JavaScript.

Solution : Math.round( (.1+.2)*100)/100;

5 [1<2<3,3<2<1]

Cette question fera croire à tort que c'est 2>1&&2<3. En fait, ce n'est pas le cas. Cette question est équivalente à

1<2=>true;true<3=>1<3=>true;3<2=>true;false<1=>0<1=>true;复制代码<p>Réponse : [vrai, vrai]<strong> Le. Le point clé de cette question est la compréhension des opérateurs. Premièrement, ce sont les règles de comparaison des différents types de valeurs en JavaScript. Pour plus de détails, voir le tableau de comparaison js, Jugement d'égalité JavaScript ; opérateurs de comparaison et opérateurs d'affectation, c'est-à-dire un de gauche à droite et un de gauche à droite~</strong></p>6 L'histoire de la confusion des navigateurs (1)<h3 id="6-1-" data-id="heading-7"><pre class="brush:php;toolbar:false">3.toString;3..toString;3...toString;复制代码
Copier après la connexion
Cette question. c'est très imaginatif~ Laissez-moi d'abord vous donner la réponse : error,'3',error;

Mais si c'est

var a=3;
a.toString;复制代码
Copier après la connexion
mais que c'est légal, la réponse est '3';

Pourquoi ?
Parce que 1.1, 1.,.1 sont tous des nombres légaux en JS ! Ainsi, lors de l'analyse de 3.toString, s'agit-il d'un numéro ou d'un appel de méthode ? Le navigateur est confus et ne peut générer qu'une erreur, donc j'ai l'impression que cette question ne fait que jouer des tours au navigateur...

7 Amélioration de la déclaration

var name = 'World!';
(function () {
    if (typeof name === 'undefined') {
        var name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})();
Copier après la connexion

La réponse est Quoi.. . Quand l'auteur l'a fait pour la première fois, j'ai bêtement pensé que c'était Bonjour tout le monde... En fait, ce n'est pas le cas. La bonne réponse est : Au revoir Jack ; . Le code ci-dessus est équivalent au Code suivant :

var name = 'World!';
(function () {
    var name;
    if (typeof name === 'undefined') {
        name = 'Jack';
        console.log('Goodbye ' + name);
    } else {
        console.log('Hello ' + name);
    }
})();
Copier après la connexion

8. 坑爹史(1)

var a = [0];
if ([0]) {
  console.log(a == true);
} else {
  console.log("wut");
}
Copier après la connexion

读者们你们觉得此题答案是什么呢?true?因为[0]被看做Boolean是被认为是true,理所当然的推出来[0]==true,控制台输出true...看似没错,然而并不是这样滴~[0]这个玩意儿在单独使用的时候是被认为是true的,但用作比较的时候它是false...所以正确答案是false;不信的话,F12控制台输出[0]==false;看是不是true......

###9. 坑爹史(2)

1 + - + + + - + 1
Copier après la connexion

这题应该是等同于:(倒着看)

1 + (a)  => 2
a = - (b) => 1
b = + (c) => -1
c = + (d) => -1
d = + (e) => -1
e = + (f) => -1
f = - (g) => -1
g = + 1   => 1
Copier après la connexion

答案是2

10. 坑爹史(3)

function sidEffecting(ary) {
  ary[0] = ary[2];
}
function bar(a,b,c) {
  c = 10
  sidEffecting(arguments);  return a + b + c;
}
bar(1,1,1)
Copier après la connexion

此题涉及ES6语法,实在坑的不行...arguments
首先 The arguments object is an Array-like object corresponding to the arguments passed to a function.也就是说 arguments 是一个 object, c 就是 arguments2, 所以对于 c 的修改就是对 arguments2 的修改.
所以答案是 21.
然而!!!!!!
当函数参数涉及到 any rest parameters, any default parameters or any destructured parameters 的时候, 这个 arguments 就不在是一个 mapped arguments object 了.....请看:

function sidEffecting(ary) {
  ary[0] = ary[2];
}
function bar(a,b,c=3) {
  c = 10
  sidEffecting(arguments);  return a + b + c;
}
bar(1,1,1)
Copier après la connexion

答案是12...
请读者细细体会!!

11. 坑爹史(4)

[,,,].join(", ")
Copier après la connexion
[,,,] => [undefined × 3]
Copier après la connexion

因为javascript 在定义数组的时候允许最后一个元素后跟一个,, 所以这是个长度为三的稀疏数组(这是长度为三, 并没有 0, 1, 2三个属性哦)
答案: ", , "

12. 浏览器懵逼史(2)

var a = {class: "Animal", name: 'Fido'};
a.class
Copier après la connexion

这个题比较流氓.. 因为是浏览器相关, class是个保留字(现在是个关键字了);Fuck!
所以答案不重要, 重要的是自己在取属性名称的时候尽量避免保留字. 如果使用的话请加引号 a['class']

13.一道容易被人轻视的面试题

function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
Copier après la connexion

14.闭包小题

for(var i = 0; i < 5; i++) {
    console.log(i);
}

for(var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000 * i);
}

for(var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, i * 1000);
    })(i);
}

for(var i = 0; i < 5; i++) {
    (function() {
        setTimeout(function() {
            console.log(i);
        }, i * 1000);
    })(i);
}

for(var i = 0; i < 5; i++) {
    setTimeout((function(i) {
        console.log(i);
    })(i), i * 1000);
}

setTimeout(function() {
  console.log(1)
}, 0);
new Promise(function executor(resolve) {
  console.log(2);
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);
Copier après la connexion

15. 函数的隐式转换

function fn() {
    return 20;
}
console.log(fn + 10); // 输出结果是多少

function fn() {
    return 20;
}

fn.toString = function() {
    return 10;
}

console.log(fn + 10);  // 输出结果是多少?

function fn() {
    return 20;
}

fn.toString = function() {
    return 10;
}

fn.valueOf = function() {
    return 5;
}

console.log(fn + 10); // 输出结果是多少?
Copier après la connexion

16. 函数防抖和函数节流(ES6)

//函数节流
const throttle = (fun, delay) => {
    let last = null;
    return () => {
        const now = + new Date();
        if (now - last > delay) {
            fun();
            last = now;
        }
    }
}
//实例
const throttleExample  = throttle(() => console.log(1), 1000);
//调用
throttleExample();
throttleExample();
throttleExample();
//函数防抖
const debouce = (fun, delay) => {
    let timer = null;
    return () => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fun();
        }, delay);
    }
}
//实例
const debouceExample = debouce(() => console.log(1), 1000);
//调用
debouceExample();
debouceExample();
debouceExample();
Copier après la connexion

推荐教程:《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!

Étiquettes associées:
source:juejin.cn
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal