5 descobertas JavaScript interessantes feitas no código fonte do Vue

A leitura do código fonte de estruturas conhecidas pode ajudar um programador a melhorar suas habilidades profissionais. O autor do artigo, cuja tradução estamos publicando hoje, analisou recentemente o código vue2.x. Ele encontrou neste código algumas idéias interessantes sobre JavaScript que decidiu compartilhar com todos.



1. Determinando o tipo exato de qualquer objeto


Como todos sabemos, em JavaScript, existem seis tipos de dados primitivos ( Boolean, Number, String, Null, Undefined, Symbol), e um tipo de objeto - Object. Você sabe distinguir entre tipos de valores de objetos diferentes? Um objeto pode ser uma matriz ou uma função, pode ser uma coleção de valores Mapou outra coisa. O que precisa ser feito para descobrir o tipo exato de objeto?

Antes de procurar uma resposta para essa pergunta, vamos pensar na diferença entre Object.prototype.toString.call(arg)e String(arg).

O uso dessas expressões visa converter o parâmetro passado para elas em uma string. Mas eles funcionam de maneira diferente.

Quando chamado, o String(arg)sistema tentará ligar arg.toString()ou arg.valueOf(). Como resultado, se dentro argou dentro do protótipoargesses métodos serão substituídos, ligarão Object.prototype.toString.call(arg)e String(arg)fornecerão resultados diferentes.

Considere um exemplo.

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

Executaremos esse código no console da ferramenta de desenvolvedor do navegador.


Nesse caso, chama obj.toString()e Object.prototype.toString.call(obj)leva aos mesmos resultados.

Aqui está outro exemplo.

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]

Vamos executar o código no console.


Agora, chamar o método do objeto .toString()e usar a construção Object.prototype.toString.call(obj)fornece resultados diferentes.

Aqui estão as regras que descrevem o comportamento de um método no padrão ECMAScript Object.prototype.toString().


Descrição do método Object.prototype.toString () no padrão ECMAScript

Examinando a documentação, podemos concluir que, quando chamadosObject.prototype.toString()para objetos diferentes, resultados diferentes serão retornados.

Explore essa ideia no console.


Além disso, o valor retornado Object.prototype.toString()é sempre apresentado no seguinte formato:

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

Se precisarmos extrair apenas uma parte dessa construção tag, podemos obtê-la removendo caracteres desnecessários do início e do fim da linha usando uma expressão regular ou método 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 esse recurso no console.


Como você pode ver, usando a função acima, você pode descobrir o tipo exato de uma variável de objeto.

Aqui , no repositório Vue, você pode encontrar o código para uma função semelhante.

2. Armazenando em cache os resultados da função


Suponha que exista uma função semelhante à seguinte que execute cálculos longos:

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

Ao criar essa função, pretendemos armazenar em cache os resultados retornados a ela. Quando essa função for chamada da próxima vez, passando os mesmos parâmetros de antes, o código da função "pesado" não será executado. Em vez disso, o resultado armazenado em cache será retornado, sem tempo extra. Como fazer isso?

Você pode, por exemplo, escrever uma função de invólucro para uma função objetiva. Essa função pode receber um nome cached. Esta função aceita, como argumento, a função objetivo e retorna uma nova função equipada com recursos de armazenamento em cache. Na função, cachedvocê pode armazenar em cache os resultados de chamadas anteriores para a função de destino usando a entidade Objectou Map. Aqui está o código para esta função:

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

Aqui está um exemplo de uso da função acima.


→  Aqui está o código para uma função semelhante disponível na base de códigos do Vue.

3. Converta uma sequência do formulário hello-world em uma sequência do formulário helloWorld


Quando vários programadores trabalham juntos no mesmo projeto, é muito importante que eles cuidem do estilo uniforme do código. Alguém, por exemplo, pode gravar alguns identificadores compostos em um formato helloWorlde alguém em um formato hello-world. Para ordenar essa área, você pode criar uma função que converta hello-worldlinhas de visualização em linhas helloWorld.

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

Este é o local do código Vue de onde este exemplo vem.

4. Determinando em qual ambiente o código JavaScript é executado


Atualmente, devido ao rápido desenvolvimento de navegadores, o código JavaScript pode ser executado em vários ambientes. Para adaptar melhor os projetos a diferentes ambientes, você precisa determinar onde os programas são executados:

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

Foi aqui que encontrei esse código.

5. Distinção entre funções internas e funções definidas pelo usuário


Sabe-se que o JavaScript possui dois tipos de funções. O primeiro tipo é interno, ou, como também é chamado, funções "nativas". Tais funções são fornecidas pelo ambiente em que o código é executado. O segundo tipo são as chamadas "funções do usuário", ou seja, aquelas que os programadores escrevem por si mesmas. Você pode distinguir entre essas funções, levando em consideração o fato de que, ao convertê-las em cadeias, vários resultados são retornados.

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

Experimentaremos esse código no console.


O método da toString()função nativa sempre retorna uma construção do seguinte formulário:

function fnName() { [native code] }

Sabendo disso, você pode escrever uma função que permita distinguir entre funções nativas e funções definidas pelo usuário:

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

→  Este é o local da base de códigos Vue onde existe essa função.

Você conseguiu encontrar algo interessante explorando o código nos repositórios de projetos JavaScript famosos?


All Articles