使用JavaScript浅谈列表

什么是列表?

列表是一组有序的数据。每个列表中的数据项称为元素。在JavaScript中,列表中的元素可以是任意类型的数据。列表中可以保存多少元素没有确定,实际使用时元素的数量受到程序内存的限制。

现在我们来抽象一下列表的抽象数据类型定义

listSize(属性):列表中的元素个数

pos(属性):列表中的元素当前可访问的位置(位置指针)

length(方法):返回列表中元素的个数

clear(方法):清空列表中的所有元素

toString(方法):返回列表的字符串形式

getElement(方法):返回列表当前可访问位置对应的元素

insert(方法):在现有元素后面插入新元素

append(方法):在列表的末尾添加新元素

remove(方法):从列表中移除元素

front(方法):将列表的当前位置移动到第一个元素

end(方法):将列表的当前位置移动到最后一个元素

prev(方法):将列表的当前位置前移一位

next(方法):将列表的当前位置后移一位

hasNext(方法):判断列表在当前位置是否还有一下个元素

hasPrev(方法):判断列表在当前位置是否还有上一个元素

currPos(方法):返回列表的当前位置

moveTo(方法):将列表的当前位置移动到指定位置

上面抽象了列表的数据类型,包括要使用到的属性和方法,下面使用代码来实现一个列表类:

// 定义列表类
class List {
    constructor() {
        // 定义列表的元素个数
        this.listSize = 0;
        // 列表的位置指针
        this.pos = 0;
        // 列表的数据存储
        this.dataSource = [];
    }

    // append: 列表增加元素
    append(element) {
        this.dataSource[this.listSize++] = element;
    }

    // remove: 列表中删除元素
    remove(element) {
        var findAt = this.find(element);
        if (findAt > -1) {
            this.dataSource.splice(findAt, 1);
            --this.listSize;
            return true;
        }
        return false;
    }

    // find:辅助方法,用于查找要操作的元素
    find(element) {
        for (var i = 0; i < this.listSize; i++) {
            if (this.dataSource[i] === element) {
                return i;
            }
        }
        return -1;
    }

    // length:返回列表中的元素个数
    length() {
        return this.listSize;
    }

    // toString: 返回列表的字符串形式
    toString() {
        return this.dataSource.toString();
    }

    // insert: 向列表中添加一个元素
    insert(element, after) {
        var insertPos = this.find(after);
        if (insertPos > -1) {
            this.dataSource.splice(insertPos + 1, 0, element);
            ++this.listSize;
            return true;
        }
        return false;
    }

    // clear: 清空列表中的元素
    clear() {
        this.dataSource.length = 0;
        this.listSize = this.pos = 0;
    }

    // front:指针归零(移动到列表的第一个元素的位置)
    front() {
        this.pos = 0;
    }
    // end: 指针移动到列表的最后一个元素的位置
    end() {
        this.pos = this.listSize - 1;
    }
    // hasPrev: 判断指针是否可以向前移动
    hasPrev() {
        return this.pos > 0
    }
    // hasNext: 判断指针是否可以向后移动
    hasNext() {
        return this.pos < this.listSize - 1
    }
    // moveTo: 修改指针的位置
    moveTo(position) {
        if (0 <= position && position <= this.listSize - 1) {
            this.pos = position;
        }
    }
    // prev: 指针向前移动一位
    prev() {
        if (this.hasPrev()) {
            --this.pos;
        }
    }
    // next: 指针向后移动一位
    next() {
        if (this.hasNext()) {
            ++this.pos;
        }
    }
    // getElement: 获取列表中指针所对应的元素
    getElement() {
        return this.dataSource[this.pos];
    }
    // currPos: 返回当前指针位置
    currPos() {
        return this.pos;
    }
}

其中next,prev,moveTo,front,end是我们设置的一些迭代器,使用迭代器有如下好处:

1. 访问列表元素的时候,我们不必关心底层的数据存储结构。

2.当对列表进行删除或增加操作的时候,存储列表元素的数组的索引值就更新了,此时只用更新列表,不需要更新迭代器。

3.可以用不同类型的数据存储方式来实现List类,迭代器为访问列表中的元素提供了一种统一的方式。

这样子我们就是实现了上面抽象的列表数据结构,接下来我们用它在做些什么。

创建一个Person 类,该类用于保存人的姓名和性别信息。创建一个至少包含10个Person对象的列表。编写一个函数显示列表中所有拥有相同性别的人。

分析如下,我们之前创建的列表类里面只适合操作基本数据类型,现在列表中的元素很明显是引用类型,所以我们想到的编写一个新的列表类,它拥有List类的所有方法,同时对有些方法实现覆盖,还要增加一些新的方法,以达到自己的需求。(之前定义的List类只是一个基本的模型而已,方便在实际应用中提供基础方法,自己实现相关的扩展)

代码如下:

// 定义列表类
class List {
    constructor() {
        // 定义列表的元素个数
        this.listSize = 0;
        // 列表的位置指针
        this.pos = 0;
        // 列表的数据存储
        this.dataSource = [];
    }

    // append: 列表增加元素
    append(element) {
        this.dataSource[this.listSize++] = element;
    }

    // remove: 列表中删除元素
    remove(element) {
        var findAt = this.find(element);
        if (findAt > -1) {
            this.dataSource.splice(findAt, 1);
            --this.listSize;
            return true;
        }
        return false;
    }

    // find:辅助方法,用于查找要操作的元素
    find(element) {
        for (var i = 0; i < this.listSize; i++) {
            if (this.dataSource[i] === element) {
                return i;
            }
        }
        return -1;
    }

    // length:返回列表中的元素个数
    length() {
        return this.listSize;
    }

    // toString: 返回列表的字符串形式
    toString() {
        return this.dataSource.toString();
    }

    // insert: 向列表中添加一个元素
    insert(element, after) {
        var insertPos = this.find(after);
        if (insertPos > -1) {
            this.dataSource.splice(insertPos + 1, 0, element);
            ++this.listSize;
            return true;
        }
        return false;
    }

    // clear: 清空列表中的元素
    clear() {
        this.dataSource.length = 0;
        this.listSize = this.pos = 0;
    }

    // front:指针归零(移动到列表的第一个元素的位置)
    front() {
        this.pos = 0;
    }
    // end: 指针移动到列表的最后一个元素的位置
    end() {
        this.pos = this.listSize - 1;
    }
    // hasPrev: 判断指针是否可以向前移动
    hasPrev() {
        return this.pos > 0
    }
    // hasNext: 判断指针是否可以向后移动
    hasNext() {
        return this.pos < this.listSize - 1
    }
    // moveTo: 修改指针的位置
    moveTo(position) {
        if (0 <= position && position <= this.listSize - 1) {
            this.pos = position;
        }
    }
    // prev: 指针向前移动一位
    prev() {
        if (this.hasPrev()) {
            --this.pos;
        }
    }
    // next: 指针向后移动一位
    next() {
        if (this.hasNext()) {
            ++this.pos;
        }
    }
    // getElement: 获取列表中指针所对应的元素
    getElement() {
        return this.dataSource[this.pos];
    }
    // currPos: 返回当前指针位置
    currPos() {
        return this.pos;
    }
}

// 创建Person类
class Person {
    constructor(name, sex) {
        this.name = name;
        this.sex = sex;
    }
}


class PersonList extends List {
    // 重写getElement方法
    getElement() {
        return this.dataSource[this.pos].name;
    }
    // 返回指定性别人员集合
    displayNames(sex){
        return this.dataSource.filter(person=>person.sex === sex);
    }
};

// 列表装载
const personList = new PersonList();
for (let i = 0; i < 10; i++) {
    personList.append(new Person('a' + i, Math.random() > 0.5 ? '男' : '女'));
}

console.log(personList.getElement()); // a0
personList.end();
console.log(personList.getElement());// a9

console.log(personList);
console.log('personList列表中性别为男的人员组合为',personList.displayNames('男'));

这样子我们就实现了需求,你可能会说需要这么麻烦,创建一个函数统计一下指定性别的人员就行了,为什么还要这些操作。其实在这里我们练习的是列表的使用,在这里只是举一个列子,其中滋味,自己体会。

有了之前的List类,我们处理一些相关的问题,通过简单的继承,就会变得相当简单。

我觉得学习新的知识之后,一定要用到实际开发中去,不然你学与不学有什么区别了,无非是浪费了一些时间来安慰自己罢了。

源码和案例地址:https://gitee.com/mvc_ydb/data-structure/blob/master/list.js

原文地址:https://www.cnblogs.com/jsydb/p/12491840.html