5 interesantes hallazgos de JavaScript realizados en el código fuente de Vue

Leer el código fuente de marcos conocidos puede ayudar a un programador a mejorar sus habilidades profesionales. El autor del artículo, cuya traducción publicamos hoy, analizó recientemente el código vue2.x. En este código encontró algunas ideas interesantes de JavaScript que decidió compartir con todos.



1. Determinar el tipo exacto de cualquier objeto


Como todos sabemos, en JavaScript, hay seis tipos de datos primitivos ( Boolean, Number, String, Null, Undefined, Symbol), y un tipo de objeto - Object. ¿Sabes cómo distinguir entre tipos de diferentes valores de objeto? Un objeto puede ser una matriz o una función, puede ser una colección de valores Mapu otra cosa. ¿Qué se debe hacer para descubrir el tipo exacto de objeto?

Antes de buscar una respuesta a esta pregunta, pensemos en la diferencia entre Object.prototype.toString.call(arg)y String(arg).

El uso de estas expresiones tiene como objetivo convertir el parámetro que se les pasa en una cadena. Pero funcionan de manera diferente.

Cuando se llama, el String(arg)sistema intentará llamar arg.toString()o arg.valueOf(). Como resultado, si está dentro argo en el prototipoargestos métodos se sobrescribirán, las llamadas Object.prototype.toString.call(arg)y String(arg)darán resultados diferentes.

Considera un ejemplo.

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

Ejecutaremos este código en la consola de la herramienta de desarrollo del navegador.


En este caso llama obj.toString()y Object.prototype.toString.call(obj)conduce a los mismos resultados.

Aquí hay otro ejemplo.

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]

Ejecutemos el código en la consola.


Ahora, llamar al método del objeto .toString()y usar la construcción Object.prototype.toString.call(obj)da resultados diferentes.

Aquí están las reglas que describen el comportamiento de un método en el estándar ECMAScript Object.prototype.toString().


Descripción del método Object.prototype.toString () en el estándar ECMAScript

Al observar la documentación, podemos concluir que cuando se solicitanObject.prototype.toString()objetos diferentes, se devolverán resultados diferentes.

Explore esta idea en la consola.


Además, el valor devuelto Object.prototype.toString()siempre se presenta en el siguiente formato:

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

Si necesitamos extraer solo una parte de esta construcción tag, podemos llegar a esta parte eliminando caracteres innecesarios desde el principio y el final de la línea utilizando una expresión o método regular String.prototype.slice().

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

Explore esta característica en la consola.


Como puede ver, utilizando la función anterior puede encontrar el tipo exacto de una variable de objeto.

Aquí , en el repositorio de Vue, puede encontrar el código para una función similar.

2. Almacenamiento en caché de los resultados de la función.


Supongamos que hay una función similar a la siguiente que realiza cálculos largos:

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

Al crear dicha función, tenemos la intención de almacenar en caché los resultados devueltos. Cuando se llama a esta función la próxima vez, pasándole los mismos parámetros que antes, el código de función "pesado" no se ejecutará. En su lugar, se devolverá el resultado almacenado en caché, sin tiempo adicional. ¿Cómo hacerlo?

Puede, por ejemplo, escribir una función de contenedor para una función objetivo. Tal función puede recibir un nombre cached. Esta función acepta, como argumento, la función objetivo y devuelve una nueva función equipada con capacidades de almacenamiento en caché. En la función, cachedpuede almacenar en caché los resultados de llamadas anteriores a la función de destino utilizando la entidad Objecto Map. Aquí está el código para esta función:

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]
  }
}

Aquí hay un ejemplo del uso de la función anterior.


→  Aquí está el código para una función similar que está disponible en la base de código Vue.

3. Convierta una cadena de la forma hello-world en una cadena de la forma helloWorld


Cuando varios programadores trabajan juntos en el mismo proyecto, es muy importante que cuiden el estilo uniforme del código. Alguien, por ejemplo, puede escribir algunos identificadores compuestos en un formato helloWorld, y alguien en un formato hello-world. Para poner orden en esta área, puede crear una función que convierta las hello-worldlíneas de vista en líneas de vista helloWorld.

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

Este es el lugar del código Vue de donde proviene este ejemplo.

4. Determinar en qué entorno se ejecuta el código JavaScript


Hoy en día, dado el rápido desarrollo de los navegadores, el código JavaScript se puede ejecutar en varios entornos. Para adaptar mejor los proyectos a diferentes entornos, debe poder determinar dónde se ejecutan los programas:

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+)/)

Aquí es donde encontré este código.

5. Distinción entre funciones incorporadas y funciones definidas por el usuario


Se sabe que JavaScript tiene dos tipos de funciones. El primer tipo está integrado o, como también se les llama, funciones "nativas". Dichas funciones son proporcionadas por el entorno en el que se ejecuta el código. El segundo tipo son las llamadas "funciones de usuario", es decir, aquellas que los programadores escriben ellos mismos. Puede distinguir entre estas funciones, teniendo en cuenta el hecho de que, al convertirlas en cadenas, se devuelven varios resultados.

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

Experimentaremos con este código en la consola.


El método de toString()función nativa siempre devuelve una construcción de la siguiente forma:

function fnName() { [native code] }

Sabiendo esto, puede escribir una función que le permita distinguir entre funciones nativas y funciones definidas por el usuario:

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

→  Este es el lugar en la base del código Vue donde existe dicha función.

¿Lograste encontrar algo interesante explorando el código en los repositorios de famosos proyectos de JavaScript?


All Articles