Vue + ElementUI 後臺管理系統專案心得(一)

osimly發表於2017-03-24

最近參與了公司的 Vue + ElementUI 後臺管理系統開發,目前專案告一段落,正好做一個總結。

本檔案分三部分進行,其一是 JavaScript 部分,其二是 Vue 部分,最後是 ElementUI 部分。

一、對JavaScript的理解

1. 如何複製一個Js物件?

在 C#,Java 等物件導向的高階語言中,可以直接通過 '=' 賦值操作符複製一個物件,如果想定義一個指向物件的代理要用到指標定義,然而 Js 早期出於效能的考慮,預設將 '=' 賦值操作符用於定義一個指向物件的指標。

var a = { prop: 'val' }
var b = a
a.prop = 'nothing'
console.log(b.prop) // 'nothing'複製程式碼

無論怎樣 “複製”,新物件總是指向原始物件,原始物件發生改變,新物件也自然改變。如何複製物件呢?我們知道,物件可以互相巢狀,即物件屬性可以是另一個物件,那麼通過普通的迴圈遍歷來複制原物件的屬性到一個新物件中是無法確保兩者保持一致的,因此這種複製也被稱作 “淺拷貝”。相對的通過遞迴遍歷來複制物件的方式也被稱作 “深拷貝”。

// 淺拷貝
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]); // 遞迴呼叫
    } else {
       c[i] = p[i];
    }
  }
  return c;
}複製程式碼

當然,可以在專案中引入函式庫(如 utils.js)來方便的引用這些擴充套件函式,不過我們不得不想有沒有更簡潔的方式來實現呢?答案是肯定的。

// utils.js
export const extendCopy(p) {...}
export const deepCopy(p, c) {...}複製程式碼
// page.js
import {extendCopy, deepCopy} from utils.js
a = {...}
b = extendCopy(a)複製程式碼

一般還可以通過如下方式解決:

  • 通過 JSON 物件提供的 stringifyparse 方法組合使用的方式實現。
// 勉強也算一句話解決了,問題在於效能不理想。
var a = {}
var b = JSON.parse(JSON.stringify(a))複製程式碼
  • 通過在函式中以返回值的形式生成新物件。
// 這種方式的缺點在於要以字面量的形式定義一個原始物件作為模板。
a = function() { 
return { prop:"123" } 
}
b = a()
d = a()
b === d // false複製程式碼
  • 通過 ES2015 中提供的 Object.assign() 方法來複制。
// 簡潔明瞭,效能良好的解決方案
var a = {}
var b = Object.assign({},a)複製程式碼

通過上面的例子,我們不難得出一個結論:使用 Object.assign() 方法複製一個物件是比較理想的解決方案。

2. 如何判斷一個元素是否在集合中

早期的 Js 標準中並沒有實現類似 array.contains(item) 的方法,因此只能通過元素在集合中的索引判斷。(感謝 XiaozhongLiu 的提醒,ES7中已加入 Array.includes() 方法。)

// 傳統寫法
var isSelected = function(row) {
  return (selection || []).indexOf(row) > -1;
}

// ES7寫法,簡潔了許多
isSelected = selection.includes(row)複製程式碼

3. 判斷一個變數是否為非空物件

首先 null 的型別是物件,如果在控制檯輸入 typeof null 會返回 "object",事實上我們要檢測一個非空陣列,就要先排除 null 值的可能。

var isObject = function(obj) {
  return obj !== null && typeof obj === 'object'
}複製程式碼

4. 如何查詢一個陣列並返回元素的子集

這裡用到了陣列的 filter 方法,此方法具有以下特點:

  1. 需要傳入一個回撥函式作為引數,此函式應返回一個布林值。
  2. filter 執行時會對陣列中的每一個元素執行一遍回撥函式。
  3. filter 的返回值為一個新陣列,其成員為原陣列中返回值為 true 的元素。
var users = allUsers.filter((user) => user.loged === true)複製程式碼

5. 如何判斷一個物件沒有任何屬性

在 Js 中兩個空物件進行比較會有什麼結果呢?

var a = {}
a === {} // false複製程式碼

在 Js 中對 object 型別的資料應用 “等於” 操作符時,比較的是兩個變數是否指向同一個引用,也就是說在記憶體中是否為同一個地址。

而我們期待的結果是比較兩個物件在邏輯上是否具有相同的屬性,空物件是一個特例,它們不具有任何屬性。

if (Object.keys(search).length !== 0) {
    args = Object.assign({}, args, search)
}複製程式碼

這裡用到 Object.keys() 方法,獲取物件鍵的集合並判斷其長度是否為 0 即可。

6. 如何使用迴圈刪除陣列中的多個元素

for (let i = 0, let j = delIds.length - 1; i < j; i++) {
    allItems.splice(delIds[i], 0)
}複製程式碼

如上,根據索引來迴圈刪除原始陣列中的元素是否可行呢?如果我們執行這段程式碼是無法得到預期結果的。原因在於,當前面的元素被刪除時,後面元素的索引發生了變化,繼續用刪除前的索引就無法定位正確的元素,解決的方法有兩種:

  • 通過倒序迴圈,獲取被刪除元素的索引,從後向前遍歷刪除。
for (let i = delIds.length - 1; i > 0; i--) {
    allItems.splice(delIds[i], 0)
}複製程式碼
  • 通過陣列的兩個方法即 forEach 配合 indexOf 刪除,這種方法需要獲取被刪除元素本身,動態獲取它的索引。
delItems.forEach ((item) => {
    allItems.splice(allItems.indexOf(item), 0)
})複製程式碼

(未完待續...)

相關文章