This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

1. Introduction

Hi, I’m Wakawa. Welcome to follow my official account Ruochuan Vision. Recently, I organized an activity to read the source code together, and those who are interested can join in with my wechat account RuoChuan12. It has been going on for more than two months.

If you want to learn source code, Underscore, Lodash, Vuex, Sentry, Axios, Redux, KOA, VUUE-Devtools, Vuex4, Koa-Compose, vue 3.2 are highly recommended Release, VUE-this, CREate-Vue, toy Vite and more than 10 source code articles.

This article warehouse vue-analysis, ask a star^_^

Recently, we organized a source code reading activity to learn source code together. So we search for all kinds of worth learning, and the code line is not many source.

I wrote two previous articles about Vue3.

  • Beginners can also understand Vue3 source code in those practical basic tool functions

This article describes how to learn the basics of JavaScript, recommends many books and learning materials, and shares some of my experience.

  • Vue 3.2 has been released, so how did Yu Creek release vue.js?

Readers who participated in the source code reading feedback, TA is still using Vue2. Can you write a Vue2 basic tool function. As a knowledge blogger humble number, in line with the purpose of learning what I have learned, for my own use, to help others, so write this article. It is a sister to Vue3 tool functions.

Reading this article, you will learn:

1.The Vue2 source code contains dozens of utility functions in the shared module2.How to learn good code and ideas from source code and put them into your own projects3.How to learn JavaScript basics, will recommend a lot of learning materials4.I share some experience5., etc.Copy the code

2. Prepare the environment

2.1 Read the Open Source Project Contribution Guide

Open the Vue repository, and open source projects can generally find contribution guidelines at readme. md or.github/contributing.

The contribution guide has a lot of information about participating in project development. Such as how to run, what is the project directory structure. How to put into development, what knowledge reserves need.

You can find the shared module in the project directory structure description.

shared: contains utilities shared across the entire codebase.

Both readme. md and contributing. Md are generally in English. It might confuse some people. Actually do not understand, can be completely with the help of cross word translation, full page translation and Google Translate translation tools. Then add English to the follow-up study plan.

Vue /vue/ SRC /shared

It can also be accessed using Github1s, which is faster. github1s vue/vue/src/shared

2.2 In order to reduce the difficulty of the article, directly learn packaged source code

The source code vue/vue/ SRC /shared, which uses the Flow type, may not be easy to understand.

To make this article easier, we’ll go straight to lines 14 through 379 of the packaged dist/vue.js in the source repository.

Of course, this might be a bit verbose. I can jump right into 3. Utility functions. But through my introduction above, even beginners can understand the source code of some open source projects, maybe there will be a sense of accomplishment. In addition, the interview is asked to be similar questions or pen test questions, you say that read Vue2 source code learned, the interviewer absolutely impressed you.

3. Utility functions

The packaged vue.js is explained in lines 14 through 379.

3.1 emptyObject

/ *! * Vue.js v2.6.14 * (c) 2014-2021 Evan You * Released Under the MIT License. */
/ * * /
var emptyObject = Object.freeze({});
Copy the code

Freeze an object. The first layer cannot be modified. Objects also have methods to determine if they are frozen.

Object.isFrozen(emptyObject); // true
Copy the code

For object API recommendations see my previous article JavaScript object all API parsing

Also check out Teacher Ruan Yifeng’s INTRODUCTION to ES6 at Reflect

3.2 Whether isUndef is undefined

// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.
function isUndef (v) {
  return v === undefined || v === null
}
Copy the code

3.3 Whether isDef is defined

There are six false values in JavaScript.

false
null
undefined
0
' '(Empty string)NaN
Copy the code

In order to determine accurately, Vue2 source code encapsulated isDef, isTrue, isFalse functions to determine accurately.

The name shows the meaning.

function isDef (v) {
  returnv ! = =undefined&& v ! = =null
}
Copy the code

3.4 whether isTrue isTrue

The name shows the meaning.

function isTrue (v) {
  return v === true
}
Copy the code

3.5 isFalse Indicates whether isFalse

The name shows the meaning.

function isFalse (v) {
  return v === false
}
Copy the code

3.6 isPrimitive determines whether the value is the original value

Check if it is a string, array, symbol, or Boolean.

/** * Check if value is primitive. */
function isPrimitive (value) {
  return (
    typeof value === 'string' ||
    typeof value === 'number' ||
    // $flow-disable-line
    typeof value === 'symbol' ||
    typeof value === 'boolean')}Copy the code

3.7 isObject Identifies an object

Because typeof NULL is ‘object’. Array and so on are also true using this function

/** * Quick object check - this is primarily used to tell * Objects from primitive values when we know the value * is a JSON-compliant type. */
function isObject (obj) {
  returnobj ! = =null && typeof obj === 'object'
}

/ / example:
isObject([]) // true
// Sometimes the distinction between arrays and objects is not necessary
Copy the code

3.8 toRawType is converted to the original type

Object. The prototype. The toString () method returns a string said the Object.

mdn

The ECMA specification describes these types.

ECMAScript5.1 Chinese version

/** * Get the raw type string of a value, e.g., [object Object]. */
var _toString = Object.prototype.toString;

function toRawType (value) {
  return _toString.call(value).slice(8, -1)}/ / example:
toRawType(' ') // 'String'
toRawType() // 'Undefined'
Copy the code

3.9 isPlainObject Is a pure object

/** * Strict object type check. Only returns true * for plain JavaScript objects. */
function isPlainObject (obj) {
  return _toString.call(obj) === '[object Object]'
}

// isObject([]) is true
// This is the way to tell if an object is pure.
/ / example:
isPlainObject([]) // false
isPlainObject({}) // true
Copy the code

3.10 isRegExp is a regular expression

function isRegExp (v) {
  return _toString.call(v) === '[object RegExp]'
}

/ / example:
// Determine if it is a regular expression
isRegExp(/ruochuan/) // true
Copy the code

3.11 isValidArrayIndex Is an available array index

The available index values for arrays are 0 (‘0’), 1 (‘1’), 2 (‘2’)…

/** * Check if val is a valid array index. */
function isValidArrayIndex (val) {
  var n = parseFloat(String(val));
  return n >= 0 && Math.floor(n) === n && isFinite(val)
}
Copy the code

The global isFinite() function is used to determine whether the passed parameter value is a finite number. If necessary, the parameter is converted to a number first.

isFinite mdn

isFinite(Infinity);  // false
isFinite(NaN);       // false
isFinite(-Infinity); // false

isFinite(0);         // true
isFinite(2e64);      // True, in the stronger number.isFinite (null) will get false

isFinite('0');       // True, in the stronger number.isFinite ('0') will get false
Copy the code

3.12 isPromise Check whether it is a promise

function isPromise (val) {
  return (
    isDef(val) &&
    typeof val.then === 'function' &&
    typeof val.catch === 'function')}/ / example:
isPromise(new Promise()) // true
Copy the code

IsDef is a little less precise than isObject. But enough.

3.13 Converting toString to a String

Convert to a string. Is an array or Object and the Object’s toString method is the Object. The prototype. ToString, using JSON. Stringify conversion.

/** * Convert a value to a string that is actually rendered. */
function toString (val) {
  return val == null
    ? ' '
    : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
      ? JSON.stringify(val, null.2)
      : String(val)
}
Copy the code

3.14 toNumber to digits

Convert to a number. Return the original string if the conversion fails.

/** * Convert an input value to a number for persistence. * If the conversion fails, return original string. */
function toNumber (val) {
  var n = parseFloat(val);
  return isNaN(n) ? val : n
}

toNumber('a') // 'a'
toNumber('1') / / 1
toNumber('1a') / / 1
toNumber('a1') // 'a1'
Copy the code

3.15 makeMap Generates a Map (Object)

Pass in a comma-separated string, generate a map(key-value pairs), and return a function to check if the key value is in the map. The second argument is the lowercase option.

/** * Make a map and return a function for checking if a key * is in that map. */
function makeMap (str, expectsLowerCase) {
  var map = Object.create(null);
  var list = str.split(', ');
  for (var i = 0; i < list.length; i++) {
    map[list[i]] = true;
  }
  return expectsLowerCase
    ? function (val) { return map[val.toLowerCase()]; }
    : function (val) { returnmap[val]; }}// object.create (null) An empty Object with no prototype chain
Copy the code

3.16 isBuiltInTag Whether isBuiltInTag is built-in

/** * Check if a tag is a built-in tag. */
var isBuiltInTag = makeMap('slot,component'.true);

// The function returned. The second argument is case insensitive
isBuiltInTag('slot') // true
isBuiltInTag('component') // true
isBuiltInTag('Slot') // true
isBuiltInTag('Component') // true
Copy the code

3.17 isReservedAttribute Whether it is a reserved attribute

/** * Check if an attribute is a reserved attribute. */
var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');

isReservedAttribute('key') // true
isReservedAttribute('ref') // true
isReservedAttribute('slot') // true
isReservedAttribute('slot-scope') // true
isReservedAttribute('is') // true
isReservedAttribute('IS') // undefined
Copy the code

3.18 remove Removes an item in an array

/** * Remove an item from an array. */
function remove (arr, item) {
  if (arr.length) {
    var index = arr.indexOf(item);
    if (index > -1) {
      return arr.splice(index, 1)}}}Copy the code

Splice is actually a performance-intensive approach. If you delete one element in the array, all the other elements move.

The axios InterceptorManager interceptor is stored in an array. When you actually remove an interceptor, you just set the interceptor to NULL. Instead of removing it by splice. If the last execution is null, the effect is the same. In the case of the Axios interceptor, it has to be said that performance is well considered. Because interceptors are user-defined and theoretically infinite, performance considerations are necessary.

Take a look at the following example of axios interceptor code:

// The code is truncated
/ / declare
this.handlers = [];

/ / remove
if (this.handlers[id]) {
    this.handlers[id] = null;
}

/ / execution
if(h ! = =null) {
    fn(h);
}
Copy the code

3.19 hasOwn Checks whether it is its own attribute

/** * Check whether an object has the property. */
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn (obj, key) {
  return hasOwnProperty.call(obj, key)
}

/ / example:

// Special note: __proto__ is the prototype of the browser implementation, which will be used later
// There are several prototype-related apis available
// Object.getPrototypeOf
// Object.setPrototypeOf
// Object.isPrototypeOf

//. Call is the function in which this is specified as the first argument and the function is executed.

hasOwn({__proto__: { a: 1 }}, 'a') // false
hasOwn({ a: undefined }, 'a') // true
hasOwn({}, 'a') // false
hasOwn({}, 'hasOwnProperty') // false
hasOwn({}, 'toString') // false
// is a property of its own, not up the chain through the prototype.
Copy the code

3.20 the cached cache

Use closure features to cache data

/** * Create a cached version of a pure function. */
function cached (fn) {
  var cache = Object.create(null);
  return (function cachedFn (str) {
    var hit = cache[str];
    return hit || (cache[str] = fn(str))
  })
}

Copy the code

Lao Yao: The JavaScript Regular Expressions Mini-Book is here! Everyone who saw it said yes. Therefore, this article will not describe the regular knowledge points in detail.

3.21 Camelize to small hump

On-click => onClick

/** * Camelize a hyphen-delimited string. */
var camelizeRE = /-(\w)/g;
var camelize = cached(function (str) {
  return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ' '; })});Copy the code

Capitalize the first letter

Capitalize the first letter

/** * Capitalize a string. */
var capitalize = cached(function (str) {
  return str.charAt(0).toUpperCase() + str.slice(1)});Copy the code

3.23 Hyphenate small hump to hyphenate

onClick => on-click

/** * Hyphenate a camelCase string. */
var hyphenateRE = /\B([A-Z])/g;
var hyphenate = cached(function (str) {
  return str.replace(hyphenateRE, '- $1').toLowerCase()
});
Copy the code

3.24 polyfillBind Bind gasket

/** * Simple bind polyfill for environments that do not support it, * e.g., PhantomJS 1.x. Technically, we don't need this anymore * since native bind is now performant enough in most browsers. * But removing it would mean breaking code that was able to run in * PhantomJS 1.x, so this must be kept for backward compatibility. */

/* istanbul ignore next */
function polyfillBind (fn, ctx) {
  function boundFn (a) {
    var l = arguments.length;
    return l
      ? l > 1
        ? fn.apply(ctx, arguments)
        : fn.call(ctx, a)
      : fn.call(ctx)
  }

  boundFn._length = fn.length;
  return boundFn
}

function nativeBind (fn, ctx) {
  return fn.bind(ctx)
}

var bind = Function.prototype.bind
  ? nativeBind
  : polyfillBind;
Copy the code

Simply put, older browsers don’t support the native bind function. At the same time compatible writing method, the number of parameters to make a judgment, using call and apply implementation, it is said that more parameters suitable for apply, less call performance better.

If you are not familiar with the use and implementation of call, apply, and bind, you can check whether you can simulate the JS call and apply methods

ToArray converts class arrays into real arrays

To convert an array of classes to an array, support where to start. The default is 0.

/** * Convert an Array-like object to a real Array. */
function toArray (list, start) {
  start = start || 0;
  var i = list.length - start;
  var ret = new Array(i);
  while (i--) {
    ret[i] = list[i + start];
  }
  return ret
}

/ / example:
function fn(){
  var arr1 = toArray(arguments);
  console.log(arr1); // [1, 2, 3, 4, 5]
  var arr2 = toArray(arguments.2);
  console.log(arr2); / / [3, 4, 5]
}
fn(1.2.3.4.5);
Copy the code

3.26 the extend merger

/** * Mix properties into target object. */
function extend (to, _from) {
  for (var key in _from) {
    to[key] = _from[key];
  }
  return to
}

/ / example:
const data = { name: 'if the sichuan' };
const data2 = extend(data, { mp: 'Wakawa View'.name: 'It's Wakawa.' });
console.log(data); // {name: "yes ", mp:" yes "}
console.log(data2); // {name: "yes ", mp:" yes "}
console.log(data === data2); // true
Copy the code

3.27 toObject Transferring an object

/** * Merge an Array of Objects into a single Object. */
function toObject (arr) {
  var res = {};
  for (var i = 0; i < arr.length; i++) {
    if(arr[i]) { extend(res, arr[i]); }}return res
}

// Array to object
toObject(['if the sichuan'.'Wakawa View'])
// {0: 'ruo ', 1:' chuan ', 2: 'shi ', 3:' ye '}
Copy the code

3.28 NoOP empty function

/* eslint-disable no-unused-vars */
/** * Perform no operation. * Stubbing args to make Flow happy without leaving useless transpiled code * with ... rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). */
function noop (a, b, c) {}

// Initialize the assignment
Copy the code

3.29 No always Returns false

/** * Always return false. */
var no = function (a, b, c) { return false; };
/* eslint-enable no-unused-vars */
Copy the code

3.30 identity Returns the parameter itself

/** * Return the same value. */
var identity = function (_) { return _; };
Copy the code

3.31 genStaticKeys Generates static attributes

/** * Generate a string containing static keys from compiler modules. */
function genStaticKeys (modules) {
  return modules.reduce(function (keys, m) {
    return keys.concat(m.staticKeys || [])
  }, []).join(', ')}Copy the code

3.32 looseEqual

Because arrays, objects, and so on are reference types, two things look equal, but strict equality is not equal.

var a = {};
var b = {};
a === b; // false
a == b; // false
Copy the code

So this function is a recursive comparison of arrays, dates, and objects. Loose equality if the contents are completely equal.

/** * Check if two values are loosely equal - that is, * if they are plain objects, do they have the same shape? * /
function looseEqual (a, b) {
  if (a === b) { return true }
  var isObjectA = isObject(a);
  var isObjectB = isObject(b);
  if (isObjectA && isObjectB) {
    try {
      var isArrayA = Array.isArray(a);
      var isArrayB = Array.isArray(b);
      if (isArrayA && isArrayB) {
        return a.length === b.length && a.every(function (e, i) {
          return looseEqual(e, b[i])
        })
      } else if (a instanceof Date && b instanceof Date) {
        return a.getTime() === b.getTime()
      } else if(! isArrayA && ! isArrayB) {var keysA = Object.keys(a);
        var keysB = Object.keys(b);
        return keysA.length === keysB.length && keysA.every(function (key) {
          return looseEqual(a[key], b[key])
        })
      } else {
        /* istanbul ignore next */
        return false}}catch (e) {
      /* istanbul ignore next */
      return false}}else if(! isObjectA && ! isObjectB) {return String(a) === String(b)
  } else {
    return false}}Copy the code

3.33 looseIndexOf looseIndexOf

This function implements loose equality. The native indexOf is strictly equal.

/** * Return the first index at which a loosely equal value can be * found in the array (if value is a plain object, the array must * contain an object of the same shape), or -1 if it is not present. */
function looseIndexOf (arr, val) {
  for (var i = 0; i < arr.length; i++) {
    if (looseEqual(arr[i], val)) { return i }
  }
  return -1
}
Copy the code

3.34 once Ensures that the function is executed only once

Use closure features to store state

/** * Ensure a function is called only once. */
function once (fn) {
  var called = false;
  return function () {
    if(! called) { called =true;
      fn.apply(this.arguments); }}}const fn1 = once(function(){
  console.log('Hey hey, whatever you call it, I'm only going to do it once.');
});

fn1(); // 'Hey hey, whatever you call it, I'm only going to execute it once'
fn1(); / / no output
fn1(); / / no output
fn1(); / / no output
Copy the code

3.35 Life cycle, etc

var SSR_ATTR = 'data-server-rendered';

var ASSET_TYPES = [
  'component'.'directive'.'filter']; [Vue lifecycle](HTTPS://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90)

var LIFECYCLE_HOOKS = [
  'beforeCreate'.'created'.'beforeMount'.'mounted'.'beforeUpdate'.'updated'.'beforeDestroy'.'destroyed'.'activated'.'deactivated'.'errorCaptured'.'serverPrefetch'
];
Copy the code

4. Finally, recommend some articles and books

This section, like the Vue3 tool functions article, is recommended, so copy it here.

Start with a few articles and a few books worth reading that I think are good JavaScript apis.

JavaScript string all API full decryption

Decrypt all JavaScript array apis

Regular expression front end usage manual

Lao Yao: The JavaScript Regular Expression Mini-book is here!

Lao Yao shallow talk: how to learn JavaScript?

Lxchuan12.geitee. IO /js-object-a…

MDN JavaScript

JavaScript Advanced Programming, 4th edition

The definitive Guide to JavaScript, 7th edition

JavaScript Object Oriented Programming 2 covers object orientation in great detail.

Ruan Yifeng: Introduction to ES6

Modern JavaScript Tutorial

JavaScript you Don’t Know, vol. 1

JavaScript Design Patterns and Development Practices

I also can’t read the book experience from small white come over. Now write articles to share.

How I read: Multiple books at the same time, looking at similar chapters, such as functions. After reading this may not understand, look at the next, a few books read down the basic understand, did not understand again, look a few times, can avoid forgetting, consolidate the relevant chapters. Of course, the beginning of reading is very uncomfortable, can not read. Most of these books are available on wechat. If you are accustomed to reading paper books, you can buy them.

Watch videos and practice simple projects.

For example, you can register a Github account by yourself, copy the code in the book in sections, and submit it to Github. Only after practice, you will feel better.

Another example is freeCodeCamp, a Chinese online learning website. Reading books is a great way to learn systematically. Later I was to see the source code more, write articles to share out to you.

5. To summarize

This article reviewed dist/vue.js packed with shared modules in Vue2 source code in lines 14 to 379. Source code is not that difficult, at least many can understand, such as tool functions. The difficulty may be: not knowing the application scenario.

Vue2 tool functions are well named, such as “is”, “to”, and “has”, allowing developers to see the semantics of the function at a glance.

These functions are also very simple, basically one function only does one thing.

Readers are advised to write unfamiliar functions, which can help consolidate basic knowledge and fill gaps.

Finally, you can continue to pay attention to me @Ruogawa. Welcome to join us in ruochuan12 and learn about the source code together.

About && communication groups

Recently, I organized a reading activity for source code. If you are interested, you can join me in wechat ruochuan12 for long-term communication and learning.

Author: Often in the name of ruochuan mixed traces in rivers and lakes. Welcome to add my wechat account ruochuan12. Front road | know very little, only good study. Concern about the public number if chuan vision, every week to learn the source code, learn to see the source code, advanced advanced front end. Wakawa’s blog segmentfault wakawa’s view column, has opened a column on wakawa’s view, welcome to follow ~ dig gold column, welcome to follow ~ github blog, beg a star^_^~