最近參與了公司的 Vue + ElementUI 后臺管理系統(tǒng)開發(fā),目前項目告一段落,正好做一個總結(jié)。
本文件分三部分進(jìn)行,其一是 JavaScript 部分,其二是 Vue 部分,最后是 ElementUI 部分。
一、對JavaScript的理解
如何復(fù)制一個Js對象?
在 C#,Java 等面向?qū)ο蟮母呒壵Z言中,可以直接通過 ‘=’ 賦值操作符復(fù)制一個對象,如果想定義一個指向?qū)ο蟮拇硪玫街羔樁x,然而 Js 早期出于性能的考慮,默認(rèn)將 ‘=’ 賦值操作符用于定義一個指向?qū)ο蟮闹羔槨?/p>
var a = { prop: 'val' }
var b = a
a.prop = 'nothing'
console.log(b.prop) // 'nothing'
無論怎樣 ‘復(fù)制’,新對象總是指向原始對象,原始對象發(fā)生改變,新對象也自然改變。如何復(fù)制對象呢?我們知道,對象可以互相嵌套,即對象屬性可以是另一個對象,那么通過普通的循環(huán)遍歷來復(fù)制原對象的屬性到一個新對象中是無法確保兩者保持一致的,因此這種復(fù)制也被稱作 ‘淺拷貝’。相對的通過遞歸遍歷來復(fù)制對象的方式也被稱作 ‘深拷貝’。
// 淺拷貝
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
// 深拷貝
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]); // 遞歸調(diào)用
} else {
c[i] = p[i];
}
}
return c;
}
當(dāng)然,可以在項目中引入函數(shù)庫(如 utils.js)來方便的引用這些擴(kuò)展函數(shù),不過我們不得不想有沒有更簡潔的方式來實現(xiàn)呢?答案是肯定的。
// utils.js
export const extendCopy(p) {...}
export const deepCopy(p, c) {...}
// page.js
import {extendCopy, deepCopy} from utils.js
a = {...}
b = extendCopy(a)
一般還可以通過如下方式解決:
- 通過 JSON 對象提供的 stringify 和 parse 方法組合使用的方式實現(xiàn)。
// 勉強(qiáng)也算一句話解決了,問題在于性能不理想。
var a = {}
var b = JSON.parse(JSON.stringify(a))
- 通過在函數(shù)中以返回值的形式生成新對象。
// 這種方式的缺點在于要以字面量的形式定義一個原始對象作為模板。
a = function(){
return { prop:"123" }
}
b = a()
d = a()
b === d // false
- 通過 ES2015 中提供的 Object.assign() 方法來復(fù)制。
// 簡潔明了,性能良好的解決方案
var a = {}
var b = Object.assign({},a)
通過上面的例子,我們不難得出一個結(jié)論:復(fù)制一個對象的最佳方案是采用 Object.assign() 方法來實現(xiàn)。
如何判斷一個元素是否在集合中
由于 Js 并沒有實現(xiàn)類似 array.contains(item) 的方法,因此只能通過元素在集合中的索引判斷。
var isSelected = function (row) {
return (selection || []).indexOf(row) > -1;
}
判斷一個變量是否為非空對象
首先 null 的類型是對象,如果在控制臺輸入 typeof null 會返回 "object",事實上我們要檢測一個非空數(shù)組,就要先排除 null 值的可能。
var isObject = function(obj) {
return obj !== null && typeof obj === 'object'
}
如何查詢一個數(shù)組并返回元素的子集
這里用到了數(shù)組的 filter 方法,此方法具有以下特點:
- 需要傳入一個回調(diào)函數(shù)作為參數(shù),此函數(shù)應(yīng)返回一個布爾值。
- filter 執(zhí)行時會對數(shù)組中的每一個元素執(zhí)行一邊回調(diào)函數(shù)。
- filter 的返回值為一個新數(shù)組,其成員為原數(shù)組中返回值為 true 的元素。
var users = allUsers.filter((user) => user.loged === true)
如何判斷一個對象沒有任何屬性
在 Js 中兩個空對象進(jìn)行比較會有什么結(jié)果呢?
var a = {}
a === {} // false
在 Js 中對 object 類型的數(shù)據(jù)應(yīng)用等于操作符時,比較的是兩個變量是否指向同一個引用,也就是說在內(nèi)存中是否為同一個地址。
而我們期待的結(jié)果是比較兩個對象在邏輯上是否具有相同的屬性,空對象是一個特例,它們不具有任何屬性。
if (Object.keys(search).length !== 0) {
args = Object.assign({}, args, search)
}
這里用到 Object.keys() 方法,獲取對象鍵的集合并判斷其長度是否為 0 即可。
如何使用循環(huán)刪除數(shù)組中的多個元素
for (let i = 0, let j = delIds.length - 1; i < j; i++) {
allItems.splice (delIds[i], 0)
}
如上根據(jù)索引來循環(huán)刪除原始數(shù)組中的元素是否可行呢,如果我們執(zhí)行這段代碼是無法得到預(yù)期結(jié)果的。原因在于當(dāng)前面的元素被刪除時,后面元素的索引發(fā)生了變化,在用刪除前的索引就無法定位正確的元素,解決的方法有兩種:
- 通過倒序循環(huán),獲取被刪除元素的索引,從后向前遍歷刪除。
for (let i = delIds.length - 1; i > 0; i++) {
allItems.splice (delIds[i], 0)
}
- 通過數(shù)組的兩個方法即 forEach 配合 indexOf 刪除,這種方法需要獲取被刪除元素本身,動態(tài)獲取它的索引。
delItems.forEach ((item) => {
allItems.splice (allItems.indexOf(item), 0)
})
(未完待續(xù)...)