5 trouvailles JavaScript intéressantes faites dans le code source de Vue

La lecture du code source de frameworks bien connus peut aider un programmeur à améliorer ses compétences professionnelles. L'auteur de l'article, dont nous publions aujourd'hui la traduction, a récemment analysé le code vue2.x. Il a trouvé dans ce code quelques idées JavaScript intéressantes qu'il a décidé de partager avec tout le monde.



1. Déterminer le type exact de n'importe quel objet


Comme nous le savons tous, en JavaScript , il existe six types de données primitifs ( Boolean, Number, String, Null, Undefined, Symbol) et un type d'objet - Object. Savez-vous comment distinguer les types de valeurs d'objet différentes? Un objet peut être un tableau ou une fonction, il peut être une collection de valeurs Mapou autre chose. Que faut-il faire pour connaître le type d'objet exact?

Avant de chercher une réponse à cette question, réfléchissons à la différence entre Object.prototype.toString.call(arg)et String(arg).

L'utilisation de ces expressions vise à convertir le paramètre qui leur est transmis en chaîne. Mais ils fonctionnent différemment.

Une fois appelé, le String(arg)système tentera d'appeler arg.toString()ou arg.valueOf(). En conséquence, si dans argou dans le prototypeargces méthodes seront écrasées, les appels Object.prototype.toString.call(arg)et String(arg)donneront des résultats différents.

Prenons un exemple.

const _toString = Object.prototype.toString
var obj = {}
obj.toString()  // [object Object]
_toString.call(obj) // [object Object]

Nous exécuterons ce code dans la console de l'outil de développement du navigateur.


Dans ce cas, appelle obj.toString()et Object.prototype.toString.call(obj)conduit aux mêmes résultats.

Voici un autre exemple.

const _toString = Object.prototype.toString
var obj = {}
obj.toString = () => '111'
obj.toString()  // 111
_toString.call(obj) // [object Object]
/hello/.toString() // /hello/
_toString.call(/hello/) // [object RegExp]

Exécutons le code dans la console.


Maintenant, appeler la méthode de l'objet .toString()et utiliser la construction Object.prototype.toString.call(obj)donne des résultats différents.

Voici les règles qui décrivent le comportement d'une méthode dans la norme ECMAScript Object.prototype.toString().


Description de la méthode Object.prototype.toString () dans le standard ECMAScript

En regardant la documentation, nous pouvons conclure que lorsqu'il est appeléObject.prototype.toString()pour différents objets, des résultats différents seront retournés.

Explorez cette idée dans la console.


De plus, la valeur renvoyée Object.prototype.toString()est toujours présentée au format suivant:

‘[object ’ + ‘tag’ +‘] ’

Si nous devons extraire uniquement une partie de cette construction tag, nous pouvons accéder à cette partie en supprimant les caractères inutiles du début et de la fin de la ligne à l'aide d'une expression ou d'une méthode régulière String.prototype.slice().

function toRawType (value) {
    const _toString = Object.prototype.toString
    return _toString.call(value).slice(8, -1)
}
toRawType(null) // "Null"
toRawType(/sdfsd/) //"RegExp"

Explorez cette fonctionnalité dans la console.


Comme vous pouvez le voir, en utilisant la fonction ci-dessus, vous pouvez trouver le type exact d'une variable d'objet.

Ici , dans le référentiel Vue, vous pouvez trouver le code d'une fonction similaire.

2. Mise en cache des résultats de la fonction


Supposons qu'il existe une fonction similaire à la suivante qui effectue de longs calculs:

function computed(str) {    
    console.log('2000s have passed')
    return 'a result'
}

En créant une telle fonction, nous avons l'intention de mettre en cache les résultats qui lui sont retournés. Lorsque cette fonction sera appelée la prochaine fois, en lui passant les mêmes paramètres que précédemment, le code de fonction "lourd" ne sera pas exécuté. Au lieu de cela, le résultat mis en cache sera retourné, sans temps supplémentaire. Comment faire?

Vous pouvez, par exemple, écrire une fonction wrapper pour une fonction objectif. Une telle fonction peut recevoir un nom cached. Cette fonction accepte comme argument la fonction objectif et renvoie une nouvelle fonction équipée de capacités de mise en cache. Dans la fonction, cachedvous pouvez mettre en cache les résultats des appels précédents à la fonction cible à l'aide de l'entité Objectou Map. Voici le code de cette fonction:

function cached(fn){
  //     ,      
  const cache = Object.create(null);

  //      
  return function cachedFn (str) {

    //       -   
    if ( !cache[str] ) {
        let result = fn(str);

        //      
        cache[str] = result;
    }

    return cache[str]
  }
}

Voici un exemple d'utilisation de la fonction ci-dessus.


→  Voici le code d'une fonction similaire disponible dans la base de code Vue.

3. Convertissez une chaîne de la forme hello-world en une chaîne de la forme helloWorld


Lorsque plusieurs programmeurs travaillent ensemble sur le même projet, il est très important pour eux de prendre soin du style uniforme du code. Quelqu'un, par exemple, peut enregistrer certains identifiants composites dans un format helloWorld, et quelqu'un dans un format hello-world. Afin de mettre de l'ordre dans cette zone, vous pouvez créer une fonction qui convertit les hello-worldlignes de vue en lignes de vue helloWorld.

const camelizeRE = /-(\w)/g
const camelize = cached((str) => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
camelize('hello-world')
// "helloWorld"

C'est l'endroit du code Vue d'où vient cet exemple.

4. Déterminer dans quel environnement le code JavaScript s'exécute


De nos jours, étant donné le développement rapide des navigateurs, le code JavaScript peut être exécuté dans divers environnements. Afin de mieux adapter les projets à différents environnements, vous devez être en mesure de déterminer où les programmes sont exécutés:

const inBrowser = typeof window !== 'undefined'
const inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform
const weexPlatform = inWeex && WXEnvironment.platform.toLowerCase()
const UA = inBrowser && window.navigator.userAgent.toLowerCase()
const isIE = UA && /msie|trident/.test(UA)
const isIE9 = UA && UA.indexOf('msie 9.0') > 0
const isEdge = UA && UA.indexOf('edge/') > 0
const isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android')
const isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios')
const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
const isPhantomJS = UA && /phantomjs/.test(UA)
const isFF = UA && UA.match(/firefox\/(\d+)/)

C'est là que j'ai trouvé ce code.

5. Distinction entre les fonctions intégrées et définies par l'utilisateur


JavaScript est connu pour avoir deux types de fonctions. Le premier type est des fonctions intégrées ou, comme on les appelle aussi, des fonctions "natives". Ces fonctions sont fournies par l'environnement dans lequel le code est exécuté. Le deuxième type est ce que l'on appelle les "fonctions utilisateur", c'est-à-dire celles que les programmeurs écrivent eux-mêmes. Vous pouvez distinguer ces fonctions, en tenant compte du fait que, lors de leur conversion en chaînes, divers résultats sont renvoyés.

Array.isArray.toString() // "function isArray() { [native code] }"
function fn(){} 
fn.toString() // "function fn(){}"

Nous expérimenterons ce code dans la console.


La méthode de toString()fonction native renvoie toujours une construction de la forme suivante:

function fnName() { [native code] }

Sachant cela, vous pouvez écrire une fonction qui vous permet de distinguer les fonctions natives des fonctions définies par l'utilisateur:

function isNative (Ctor){
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

→  C'est l'endroit dans la base de code Vue où il y a une telle fonction.

Avez-vous réussi à trouver quelque chose d'intéressant en explorant le code dans les référentiels de projets JavaScript célèbres?


All Articles