Vue源碼學(xué)習(xí)_4個實用的Javascript技巧

來源 | https://juejin.cn/post/6971225536882278413
1、變量轉(zhuǎn)字符串
vue/src/shared/util.js
將值轉(zhuǎn)換為字符串是一個非常常見的需求,在JavaScript中,有兩個函數(shù)將值轉(zhuǎn)換為字符串:
String()
JSON.stringify()
這兩個功能具有不同的機制,請看下面代碼:
console.log(String(null)); // nullconsole.log(JSON.stringify(null)); // nullconsole.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"}
從上面輸出結(jié)果來看,兩個方法將對象轉(zhuǎn)為字符串機制存在差異,如何選擇呢?
實際開發(fā)中我們需要將null和undefined轉(zhuǎn)換為字符串時,經(jīng)常是希望它返回一個空字符串。
當(dāng)需要將一個數(shù)組和一個普通對象轉(zhuǎn)換為字符串時,經(jīng)常使用JSON.stringify。
如果需要對象的toString方法被重寫,則需要使用String()。
在其他情況下,使用String()將變量轉(zhuǎn)換為字符串。
為了滿足以上條件,Vue源碼的實現(xiàn)如下:
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)); // ""
2、普通對象
vue/src/shared/util.js
Object.prototype.toString允許將對象轉(zhuǎn)換為字符串。對于普通對象,當(dāng)調(diào)用此方法時,總是返回[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中還有一些特殊的對象,如Array、String和RegExp,它們在Javascript引擎中具有特殊的設(shè)計。當(dāng)它們調(diào)用Object.prototype.toString方法時,會返回不同的結(jié)果。
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]
為了區(qū)分特殊設(shè)計對象和普通對象,可以用下面的函數(shù)來實現(xiàn)。
function isPlainObject(obj) {return Object.prototype.toString.call(obj) === "[object Object]";}
很多時候,我們希望一個函數(shù)只執(zhí)行一次。如果多次調(diào)用該函數(shù),則只會執(zhí)行第一次。
3、once
vue/src/shared/util.js
很多時候,我們希望一個函數(shù)只執(zhí)行一次。如果多次調(diào)用該函數(shù),則只會執(zhí)行第一次。
function once(fn) {let called = false;return function () {if (!called) {called = true;fn.apply(this, arguments);}};}function launchRocket() {console.log("我已經(jīng)執(zhí)行了");}const launchRocketOnce = once(launchRocket);launchRocketOnce();launchRocketOnce();launchRocketOnce();
4、瀏覽器嗅探
vue/src/core/util/env.js
我們知道Javascript可以在瀏覽器、nodejs等環(huán)境中運行,那么如何檢查當(dāng)前的Javascript代碼是否在瀏覽器環(huán)境中運行?
如果Javascript在瀏覽器環(huán)境中運行,則會有一個全局對象:window。因此,可以通過以下方式判斷環(huán)境:
const inBrowser = typeof window !== "undefined";
在Chrome中執(zhí)行

在Node中執(zhí)行

如果腳本在瀏覽器環(huán)境中運行,那么我們可以通過以下方式獲取瀏覽器的userAgent:
const UA = inBrowser && window.navigator.userAgent.toLowerCase();
在Chrome中執(zhí)行

不同的瀏覽器具有不同的userAgent。在Internet Explorer的userAgent中,始終包含單詞MSIE和Trident。在Chrome瀏覽器的userAgent中,始終包含Chrome一詞。
同樣,在Android操作系統(tǒng)瀏覽器中,userAgent始終包含單詞Android。在iOS中,總是有iPhone、iPad、iPod、iOS一詞。
因此,可以通過檢查userAgent來確定當(dāng)前的瀏覽器供應(yīng)商和操作系統(tǒng)。
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一詞。
也就是說,當(dāng)瀏覽器的userAgent中包含Chrome一詞時,該瀏覽器不一定是Chrome。const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
學(xué)習(xí)更多技能
請點擊下方公眾號
![]()

