javascript数组集合的操作扩展

原创
2017/03/31 12:01
阅读数 211

javascript的数组功能非常好用。尤其是在目前前端MVVM的大潮流下前端使用Array+JSON的场景非常频繁,对数组的操作要求越来越多。添加,删除,交换,集合取交集,并集,差集等。直接使用原生API,比较麻烦。这里对Array使用prototype进行扩展。

主要代码如下:

/**
 * 对象常见操作工具类
 */
var objectkit = {
    isJSON: function(obj) {
        var isjson = typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length;
        return isjson;
    },
    deepClone: function(obj) {
        return JSON.parse(JSON.stringify(obj));
    },
    equals: function(v1, v2) {
        if (typeof(v1) === "object" && objectkit.isJSON(v1) && typeof(v2) === "object" && objectkit.isJSON(v2)) {
            return JSON.stringify(v1) == JSON.stringify(v2);
        } else {
            return v1 == v2;
        }

    }
};

/**
 * 数组API扩展
 */
Array.prototype.indexOf = function(arg, n) {
    var i = isNaN(n) || n < 0 ? 0 : n;
    for (; i < this.length; i++) {
        if (this[i] == arg) {
            return i;
        } else if (typeof(this[i]) === "object" && objectkit.equals(this[i], arg)) {
            return i;
        }
    }
    return -1;
};
Array.prototype.each = function(fn) {
    fn = fn || Function.K;
    var a = [];
    var args = Array.prototype.slice.call(arguments, 1);
    for (var i = 0; i < this.length; i++) {
        var res = fn.apply(this, [this[i], i].concat(args));
        if (res != null) a.push(res);
    }
    return a;
};
Array.prototype.contains = function(obj) {
    return this.indexOf(obj) >= 0;
};
Array.prototype.clear = function() {
    this.length = 0;
    return this;
};
Array.prototype.append = function(obj) {
    this.push(obj);
    return this;
};
Array.prototype.insertAt = function(index, obj) {
    this.splice(index, 0, obj);
    return this;
};
Array.prototype.removeAt = function(index) {
    this.splice(index, 1);
    return this;
};
Array.prototype.remove = function(obj) {
    if (obj instanceof Array) {
        for (var i = 0; i < obj.length; i++) {
            this.remove(obj[i]);
        }
    }
    var index = this.indexOf(obj);
    if (index >= 0) {
        this.removeAt(index);
    }
    return this;
};
Array.prototype.size = function() {
    return this.length;
};
Array.prototype.clone = function() {
    var cloneList = Array();
    for (var i = 0, a = 0; i < this.length; i++) {
        cloneList.push(this[i]);
    }
    return cloneList;
};

Array.prototype.clone = function() {
    var arr = [];
    for (var i = 0; i < this.length; i++) {
        if (typeof(this[i]) !== 'object') {
            arr.push(this[i]);
        } else if (objectkit.isJSON(this[i])) {
            arr.push(objectkit.deepClone(this[i]));
        } else if (typeof(this[i].clone) === "function") {
            arr.push(this[i].clone());
        }
    }
    return arr;
};

/* variable number of arrays */
Array.prototype.merge = function() {
    for (var i = 0; i < arguments.length; i++) {
        var array = arguments[i];
        if (array instanceof Array) {
            for (var j = 0; j < array.length; j++) {
                if (this.indexOf(array[j]) === -1) {
                    this.push(array[j]);
                }
            }
        } else {
            this.push(array);
        }
    }
    return this;
};
Array.prototype.swap = function(i, j) {
    var temp = this[i];
    this[i] = this[j];
    this[j] = temp;
    return this;
};
/**  
 * 得到一个数组不重复的元素集合<br/>  
 * 唯一化一个数组  
 * @returns {Array} 由不重复元素构成的数组  
 */
Array.prototype.uniquelize = function() {
    var copy = this.clone();
    this.clear();
    for (var i = 0; i < copy.length; i++) {
        if (!this.contains(copy[i])) {
            this.push(copy[i]);
        }
    }
    return this;
};
/**
 * 两个集合的差集
 */
Array.prototype.minus = function(b) {
    var copy = this.clone();
    this.clear();
    var r = copy.uniquelize().each(function(o) { return b.contains(o) ? null : o });
    return this.concat(r);
};

/**
 * 求两个集合的并集
 */
Array.prototype.union = function(b) {
    var copy = this.clone();
    this.clear();
    var r = copy.concat(b).uniquelize();;
    return this.concat(r);
};

/**
 * 两个集合的交集  
 */
Array.prototype.intersect = function(b) {
    // return a.uniquelize().each(function(o) { return b.contains(o) ? o : null });

    var copy = this.clone();
    this.clear();
    var r = copy.uniquelize().each(function(o) { return b.contains(o) ? o : null });
    return this.concat(r);
};

最终运行效果如下

GIT地址: https://git.oschina.net/teamsir/js-array-extend-demo.git

 

代码解释:

objectkit 该对象是对Object类操作的一些扩展。曾经想过直接使用Object.prototype进行扩展,后来验证得到,这样做非常不安全。Object是所有类的基础类,直接加到Object上,会出现问题,目前发现和jQuery就会出现冲突。

为什么不要直接在Object.prototype上定义方法:https://www.zhihu.com/question/26924011

该工具类,目前有三个函数:

isJSON:判断是否是JSON对象

    isJSON: function(obj) {
        var isjson = typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length;
        return isjson;
    }

deepClone:JSON对象深拷贝,对象转json字串,然后再转回对象(好暴力的做法)

deepClone: function(obj) {
        return JSON.parse(JSON.stringify(obj));
    }

equals:判断两个对象是否相等,包含一般数据和JSON对象。(如果是json对象,直接转成json字串进行比较)

    equals: function(v1, v2) {
        if (typeof(v1) === "object" && objectkit.isJSON(v1) && typeof(v2) === "object" && objectkit.isJSON(v2)) {
            return JSON.stringify(v1) == JSON.stringify(v2);
        } else {
            return v1 == v2;
        }
    }

 

PS:

我这个前端展示页面使用VUE2.0做的一个简单案例(如果老老实实写table,太累了,我喜欢偷懒),如果你了解vue可以阅读下,不了解,也不影响本文的主题。

index.html代码如下:

<!doctype html>
<html>

<head>
    <title>数组扩展功能展示</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link href="./static/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
    <script src="./static/jquery/1.12.4/jquery.min.js" type="text/javascript"></script>
    <script src="./static/bootstrap/3.3.7/js/bootstrap.min.js" type="text/javascript"></script>
    <script src="./static/vue/2.2.2/vue.min.js" type="text/javascript"></script>
    <script src="./static/lang/array.js" type="text/javascript"></script>
</head>

<body>
    <div id="app">
        <table id="" class="table table-bordered table-hover">
            <caption>数组扩展功能展示</caption>
            <thead>
                <tr>
                    <th>名称</th>
                    <th>表达式</th>
                    <th>结果</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for="(row,index) in rows">
                    <td>{{row.name}}</td>
                    <td><code>{{row.expr | json}}</code></td>
                    <td><code>{{parseExpression(index)}}</code><small>{{row.remark}}</small></td>
                </tr>
            </tbody>
        </table>
    </div>

</body>

</html>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: function() {
            return {
                rows: [{
                    name: '查找-位置',
                    expr: '[0,1,2,3,5].indexOf(5)'
                }, {
                    name: '添加-后追加',
                    expr: '[0,1,2,3].append(4)'
                }, {
                    name: '添加-PUSH(闭包)',
                    expr: '(function(){var v=[0,1,2,3];v.push(4);return v;})()'
                }, {
                    name: '添加-PUSH',
                    expr: '[0,1,2,3].push(4)',
                    remark: '返回总长度'
                }, {
                    name: '插入',
                    expr: '[0,1,2,3].insertAt(1,4)'
                }, {
                    name: '删除',
                    expr: '[0,1,2,3].removeAt(1)'
                }, {
                    name: '删除',
                    expr: '[0,1,2,3].remove([1,2])'
                }, {
                    name: '删除-对象',
                    expr: '[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21}].remove({n:"钱二",v:24})'
                }, {
                    name: '删除-对象',
                    expr: '(function(){var v=[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21}];v.remove(v[1]);return v;})()'
                }, {
                    name: '合并-简单对象',
                    expr: '[0,1,2,3].merge(4)'
                }, {
                    name: '合并-简单对象-去除重复',
                    expr: '[0,1,2,3].merge([3,4,5])'
                }, {
                    name: '合并-简单对象-不去重',
                    expr: '[0,1,2,3].concat([3,4,5])'
                }, {
                    name: '合并-复杂对象',
                    expr: '[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21}].merge({n:"李四",v:22})'
                }, {
                    name: '交换对象',
                    expr: '[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21}].swap(0,2)'
                }, {
                    name: '去重-简单数据',
                    expr: '[0,1,2,3,2,3,5].uniquelize()'
                }, {
                    name: '集合-差集',
                    expr: '[1,2,3,4].minus([3,4,5,6])'
                }, {
                    name: '集合-并集',
                    expr: '[1,2,3,4].union([3,4,5,6])'
                }, {
                    name: '集合-交集',
                    expr: '[1,2,3,4].intersect([3,4,5,6])'
                }, {
                    name: '复杂对象-去重',
                    expr: '[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21},{n:"赵一",v:18}].uniquelize()'
                }, {
                    name: '复杂对象-差集',
                    expr: '[{n:"赵一",v:18},{n:"钱二",v:24},{n:"孙三",v:21},{n:"赵一",v:18}].minus([{n:"孙三",v:21},{n:"赵一",v:18}])'
                }]
            };
        },
        created: function() {

        },
        mounted: function() {

        },
        methods: {
            parseExpression: function(i) {
                var vm = this;
                var expr = vm.rows[i].expr;
                // console.log(expr);
                try {
                    return eval(expr);
                } catch (e) {
                    // console.log(1, e);
                    console.error(e);
                }
            }
        }
    });
</script>

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部