Vue學習的4個實用的Javascript技巧
學習一門語言的一種非常有效的方法就是閱讀該程式語言開發的優秀開源專案的原始碼。 Vuejs是最好的Javascript開源專案之一。
1.變數轉字串
vue/src/shared/util.js
將值轉換為字串是一個非常常見的需求,在Javascript中,有兩個函式將值轉換為字串:
String()
JSON.stringify()
這兩個功能具有不同的機制,請看下面程式碼:
console.log(String(null)); // null
console.log(JSON.stringify(null)); // null
console.log(String(undefined)); // undefined 這裡是字串
console.log(JSON.stringify(undefined)); // undefined 這裡是變數
console.log(String("abc")); // abc
console.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,3
console.log(JSON.stringify([1, 2, 3])); // [1,2,3]
const obj = {
title: "devpoint",
toString() {
return "obj";
},
};
console.log(String(obj)); // obj
console.log(JSON.stringify(obj)); // {"title":"devpoint"}
從上面輸出結果來看,兩個方法將物件轉為字串機制存在差異,如何選擇呢?
實際開發中我們需要將null和undefined轉換為字串時,經常是希望它返回一個空字串。
當需要將一個數組和一個普通物件轉換為字串時,經常使用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)); // obj
console.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允許將物件轉換為字串。對於普通物件,當呼叫此方法時,總是返回[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引擎中具有特殊的設計。當它們呼叫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]";
}
很多時候,我們希望一個函式只執行一次。如果多次呼叫該函式,則只會執行第一次。
3.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();
4.瀏覽器嗅探
vue/src/core/util/env.js
我們知道Javascript可以在瀏覽器、nodejs等環境中執行,那麼如何檢查當前的Javascript程式碼是否在瀏覽器環境中執行?
如果Javascript在瀏覽器環境中執行,則會有一個全域性物件:window。因此,可以通過以下方式判斷環境:
const inBrowser = typeof window !== "undefined";
在Chrome中執行
在Node中執行
如果指令碼在瀏覽器環境中執行,那麼我們可以通過以下方式獲取瀏覽器的userAgent
:
const UA = inBrowser && window.navigator.userAgent.toLowerCase();
在Chrome中執行
不同的瀏覽器具有不同的userAgent。在Internet Explorer的userAgent中,始終包含單詞MSIE和Trident。在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。