Vue源码学习 | 从源码中学习Javascript技巧

简介: 阅读代码是提高编码水平的好方法,优秀的源代码就像一部文学巨作,开拓思维,提供启示。最近在阅读vue2的源代码,学到了很多JS的编码技巧,后续陆续分享出来供参考,顺便总结一下代码阅读成果。

阅读代码是提高编码水平的好方法,优秀的源代码就像一部文学巨作,开拓思维,提供启示。最近在阅读vue2的源代码,学到了很多JS的编码技巧,后续陆续分享出来供参考,顺便总结一下代码阅读成果。

1. 缓存函数

先来看一个需求,假设有一个逻辑复杂的函数 superComputed 执行很费时间,如果每次使用都去计算一次,就会给用户带来很长的等待。这个时候需要考虑将计算结果缓存起来供后续程序调用,缓存函数需要实现当参数相同的情况下,直接取缓存结果。这跟服务器端为避免过多的查询数据库而用文件缓存查询结果相似,在前端如何实现呢?

const superComputed = (str) => {
    // 假设这个函数执行时间很长
    console.info("===> 超级计算开始了……");
    return `输入:${str}`;
};

编写一个 cached 函数来封装目标函数,这个 cached 函数接受目标函数作为参数,然后返回一个封装好的新函数。在 cached 函数的内部,可以使用 ObjectMap 缓存前一个函数调用的结果。

在VUE项目文件的第 153 行(点击进去)。

vue/src/shared/util.js

这个 cached 的代码如下:

/**
 * Create a cached version of a pure function.
 */
export function cached<F: Function>(fn: F): F {
    const cache = Object.create(null);
    return (function cachedFn(str: string) {
        const hit = cache[str];
        return hit || (cache[str] = fn(str));
    }: any);
}

现在将 cached 稍微改下,让其可以执行,每次执行 superComputed 函数都会打印 ===> 超级计算开始了……,以方便查看函数是否被缓存, 如下:

const superComputed = (str) => {
    // 假设这个函数执行时间很长
    console.info("===> 超级计算开始了……");
    return `输入:${str}`;
};
const cached = (fn) => {
    const cache = Object.create(null);
    return (str) => {
        const hit = cache[str];
        return hit || (cache[str] = fn(str));
    };
};
const cacheSuperComputed = cached(superComputed);
console.log(cacheSuperComputed("DevPoint"));
console.log(cacheSuperComputed("DevPoint"));
console.log(cacheSuperComputed("juejin"));

执行后的结果如下:

===> 超级计算开始了……
输入:DevPoint
输入:DevPoint
===> 超级计算开始了……
输入:juejin

从结果不难看出,函数执行结果在参数不变的情况下,取得缓存的数据。

2. 将dev-point转换为devPoint

在项目开发过程中,通常会出现变量风格不一致的问题,可以编写一个函数将其转换为统一的风格。

在VUE项目文件的第 160 行(点击进去)。

vue/src/shared/util.js
/**
 * Camelize a hyphen-delimited string.
 */
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})

将其稍微修改,里面的 cached 函数就是之前介绍的缓存函数。

const camelizeRE = /-(\w)/g;
const camelize = cached((str) => {
    return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ""));
});
console.log(camelize("dev-point")); // devPoint

3. 自定义函数判断

这里所说的自定义函数,指的是开发人员自定义的函数,不是Javascript原生宿主函数。可能想到原理就是将函数转换为字符串,先来看下结果:

console.log(cached.toString());
console.log(toString.toString());

执行结果如下:

// 下面是自定义函数的结果
(fn) => {
    const cache = Object.create(null);
    return (str) => {
        const hit = cache[str];
        return hit || (cache[str] = fn(str));
    };
}
// 下面是原生宿主函数的结果
function toString() { [native code] }

从执行结果来看,原生宿主函数 toString 的结果始终是 function fnName() { [native code] } 格式,因此就可以通过这个来区分,接下来看看VUE项目中的实现方式。

vue/src/core/util/env.js

在文件的第 58 行,代码如下:

/* istanbul ignore next */
export function isNative (Ctor: any): boolean {
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

4. JS运行环境

在前端快速发展的今天, JavaScript 代码可以在不同的运行环境中执行。为了更好的适应各种运行环境,需要判断当前代码是在哪个运行环境中执行的,下面来学习一下Vue是如何判断运行环境的:

vue/src/core/util/env.js

在文件的第 6 行开始,代码如下:

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

这些判断代码都值得借鉴的,这里不展开介绍了,之前在《Vue源码学习 | 4个实用的Javascript技巧》介绍了浏览器的判断。


相关文章
|
10天前
|
JavaScript
JS实现简单的打地鼠小游戏源码
这是一款基于JS实现简单的打地鼠小游戏源码。画面中的九宫格中随机出现一个地鼠,玩家移动并点击鼠标控制画面中的锤子打地鼠。打中地鼠会出现卡通爆破效果。同时左上角统计打地鼠获得的分数
25 1
|
3天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
2天前
|
前端开发 JavaScript
用HTML CSS JS打造企业级官网 —— 源码直接可用
必看!用HTML+CSS+JS打造企业级官网-源码直接可用,文章代码仅用于学习,禁止用于商业
19 1
|
3天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
8天前
|
JavaScript
JS趣味打字金鱼小游戏特效源码
hi fish是一款打字趣味小游戏,捞出海里的鱼,捞的越多越好。这款游戏用于电脑初学者练习打字。初学者可以根据自己的水平设置游戏难度。本段代码可以在各个网页使用,有需要的朋友可以直接下载使用,本段代码兼容目前最新的各类主流浏览器,是一款非常优秀的特效源码!
15 3
|
10天前
|
JavaScript
JS鼠标框选并删除HTML源码
这是一个js鼠标框选效果,可实现鼠标右击出现框选效果的功能。右击鼠标可拖拽框选元素,向下拖拽可实现删除效果,简单实用,欢迎下载
20 4
|
10天前
|
JavaScript
js实现简洁实用的网页计算器功能源码
这是一款使用js实现简洁实用的网页计算器功能源码。可实现比较基本的加减乘除四则运算功能,界面简洁实用,是一款比较基本的js运算功能源码。该源码可兼容目前最新的各类主流浏览器。
18 2
|
9天前
|
移动开发 HTML5
html5+three.js公路开车小游戏源码
html5公路开车小游戏是一款html5基于three.js制作的汽车开车小游戏源代码,在公路上开车网页小游戏源代码。
27 0
html5+three.js公路开车小游戏源码
|
9天前
|
JavaScript
JS趣味打字金鱼小游戏特效源码
hi fish是一款打字趣味小游戏,捞出海里的鱼,捞的越多越好。这款游戏用于电脑初学者练习打字。初学者可以根据自己的水平设置游戏难度。本段代码可以在各个网页使用,有需要的朋友可以直接下载使用,本段代码兼容目前最新的各类主流浏览器,是一款非常优秀的特效源码!
18 0
JS趣味打字金鱼小游戏特效源码
|
11天前
|
JavaScript
js实现的精美彩色tab选项卡切换特效源码
js实现的精美彩色tab选项卡切换特效源码是一段基于JS实现的文件夹tab选项卡切换效果,拥有彩色、单色两种选择,点击标签选项卡可实现相应的变色效果,非常有意思,欢迎对此段代码感兴趣的朋友前来下载使用。
20 2