首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Javascript对象排序数组使用显式声明,使用变量时中断

Javascript对象排序数组使用显式声明,使用变量时中断
EN

Stack Overflow用户
提问于 2018-02-15 11:30:10
回答 4查看 122关注 0票数 2

我正在使用一个返回JSON数据的应用程序接口,我想按时间顺序对数据进行排序--按对象的releaseDate (整数)属性排序。

数据示例:

代码语言:javascript
复制
let all_albums = [
  {
    "releaseDate": 1461913200000,
    "critic_rating": 69,
    "user_rating": 57,
    "average_rating": 63
  },
  {
    "releaseDate": 1380006000000,
    "critic_rating": 79,
    "user_rating": 75,
    "average_rating": 77
  },
  {
    "releaseDate": 1321344000000,
    "critic_rating": 78,
    "user_rating": 79,
    "average_rating": 78.5
  },
]

如果我将其复制/粘贴到项目之外的单独文件中,则可以使用以下命令对其进行排序:

代码语言:javascript
复制
 let sortedAlbums = all_albums.sort(function (a, b) {
    return a.releaseDate - b.releaseDate;
});

但是,如果我尝试将其实现到我的项目中,我可以用同样的方式遍历JSON,以同样的方式打印到控制台,所有的数据都与我上面演示的完全相同--但是我不能对这个数据集进行排序。

我来自python背景,所以异步的世界对我来说是新的。这有关系吗?或者,如何对刚从API调用的对象进行排序?

感谢大家到目前为止的评论。我重构了一些变量,根据你的建议清理了代码。尽管如此,当直接从API调用时,问题仍然存在。下面是示例调用的完整代码(尽管带有被审查的mashape键)

代码语言:javascript
复制
$(function () {
    return $.ajax({
        url: 'https://api-marcalencc-metacritic-v1.p.mashape.com/person/drake/album',
        type: 'get',
        dataType: 'json',
        headers: {
            "X-Mashape-Key": "----------------------------",
            "Accept": "application/json"
        },
        success: function (data) {
            handleDiscography(data);
        },
    })
});

const allAlbums = [];

function Album(releaseDate) {
    this.releaseDate = new Date(releaseDate).getTime();
}

function addAlbum(releaseDate) {
    const a = new Album(releaseDate);
    allAlbums.push(a);
}

function handleDiscography(data) {
    const album = data[0].CreditMediaPairItems;
    $.each(album, function (key, val) {
        const releaseDate = val.Item.ReleaseDate;
        addAlbum(releaseDate);
    });
    return data
}

const sortedAlbums = allAlbums.sort((a, b) => a.releaseDate - b.releaseDate);
console.log(sortedAlbums);
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-02-15 14:01:23

这个问题实际上是一个异步问题。

ajax请求的success回调中的代码在以下代码之后执行:

代码语言:javascript
复制
const sortedAlbums = allAlbums.sort((a, b) => a.releaseDate - b.releaseDate);
console.log(sortedAlbums);

Array.prototype.sort对数组中的元素进行原地排序并返回该数组。因此,在调用sort之后,sortedAlbumsallAlbums都引用相同的数组。

因为当时没有请求任何数据,所以在空数组上调用sort,并且不对任何内容进行排序。

下一个问题是,console.log(sortedAlbums);不会显示sortedAlbums在被记录时的内容,而是在开发人员工具中第一次检查它时的内容。因此,当您查看它时,请求已经完成,并且现在引用与sortedAlbums相同的对象的allAlbums已经被填充。但这是在您对空数组进行排序之后发生的。

最简单的方法是将排序和日志放在success回调中:

代码语言:javascript
复制
$.ajax({
  url: 'https://api-marcalencc-metacritic-v1.p.mashape.com/person/drake/album',
  type: 'get',
  dataType: 'json',
  headers: {
    "X-Mashape-Key": "----------------------------",
    "Accept": "application/json"
  },
  success: function(data) {
    handleDiscography(data);
    allAlbums.sort((a, b) => a.releaseDate - b.releaseDate);
    console.log(allAlbums);
  }
})

一个更干净的解决方案看起来像这样:

代码语言:javascript
复制
function Album(releaseDate) {
  this.releaseDate = new Date(releaseDate).getTime();
}


function handleDiscography(data) {
  const album = data[0].CreditMediaPairItems;
  return album.map(val => new Album(val.Item.ReleaseDate))
}

function getAlbumData() {
  return $.ajax({
      url: 'https://api-marcalencc-metacritic-v1.p.mashape.com/person/drake/album',
      type: 'get',
      dataType: 'json',
      headers: {
        "X-Mashape-Key": "----------------------------",
        "Accept": "application/json"
      }
    })
    .then(data => handleDiscography)
}


getAlbumData()
  .then(allAlbums => {
    allAlbums.sort(function(a, b) {
      return a.releaseDate - b.releaseDate;
    });

    console.log(allAlbums)
  })

在本例中,您完全摆脱了全局对象,这是应该始终避免的,特别是在使用异步代码时。

票数 1
EN

Stack Overflow用户

发布于 2018-02-15 11:38:51

我稍微清理了一下你的示例代码,但在功能上是一样的。它排序很好。

代码语言:javascript
复制
const allAlbums = [
  {
    'releaseDate': 1461913200000,
    'critic_rating': 69,
    'user_rating': 57,
    'average_rating': 63
  },
  {
    'releaseDate': 1380006000000,
    'critic_rating': 79,
    'user_rating': 75,
    'average_rating': 77
  },
  {
    'releaseDate': 1321344000000,
    'critic_rating': 78,
    'user_rating': 79,
    'average_rating': 78.5
  },
];

const sortedAlbums = allAlbums.sort((a, b) => a.releaseDate - b.releaseDate);
console.log(sortedAlbums);

输出:

代码语言:javascript
复制
[
  {
    "releaseDate": 1321344000000,
    "critic_rating": 78,
    "user_rating": 79,
    "average_rating": 78.5
  },
  {
    "releaseDate": 1380006000000,
    "critic_rating": 79,
    "user_rating": 75,
    "average_rating": 77
  },
  {
    "releaseDate": 1461913200000,
    "critic_rating": 69,
    "user_rating": 57,
    "average_rating": 63
  }
]

这里有一些样式技巧,因为您是Python程序员。虽然没有官方的标准风格指南,但有一些一般性的建议。

使用单引号。仅限camelCase。两个空格,而不是制表符。

在处理数组和对象文字时,您几乎总是希望使用const。仅当您将相同的命名变量重新赋值为不同的值时,才需要letvar。在处理数组和对象时,您可以自由地修改它们的属性,因为您不需要重新分配变量。

在声明函数时,90%的时间胖箭头语法将有助于防止处理this的错误。另外10%的时间是胖箭头导致错误的时候。

票数 4
EN

Stack Overflow用户

发布于 2018-02-15 13:51:27

下面是你的代码应该是什么样子,加上一些注释。看起来您正在尝试使用一个全局变量allAlbums,该变量是在带有异步结果的文档就绪事件中设置的。

但是您正在尝试在文档就绪事件处理程序之外使用该变量,因此现在访问它还为时过早,因为甚至没有尝试加载数据,而且即使加载数据是异步的,您也不能为其设置值,因为该值在将来可用(或者如果失败,则根本不能)。

您只能在document ready中访问allAlbums,并将其设置为promise值,以便知道实际值何时可用。

如果allAlbums与其他代码共享,那么不要仅仅对它进行排序,因为排序会改变它,也许当您在其他地方使用它时,您不希望它以某种方式排序。如果您确实希望对其进行排序,请在.sort之前删除.map(x=>x)

代码语言:javascript
复制
//All albums is the result of asynchronous action so better store it
//  as a result of asynchronous action (promise)
var allAlbums = $.Deferred().resolve([]);
function Album(releaseDate) {
  this.releaseDate = new Date(releaseDate).getTime();
}
const logSorted = (message,albums) =>
  albums.then(
    albums => albums.map(x=>x).sort((a, b) => a.releaseDate - b.releaseDate)
  ).then(
    sortedAlbums=>console.log(message,sortedAlbums)
  );
$(function () {
  //set allAlbums to a promise
  allAlbums = $.ajax({
    url: 'https://api-marcalencc-metacritic-v1.p.mashape.com/person/drake/album',
    type: 'get',
    dataType: 'json',
    headers: {
      "X-Mashape-Key": "----------------------------",
      "Accept": "application/json"
    }
  })
  .then(
    data =>
      data[0].CreditMediaPairItems.map(
        val =>
          new Album(val.Item.ReleaseDate)
      )
  );
  allAlbums.then(
    albums=>
      logSorted(
        "all albums is set with results so should log sorted:",
        albums
      )
  );
});

//it is kind of pointless to try and use all albums outside of he document ready
//  because document ready is an event that you don't know when it happens unless
//  code is inside document ready.
logSorted("all albums should be empty so sorted is empty too",allAlbums);

当你解决了异步问题,你仍然需要排序,下面是一个如何组合函数来构建多列排序的示例:

代码语言:javascript
复制
const sorter = getter => comparer => (a,b) => 
  comparer(getter(a),getter(b));

const compareNumbers = (a,b)=>a-b;

const compareStrings = (a,b)=>a>b?1:(a<b)?-1:0;

const sortReleaseDate = sorter(x=>x.releaseDate)(compareNumbers);

const sortSomeStringValue = sorter(x=>x.someString)(compareStrings);

const sort = (sorters) => (a,b) => {
  const recur = (index) =>{
    if(index===sorters.length){
      return 0;
    }
    const [sorter,direction] = sorters[index];
    const result = sorter(a,b);
    if(result!==0){
      return result*direction;
    }
    return recur(index+1);
  }
  return recur(0);
};

//example on how to use:
const sampleArray = [
  {someString:"a",releaseDate:3},
  {someString:"a",releaseDate:2},
  {someString:"a",releaseDate:1},
  {someString:"b",releaseDate:3},
  {someString:"b",releaseDate:2},
  {someString:"b",releaseDate:1},
  {someString:"c",releaseDate:3},
  {someString:"c",releaseDate:2},
  {someString:"c",releaseDate:1}
];

console.log(
  "someString descending then releaseDate ascending",
  JSON.stringify(
    sampleArray
    .map(x=>x)//copy so we won't change original
    .sort(
      sort([
        [sortSomeStringValue,-1],//sort by by some string descending
        [sortReleaseDate,1]//sort by release date ascending
      ])
    ),
    undefined,
    2
  )
);

console.log(
  "releaseDate descending then some string ascending",
  JSON.stringify(
    sampleArray
    .map(x=>x)//copy so we won't change original
    .sort(
      sort([
        [sortReleaseDate,-1],//sort by release date descending
        [sortSomeStringValue,1]//sort by by some string ascending
      ])
    ),
    undefined,
    2
  )
)

console.log(
  "only releaseDate descending",
  JSON.stringify(
    sampleArray
    .map(x=>x)//copy so we won't change original
    .sort(
      sort([
        [sortReleaseDate,-1]//sort by release date descending
      ])
    ),
    undefined,
    2
  )
)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48799558

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档