Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS解惑-Object中的key是有序的么? #63

Open
sunmaobin opened this issue May 5, 2019 · 1 comment

Comments

1 participant
@sunmaobin
Copy link
Owner

commented May 5, 2019

当我们使用for/in遍历一个Object对象的时候,打印的结果是否按key的顺序打印出来呢?

答案是:不一定

背景

最近在做一个项目的时候,遇到这样一个需求:

一个下拉列表中有3个固定选项,包括:-1:全部;0:正常;1:失效

于是,我就定义了一个对象,然后循环这个对象,把结果放到 <option> 上面:

var obj = {
    '-1': '全部',
    '0' : '正常',
    '1' : '失效'
};
<!-- Vue代码片段 -->
<select>
    <option v-for="(item, key) in obj" :value="key">{{item}}</option>
</select>

<!-- 结果却是: -->
<!--  0  正常 -->
<!--  1  失效 -->
<!--  -1  全部 -->

于是就有了今天这篇文章,且看下文。

解惑

Object的key的排序规则到底是什么样子的呢?答案是:

如果key是整数(如:123)或者整数类型的字符串(如:“123”),那么会按照从小到大的排序。除此之外,其它数据类型,都安装对象key的实际创建顺序排序。

var obj = {
    '-1': '全部',
    '0' : '正常',
    '1' : '失效'
};
for (let key in obj) {
     console.log(key, obj[key]);
};
// result
// 0 正常
// 1 失效
// -1 全部

另外,如果key中除了整数或者整数类型的字符串外,还含有其它数据类型,则整数放在最前面,比如:

var obj = {
    'a': 111,
    '' : 222,
    '1' : 333,
    '1.3': 444,
    '3': 555
};
for (let key in obj) {
     console.log(key, obj[key]);
};
// result
// 1 333
// 3 555
// a 111
// 我 222
// 1.3 444

解决

那还是上面的问题,我如何让对象按key的顺序输出呢?答案是:

将key转换成非整数类型的字符串,使用的时候再还原。

如果全部是类整数的key,则可以这么做:

// 每个key后面加.转换成字符串
var obj = {
    '-1.': '全部',
    '0.' : '正常',
    '1.' : '失效'
};
for (let key in obj) {
    // ~~ 表示转换成整数,这样上面的key又还原成了-1/0/1
    console.log(~~key, obj[key]);
};
// result
// -1 全部
// 0 正常
// 1 失效

但是,如果key是由各种数据类型混合的,那就不能转换成整数了,可以这么做:

// 每个key前面加.转换成字符串
var obj = {
    '.a': 111,
    '.我' : 222,
    '.1' : 333,
    '.1.3': 444,
    '.3': 555
};
for (let key in obj) {
    // 从第1个字符取原始的key
    console.log(key.substring(1), obj[key]);
};
// result
// a 111
// 我 222
// 1 333
// 1.3 444
// 3 555

最后

回归到我最初遇到的问题,那就这么解决了:

var obj = {
    '-1.': '全部',
    '0.' : '正常',
    '1.' : '失效'
};
<select>
    <option v-for="(item, key) in obj" :value="~~key">{{item}}</option>
</select>

补充方案 2019年06月27日11:24:47

最近又遇到一个问题,在详情页面后台返回key,但是页面上要展示文案,所以按照上面 “最后” 的解决方案,我们就只能这么做了:

{{obj[`${data.key}.`]}}

也就是取值显示的时候,需要 key+. 来拼接,这个写法就非常不友好了。

所以,最后我们采用了Map来处理这个事情,处理上基本算完美了,方案如下:

定义对象:

const obj = new Map([
    [-1, '全部'],
    [0, '正常'],
    [1, '失效']
]);

循环遍历时:

<select>
    <option v-for="[key, item] in Array.from(obj)" :value="key">{{item}}</option>
</select>

详情查看时:

{{obj.get(data.key)}}

参考

@sunmaobin sunmaobin added this to the 2019年 milestone May 5, 2019

@sunmaobin sunmaobin self-assigned this May 5, 2019

@sunmaobin

This comment has been minimized.

Copy link
Owner Author

commented Jun 27, 2019

目前比较推荐最后的 补充方案 ,如果还要其它问题,欢迎留言交流。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.