3

In the previous article, we introduced in detail the sparse array , and in actual projects, how the sparse array can exert its maximum effect in the front-end spreadsheet. And this time, we will start from the actual application and introduce the specific application of sparse array in the front end.

We all know that in Javascript, the sparse matrix is constructed through the Array() constructor, or through the array, the sparse matrix is created by setting the index length of the array to be greater than the length of the current array.

var arr = new Array(100)   //arr没有元素,但arr.length是100
var a = [];  //创建一个空数组,length为0
a[50] = 50;  //赋值添加一个元素,length为 51
 

In a sparse array, nodes without elements are empty, and obtaining these nodes will return the result undefined. You can determine whether a node has elements by using index in array. For example, in the following code, both a[0] and a[1] return undefined, but a[1] is actually empty.

JS already supports the storage of sparse arrays, but in actual situations, we do not save sparse arrays directly. Instead, we will construct other storage methods to save sparse arrays according to the actual situation. If you want to understand why you want to do this, you need to understand a concept-data persistence.

When we perform many operations on the front-end, a lot of data will be generated. For example, when multiple people fill in and collaborate on the front-end form, there will be a lot of data that needs to be stored for a long time. Some data needs to be transferred to other locations for people to store, manage, and Operation etc. The key to achieving this goal is the persistence of data. We need to serialize the data in memory into storage formats such as json and save it to the database and deserialize it to memory. The previous article detailed the json data in the spreadsheet: serialization and deserialization has been introduced in detail, and you can check it if you are interested.

Seeing this, do you think the problem is completely solved? The drawing is broken.

In order to solve data persistence, we use JSON, but at this time new problems also arise, there is no undefined in JSON storage. When we operate on the array, the empty fields in the array will be serialized to null, as shown in the figure below.

JSON.stringify(a)
'[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,50]'

After parse again, the array is no longer a sparse array.

JSON.parse(JSON.stringify(a))
(51) [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 50]

In this case, in order to solve the above-mentioned situation in the conversion process of JSON data, we need to build some other storage methods to better solve this problem~ And what are the characteristics of these storage methods, let us take a look together .

1. Object storage

Using the language features of JS at the front end, we can easily implement Sparse Array through Object. For example, in Spread JS, the object attribute name corresponds to the row and column of the cell where it is located, and the value attribute stores the value of the cell. It can also be extended to store formula and style of the cell with attributes such as formula and style. When using Sparse Array, you don't need to initialize the size or care about the expansion of the data. You only need to change the reference of the row and column attributes when you need to do row and column operations.

The data storage results in the above figure are as follows

{
    "0": {
        "0": {
            "value": 0
        }
    },
    "2": {
        "1": {
            "value": 2
        },
        "3": {
            "value": "S"
        }
    },
    "4": {
        "3": {
            "value": 3
        }
    }
}
 

When you need to access data, you can access it directly through object properties. The following is a simple object implementation of JS Sparse Array.


function SparseArray(){
    this._array = {}
}
SparseArray.prototype.setValue = function(row, col, data){
    if(!this._array[row]){
        this._array[row] = {}
    }
    this._array[row][col] = data
}
SparseArray.prototype.getValue = function(row, col){
    if(this._array[row]){
        return this._array[row][col]
    }
    return undefined;
}
let arr = new SparseArray();
arr.setValue(3, 3, 5);
console.log(arr.getValue(3, 3))    // 5

2. Triples

Each element in the matrix has three pieces of information: row label, column label, and element value. Putting the elements into the array as needed is triple storage. The storage structure can be an object containing element information, or it can be directly simplified into an array of length 3. The storage mode of triples can conveniently record trajectory information or free curve information similar to the following figure. By pushing and popping the array, it is convenient to go back and forward.

The trajectory information in the above figure is stored as an array triple as follows, the element value represents the current number of elements, and more information such as object recording time can also be used.

[
    [1,1,1],
    [5,8,2],
    [4,3,3], 
    [1,5,4]
]

Next, we will use this method to create an undoStack record rollback.

function TSMatrix(){
this._array = [];
this.undoStack = []
}

 
TSMatrix.prototype.addNode = function(row, col, value){
this._array.push([row, col, value])
}
TSMatrix.prototype.canUndo = function(){
return this._array.length > 0;
}
TSMatrix.prototype.undo = function(){
if(this._array.length > 0){
this.undoStack.push(this._array.pop())
}
}
TSMatrix.prototype.canRedo = function(){
return this.undoStack.length > 0;
}
TSMatrix.prototype.redo = function(){
if(this._array.length > 0){
this._array.push(this.undoStack.pop())
}
}
TSMatrix.prototype.print = function(){
console.log(JSON.stringify(this._array))
}

let mat = new TSMatrix();
mat.addNode(1, 1, 1)
mat.addNode(5, 8, 2)
mat.addNode(4, 3, 3)
mat.addNode(1, 5, 4)
mat.print() //[[1,1,1],[5,8,2],[4,3,3],[1,5,4]]
mat.undo()
mat.print()  //[[1,1,1],[5,8,2],[4,3,3]]
mat.redo()
mat.print()  //[[1,1,1],[5,8,2],[4,3,3],[1,5,4]]

In addition to the above two methods, you can also combine the above methods to create a cross-linked list to deal with more complex scenarios. If you are interested, please give us a thumbs up and we will continue to talk about it next time.

In the follow-up content, we will continue to bring you the in-depth decryption in other front-end spreadsheet technologies, so don't miss it when you pass by.


葡萄城技术团队
2.7k 声望29.3k 粉丝

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务,一站式满足开发者需求,帮助企业提升开发效率并创新开发模式。