2013-10-10 3 views
1

J'ai écrit un code comme ceci: est 'faux'underscore.js tous les() avec non défini

var a = new Array(10); // should be [undefined * 10] 
var b = _.every(a, function(m){ 
    if(_.isUndefined(m)){ 
     return false; 
    } 
    return true; 
}); 

Je pense b, mais il retourne 'vrai'. Pourquoi retourne-t-il 'vrai'?

Ensuite, je change à ceci:

var c = [undefined, undefined]; 
var d = _.every(c, function(m){ 
    if(_.isUndefined(m)){ 
     return false; 
    } 
    return true; 
}); 

le retourner 'faux' dans d. Pourquoi sont-ils différents? Pourquoi?

Vous pouvez le tester dans http://jsfiddle.net/3qj4B/3/

Répondre

2

Lorsque vous créez un tableau en utilisant la initialiseur de classe vous créez un tableau avec 10 espace de mémoire disponible pour être utilisé, mais aucun d'entre eux n'est encore initialisé. Donc, vous n'êtes pas en train de boucler quoi que ce soit.

Regardez maintenant la source de every:

_.every = _.all = function(obj, iterator, context) { 
    iterator || (iterator = _.identity); 
    var result = true; 
    if (obj == null) return result;  
    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); 
    each(obj, function(value, index, list) { 
     if (!(result = result && iterator.call(context, value, index, list))) return breaker; 
    }); 
    return !!result; 
}; 

result est réglé pour être true et il est retourné depuis each ne fait pas d'itérations. C'est pourquoi vous retournez true.

Si, dans votre violon, vous essayez d'ajouter un console.log(m) à l'intérieur du gestionnaire, vous ne verrez aucun journal dans la console puisque each itère 0 fois.

+0

J'utilise 'console.log (a)', il imprime '[undefined x 10]'. Et 'console.log (a [1])', il affiche 'undefined'. Cela me rend confus. Si je peux utiliser 'a [1]' pour obtenir quelque chose, pourquoi je ne peux pas l'itérer? – shian

+0

http: // perfectionkills.com/how-ecmascript-5-ne-permet-pas-de-sous-classe-un-tableau/# special_nature_of_arrays –

+0

Merci de votre lien. – shian

2

Il y a une différence subtile entre l'initialisation d'un tableau avec le constructeur Array et une taille initiale, et l'initialisation avec une liste explicite des undefined entrées. Le premier (le constructeur Array) ne crée pas de propriétés correspondant aux index, contrairement à l'initialisation explicite.

Je suspecte que Underscore utilise le .forEach() natif quand il le peut, et cela n'appellera pas son rappel pour les index non initialisés. Ainsi, dans le premier test, le rappel à _.every() n'est jamais appelé du tout.

modifier — le constructeur Array fait quelque chose de plus ou moins la même chose que:

var a = []; a.length = 10; 

Lorsque vous étendez un tableau en augmentant sa longueur comme ça, les nouvelles positions d'index implicites ne sont pas initialisé . C'est la différence fondamentale entre la non-existence d'une propriété et la présence d'une propriété sans valeur. Dans les deux cas, une déréférence de la propriété entraîne undefined. Ainsi:

var o = {}; 

if (o.something == undefined) // this will be true 

puis:

var o = { something: undefined }; 

if (o.something == undefined) // also true 

Une façon de faire la différence entre les deux situations est l'opérateur in:

if ('something' in o) // only true in the second case