写点什么

Vue 源码学习 | 4 个实用的 javascript 技巧

用户头像
devpoint
关注
发布于: 2021 年 03 月 09 日
Vue源码学习 | 4个实用的javascript技巧

学习一门语言的一种非常有效的方法就是阅读该编程语言开发的优秀开源项目的源代码。 Vuejs是最好的 Javascript 开源项目之一。

变量转字符串

vue/src/shared/util.js
复制代码

将值转换为字符串是一个非常常见的需求,在 Javascript 中,有两个函数将值转换为字符串:

  • String()

  • JSON.stringify()

这两个功能具有不同的机制,请看下面代码:


console.log(String(null)); // nullconsole.log(JSON.stringify(null)); // null
console.log(String(undefined)); // undefined 这里是字符串console.log(JSON.stringify(undefined)); // undefined 这里是变量
console.log(String("abc")); // abcconsole.log(JSON.stringify("abc")); // "abc"
console.log(String({ key: "value" })); // [object Object]console.log(JSON.stringify({ key: "value" })); // {"key":"value"}
console.log(String([1, 2, 3])); // 1,2,3console.log(JSON.stringify([1, 2, 3])); // [1,2,3]
const obj = { title: "devpoint", toString() { return "obj"; },};console.log(String(obj)); // objconsole.log(JSON.stringify(obj)); // {"title":"devpoint"}
复制代码


从上面输出结果来看,两个方法将对象转为字符串机制存在差异,如何选择呢?

  • 实际开发中我们需要将nullundefined转换为字符串时,经常是希望它返回一个空字符串。

  • 当需要将一个数组和一个普通对象转换为字符串时,经常使用JSON.stringify

  • 如果需要对象的toString方法被重写,则需要使用 String()。

  • 在其他情况下,使用String()将变量转换为字符串。

为了满足以上条件,Vue 源码的实现如下:


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);}
const obj = { title: "devpoint", toString() { return "obj"; },};console.log(toString(obj)); // objconsole.log(toString([1, 2, 3])); // [1, 2, 3]console.log(toString(undefined)); // ""console.log(toString(null)); // ""
复制代码

普通对象

vue/src/shared/util.js
复制代码

Object.prototype.toString允许将对象转换为字符串。对于普通对象,当调用此方法时,总是返回[object object]


const runToString = (obj) => Object.prototype.toString.call(obj);console.log(runToString({})); // [object Object]console.log(runToString({ title: "devpoint" })); // [object Object]console.log(runToString({ title: "devpoint", author: { name: "devpoint" } })); // [object Object]
复制代码

类似上面这种对象我们称之为普通对象。

在 Javascript 中还有一些特殊的对象,如ArrayStringRegExp,它们在 Javascript 引擎中具有特殊的设计。当它们调用Object.prototype.toString方法时,会返回不同的结果。


const runToString = (obj) => Object.prototype.toString.call(obj);console.log(runToString(["devpoint", 2021])); // [object Array]console.log(runToString(new String("devpoint"))); // [object String]console.log(runToString(/devpoint/)); // [object RegExp]
复制代码


为了区分特殊设计对象和普通对象,可以用下面的函数来实现。


function isPlainObject(obj) {    return Object.prototype.toString.call(obj) === "[object Object]";}
复制代码


很多时候,我们希望一个函数只执行一次。如果多次调用该函数,则只会执行第一次。

once

vue/src/shared/util.js
复制代码


很多时候,我们希望一个函数只执行一次。如果多次调用该函数,则只会执行第一次。


function once(fn) {    let called = false;    return function () {        if (!called) {            called = true;            fn.apply(this, arguments);        }    };}
function launchRocket() { console.log("我已经执行了");}const launchRocketOnce = once(launchRocket);launchRocketOnce();launchRocketOnce();launchRocketOnce();
复制代码


浏览器嗅探

vue/src/core/util/env.js
复制代码


不同的浏览器具有不同的userAgent。在 Internet Explorer 的userAgent中,始终包含单词MSIETrident。在 Chrome 浏览器的userAgent中,始终包含 Chrome 一词。


同样,在 Android 操作系统浏览器中,userAgent始终包含单词 Android。在 iOS 中,总是有 iPhone、iPad、iPod、iOS 一词。


因此,可以通过检查userAgent来确定当前的浏览器供应商和操作系统。


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+)/);
复制代码


附带说明一下,Edge 和 Chrome 均基于 Chromium,因此两种浏览器的userAgent都包含 Chrome 一词。也就是说,当浏览器的userAgent中包含 Chrome 一词时,该浏览器不一定是 Chrome。const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge


发布于: 2021 年 03 月 09 日阅读数: 22
用户头像

devpoint

关注

细节的追求者 2011.11.12 加入

专注前端开发,用技术创造价值!

评论

发布
暂无评论
Vue源码学习 | 4个实用的javascript技巧