In our interview process, we often come across the source section, because a good framework usually contains a lot of design concepts and programming practices. I have been looking at the source code for Vue2 and have found a lot of interesting implementations. Now that Vue3 has been released, the fact that Vue2 is an excellent framework does not mean that we have learned some best practices from it.

Those of you who are not interested in Vue can also take a look, because I’m just talking about some JavaScript uses that I learned from the implementation of the framework, and I don’t touch on the concept of Vue.

  1. Get a string in HTML format with non-tag text (vue/src/compiler/parser/entity-decoder.js)

Suppose we have a string like this:

Var HTML = ‘hello world hello XXX ‘. We now want to extract the non-labeled text and get the following result:

Hello world hello XXX ‘. What should I do? The first thing that comes to mind is regular expressions, but in this case regular expressions can be very annoying to write, so let’s take a look at how the developers of Vue handle it:

  • Since this string isHTMLText format, we can parse it into the correspondingHTMLElements.
  • HTMLElements of thetextContentProperty can be used to getHTMLElement.

The code is as follows:

function decoder(html){
  let decoder = document.createElement('div')
  decoder.innerHTML = html
  console.log(decoder.textContent)
  // return decoder.textContent
}
Copy the code

This code creates a div element as the container, sets innerHTML to convert the string to the corresponding HTML element, and then retrieves the textContent through the textContent attribute.

  1. Determine the operating environment (vue/src/core/util/env.js)

With the rapid development of the front end, we can now run JavaScript code in multiple environments. In order to make adjustments to the different runtime environments, we need to know which environment our code is running in. Let’s take a look at how Vue determines the runtime environment:

const inBrowser = typeof window! = ='undefined'
const inWeex = typeofWXEnvironment ! = ='undefined'&&!!!!! WXEnvironment.platformconst 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) && ! isEdgeconst isPhantomJS = UA && /phantomjs/.test(UA)
const isFF = UA && UA.match(/firefox\/(\d+)/)
Copy the code

If our code is running in a browser, we’ll definitely get onewindowObject, so we can go throughconst inBrowser = typeof window ! == 'undefined'This is the way to judge the environment.

And in the browser, we can go throughwindowObject to the browseruserAgent.For different browsersuserAgentIt’s different, likeIEtheuserAgentIt always includesMSIEAnd theChrometheuserAgentWill containChrome. Similar to the Android browseruserAgentWill takeAndroid. So we go throughuserAgentYou can determine what browser you’re using and what operating system you’re running on. The above code already lists the major browser and operating system judgmentsEdgeThe latest version of the browser is also based onChromiumKernel, so it’suserAgentAlso containChromeSo we have to writeconst isChrome = UA && /chrome\/\d+/.test(UA) && ! isEdgeSuch code to determine the current environment isChrome.

  1. Determine if a function is user-defined (vue/src/core/util/env.js)

In general, we use only two types of functions, those provided by the environment and those defined by the user, which behave differently when converted to a string:

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

Function fnName() {[native Code]}; function fnName() {[native Code]}; function fnName() {[native Code]};

function isNative (Ctor){
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}
Copy the code
  1. Implement a function that only executes once (vue/src/shared/util.js)

Many times we want a function to be executed only once, and even if it is called multiple times, it will only be executed the first time, so we can write code like this:

function once (fn) {
  let called = false
  return function () {
    if(! called) { called =true
      fn.apply(this.arguments)}}}Copy the code

So we’re going to skip it when we do it later, but this is done using higher-order functions, so you can check out my previous article advanced Tips for JavaScript. Let’s test this method:

You can see that the test method is executed only once.

  1. Cache function execution results (vue/src/shared/util.js)

As I mentioned in the previous blog, sometimes a function execution is time-consuming and we want to cache the results. This way, when called later, if the parameters are the same, we can skip the calculation and return the result directly. All we need is to implement a cached function that takes the actual function that was called as an argument, and then returns a wrapped function. In this cached function, we can use an object or Map to cache the results.

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]
  }
}
Copy the code

  1. Transform the naming style (vue/src/shared/util.js)

Each of us may use a different programming style, some prefer the camel’s hump, others prefer the small bar connection, to solve this problem, we can write a function to do the uniform conversion. (Such as converting A-B-C to aBC)

const camelizeRE = /-(\w)/g
const camelize = cached((str) => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
camelize('a-b-c')
// "aBC"
Copy the code
  1. Determine the type of the object (vue/src/shared/util.js)

In JavaScript, there are six basic types (Boolean, Number, String, Null, Undefined, Symbol) and an object type, but object types can be subdivided into many types. An object can be an array, a function, and so on. Is there any way we can get the exact type?

We can use the Object. The prototype. ToString converts an Object into a string, if we use {} to create objects, this method always returns [Object Object].

For arrays, regular expressions, and other object types that come with the environment, they return different results.

Using this feature we can determine if an object is the object we created with {} :

function isPlainObject (obj){
  return Object.prototype.toString.call(obj) === '[object Object]'
}
Copy the code

And we noticed that the Object. The prototype. The toString (), the return value is always to [the Object tag] form, if we just want this tag, we can take other things out, For simplicity, use either regular or string.prototype.slice ().

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

So we can get the type of a variable.

  1. Convert value to string (vue/src/shared/util.js)

We often need to convert a value to a string. In JavaScript, we have two ways to get a string:

  • String()
  • JSON.stringify()

However, the implementation mechanism of the two approaches is different:

As we saw, they convert strings based on completely different rules. String(arg) will try to call arg.toString() or arg.valueof (), so which one should we use?

  • For null and undefined, we want to convert it to an empty string

  • We use json.stringify when converting an array or the object we created

  • If the object’s toString method is overridden, then we’ll prefer to use String().

  • In other cases, it’s always String()

    To match the above requirements, the Vue developers implemented the following:

    function isPlainObject (obj){
      return Object.prototype.toString.call(obj) === '[object Object]'
    }
    function toString (val) {
      if(val === null || val === undefined) return ' '
    if (Array.isArray(val)) return JSON.stringify(val)
    if (isPlainObject(val) && val.toString === Object.prototype.toString)
        return JSON.stringify(val)
      return String(val)
    }
    Copy the code

    Is full of harvest day, by reading the best framework code can quickly improve our use of language, strengthen our understanding of the features, summarizes some programming practice, our programming ability also in virtually to get qualitative leap, when very recommend further learning a language with the language to achieve good code to read. Could there be more fun in JavaScript than learning so much just by talking about Vue’s three source files? I hope this article can also give you some help, Happy Coding ~