这篇文章主要介绍了 JavaScript 对象数组如何按指定属性和排序方向进行排序的相关资料, 非常不错,具有参考借鉴价值,需要的朋友可以参考下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
引子
在以数据为中心的信息系统中,以表格形式展示数据是在常见不过的方式了。对数据进行排序是必不可少的功能。排序可以分为按单个字段排序和按多个字段不同排序方向排序。单字段排序局限性较大,不能满足用户对数据的关注点变化的需求,而多字段排序就可以较好的弥补这个缺陷。
多字段排序,实现的方式从大的层面上可以分为后端实现和前端实现。
后端排序
后端实现排序可以在数据库层面实现或者在应用程序层面实现。
数据库层面实现多字段排序非常简单,使用 SQL 的排序指令 "Order By" 即可——Order By field1 asc, field2 desc, field3 asc -- ...。
应用程序层面是指 web 应用层(这里不讨论 C/S 架构),比如 PHP、Java Web、ASP.NET 等。应用程序层面实现就是使用 PHP、Java、.NET(C#/VB)这些后端服务语言来实现对数据的排序。以 ASP.NET C# 为例,因为 C# 中的 LINQ 内置了对集合类型的诸多操作,并且支持多属性排序,所以使用 LINQ 能够很方便的实现此目的——from f in foos orderby f.Name descending, f.Num ascending select f(可以发现 LINQ 的排序语法几乎与 SQL 的一模一样)。如果其它语言没有内置类似的支持,则按照排序算法来实现,这是通用的,与编程语言无关。
前端排序
在 JavaScript 中,数组有一个排序方法 "sort",当数组是一个简单数组(数组元素是简单类型——字符串、数值和布尔)时,使用该方法可以很方便的到达排序目的。但是当数组元素是非简单类型,比如名 / 值对的 Object,并且想要按照指定的某几个属性按不同的排序方向进行排序时,简单的调用 "sort" 方法就不能实现此目的了。
不过好在 "sort" 方法预留了自定义排序的接口,可以实现想要的排序方式。
来看看数组的 "sort" 方法是怎样的。
sort 函数原型
- // 对数组的元素做原地的排序,并返回这个数组。
- // 默认按照字符串的Unicode码位点(code point)排序。
- Array.prototype.sort([compareFunction]:number); // number:-1 | 0 | 1。
- // 典型的比较函数(升序排序)。
- function compareFunction(item1, item2) {
- if(item1 > item2) {
- return 1; // 如果是降序排序,返回-1。
- }else if(item1 === item2) {
- return 0;
- }else {
- return -1; // 如果是降序排序,返回1。
- }
- }
说明:如果没有指明 compareFunction,那么元素会被转换为字符串的诸个字符并按照 Unicode 位点顺序排序。例如,"Cherry" 会被排列到 "banana" 之前。当对数字进行排序的时候, 9 会出现在 80 之前,因为他们会先被转换为字符串,而 "80" 比 "9" 要靠前。
• 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
• 如果 compareFunction(a, b) 等于 0 ,a 和 b
的相对位置不变。备注:ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003
年之前的版本);
• 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
•compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
注:以上规则得出的排序结果是升序的,如果想要得到降序的结果,则在比较结果大于 0 时返回小于 0 的结果,比较结果小于 0 时 返回大于 0 的结果即可。
要实现多属性排序,关键就在于比较函数的实现。根据以上规则, 实现多属性不同方向排序,依然要返回两个比较项的大小关系。
那么多属性对象的大小关系如何确定呢?这个可以分两步走。
第一步,记录下两个排序项按照各个排序属性及方向进行比较得到的结果。
- var propOrders = {
- "prop1": "asc",
- "prop2": "desc",
- "prop3": "asc"
- };
- function cmp(item1, item2, propOrders) {
- var cps = []; // 用于记录各个排序属性的比较结果,-1 | 0 | 1 。
- var isAsc = true; // 排序方向。
- for (var p in propOrders) {
- isAsc = propOrders[p] === "asc";
- if (item1[p] > item2[p]) {
- cps.push(isAsc ? 1 : -1);
- break; // 可以跳出循环了,因为这里就已经知道 item1 "大于" item2 了。
- } else if (item1[p] === item2[p]) {
- cps.push(0);
- } else {
- cps.push(isAsc ? -1 : 1);
- break; // 可以跳出循环,item1 "小于" item2。
- }
- }
- /*
- .
- .
- .
- */
- }
第二步,根据各排序属性比较结果综合判断得出两个比较项的最终大小关系。
- /*
- .
- .
- .
- */
- for(var j = 0; j < cps.length; j++) {
- if(cps[j] === 1 || cps[j] === -1) {
- return cps[j];
- }
- }
- return 0;
有了上述思路后,实现整个比较函数就容易了,下面是比较函数的完整 JavaScript 代码:
比较函数
- function SortByProps(item1, item2) {
- "use strict";
- var props = [];
- for (var _i = 2; _i < arguments.length; _i++) {
- props[_i - 2] = arguments[_i];
- }
- var cps = []; // 存储排序属性比较结果。
- // 如果未指定排序属性,则按照全属性升序排序。
- var asc = true;
- if (props.length < 1) {
- for (var p in item1) {
- if (item1[p] > item2[p]) {
- cps.push(1);
- break; // 大于时跳出循环。
- } else if (item1[p] === item2[p]) {
- cps.push(0);
- } else {
- cps.push(-1);
- break; // 小于时跳出循环。
- }
- }
- } else {
- for (var i = 0; i < props.length; i++) {
- var prop = props[i];
- for (var o in prop) {
- asc = prop[o] === "asc";
- if (item1[o] > item2[o]) {
- cps.push(asc ? 1 : -1);
- break; // 大于时跳出循环。
- } else if (item1[o] === item2[o]) {
- cps.push(0);
- } else {
- cps.push(asc ? -1 : 1);
- break; // 小于时跳出循环。
- }
- }
- }
- }
- for (var j = 0; j < cps.length; j++) {
- if (cps[j] === 1 || cps[j] === -1) {
- return cps[j];
- }
- }
- return 0;
- }
测试用例
- // -------------测试用例------------------------------
- var items = [{
- name: 'Edward',
- value: 21
- },
- {
- name: 'Sharpe',
- value: 37
- },
- {
- name: 'And',
- value: 45
- },
- {
- name: 'Edward',
- value: -12
- },
- {
- name: 'Magnetic',
- value: 21
- },
- {
- name: 'Zeros',
- value: 37
- }];
- function test(propOrders) {
- items.sort(function(a, b) {
- return SortByProps(a, b, propOrders);
- });
- console.log(items);
- }
- function testAsc() {
- test({
- "name": "asc",
- "value": "asc"
- });
- }
- function testDesc() {
- test({
- "name": "desc",
- "value": "desc"
- });
- }
- function testAscDesc() {
- test({
- "name": "asc",
- "value": "desc"
- });
- }
- function testDescAsc() {
- test({
- "name": "desc",
- "value": "asc"
- });
- }
- TypeScript代码
- /**
- ** 排序方向。
- */
- type Direct = "asc" | "desc";
- /**
- ** 排序属性。
- **
- ** @interface IPropertyOrder
- */
- interface IPropertyOrder { [name: string] : Direct;
- }
- /**
- ** 简单名/值对象。
- **
- ** @interface ISimpleObject
- */
- interface ISimpleObject { [name: string] : string | number | boolean;
- }
- /**
- ** 对简单的名/值对象按照指定属性和排序方向进行排序(根据排序属性及排序方向,
- ** 对两个项依次进行比较,并返回代表排序位置的值)。
- **
- ** @template T 简单的名/值对象。
- ** @param {T} item1 排序比较项1。
- ** @param {T} item2 排序比较项2。
- ** @param {...IPropertyOrder[]} props 排序属性。
- ** @returns 若项1大于项2返回1,若项1等于项2返回0,否则返回-1。
- */
- function SortByProps < T extends ISimpleObject > (item1: T, item2: T, ...props: IPropertyOrder[]) {
- "use strict";
- var cps: Array < number > =[]; // 存储排序属性比较结果。
- // 如果未指定排序属性,则按照全属性升序排序。
- var asc = true;
- if (props.length < 1) {
- for (var p in item1) {
- if (item1[p] > item2[p]) {
- cps.push(1);
- break; // 大于时跳出循环。
- } else if (item1[p] === item2[p]) {
- cps.push(0);
- } else {
- cps.push( - 1);
- break; // 小于时跳出循环。
- }
- }
- } else { // 按照指定属性及升降方向进行排序。
- for (var i = 0; i < props.length; i++) {
- var prop = props[i];
- for (var o in prop) {
- asc = prop[o] === "asc";
- if (item1[o] > item2[o]) {
- cps.push(asc ? 1 : -1);
- break; // 大于时跳出循环。
- } else if (item1[o] === item2[o]) {
- cps.push(0);
- } else {
- cps.push(asc ? -1 : 1);
- break; // 小于时跳出循环。
- }
- }
- }
- }
- for (var j = 0; j < cps.length; j++) {
- if (cps[j] === 1 || cps[j] === -1) {
- return cps[j];
- }
- }
- return 0;
- }
使用场景及局限性
在前端使用 JavaScript 实现多属性排序,减少了对服务器端的请求,减轻服务器端的计算压力,但是也仅适用于只需要对本地数据进行排序的情形。如果需要对整个数据集进行多属性排序,最终还是要在服务器端的数据库层面上进行。
以上所述是小编给大家介绍的 JavaScript 对象数组如何按指定属性和排序方向进行排序的全部叙述,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 phperz 网站的支持!
来源: http://www.phperz.com/article/17/0311/264854.html