René's URL Explorer Experiment


Title: 从underscore源码看数组乱序 · Issue #7 · webproblem/Blog · GitHub

Open Graph Title: 从underscore源码看数组乱序 · Issue #7 · webproblem/Blog

X Title: 从underscore源码看数组乱序 · Issue #7 · webproblem/Blog

Description: 前言 前段时间看到过一道实现数组乱序的面试题,也在《如何轻松拿到淘宝前端 offer》一文中看到作者提到数组乱序的问题,竟然还涉及到 v8 引擎方面的知识,正好近期在拜读 underscore 的源码,自己也没有了解过这方面的知识点,在此就总结下关于数组乱序的知识。 面试题 看到的面试题大致是这样的:var arr = ['a', 'b', 'c', 'd', 'c']; 实现数组乱序 。 首先,通过题目可以看出,可能存在一个小陷阱,数组中存在两个 'c' 元素,我想这...

Open Graph Description: 前言 前段时间看到过一道实现数组乱序的面试题,也在《如何轻松拿到淘宝前端 offer》一文中看到作者提到数组乱序的问题,竟然还涉及到 v8 引擎方面的知识,正好近期在拜读 underscore 的源码,自己也没有了解过这方面的知识点,在此就总结下关于数组乱序的知识。 面试题 看到的面试题大致是这样的:var arr = ['a', 'b', 'c', 'd', 'c']; 实现数组乱序 。 ...

X Description: 前言 前段时间看到过一道实现数组乱序的面试题,也在《如何轻松拿到淘宝前端 offer》一文中看到作者提到数组乱序的问题,竟然还涉及到 v8 引擎方面的知识,正好近期在拜读 underscore 的源码,自己也没有了解过这方面的知识点,在此就总结下关于数组乱序的知识。 面试题 看到的面试题大致是这样的:var arr = ['a', 'b', 'c...

Opengraph URL: https://github.com/webproblem/Blog/issues/7

X: @github

direct link

Domain: patch-diff.githubusercontent.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"从underscore源码看数组乱序","articleBody":"![image](https://user-images.githubusercontent.com/20440496/47947861-d7310000-df5f-11e8-9f53-9717d2d093cc.png)\r\n\r\n\r\n### 前言\r\n\r\n前段时间看到过一道实现数组乱序的面试题,也在《如何轻松拿到淘宝前端 offer》一文中看到作者提到数组乱序的问题,竟然还涉及到 v8 引擎方面的知识,正好近期在拜读 underscore 的源码,自己也没有了解过这方面的知识点,在此就总结下关于数组乱序的知识。\r\n\r\n### 面试题\r\n\r\n看到的面试题大致是这样的:```var arr = ['a', 'b', 'c', 'd', 'c']; 实现数组乱序``` 。\r\n\r\n首先,通过题目可以看出,可能存在一个小陷阱,数组中存在两个 'c' 元素,我想这并不是面试官或者出题人无意打错字,可能是想顺便考察下面试者对数组去重的掌握情况。当然了,这个小细节也可以忽略直接进入实现乱序功能。\r\n\r\n对于有代码洁癖的开发人员来说,是不允许自己的程序中出现相同的元素数组值的,所以我们先把数组去重好了。\r\n\r\n```javascript\r\narr = [...new Set(arr)]; // [\"a\", \"b\", \"c\", \"d\"]\r\n```\r\n\r\n去重之后,就可以思考如何实现乱序了。所谓乱序就是打乱原数组元素之间的位置,使之与原数组之间的结构不一致。一开始想的方案是随意交换两个相邻元素的位置使得与原数组不一致就好了。\r\n\r\n```javascript\r\nfunction shuffle(array) {\r\n    array = array.concat();\r\n    var rand = Math.floor(Math.random() * Number(array.length));\r\n    var temp = array[rand];\r\n    if(array[rand - 1] !== void 0) {\r\n        array[rand] = array[rand - 1];\r\n    \tarray[rand - 1] = temp;\r\n    }else if(arr[rand + 1] !== void 0) {\r\n        array[rand] = array[rand + 1];\r\n    \tarray[rand + 1] = temp;\r\n    }\r\n    return array;\r\n}\r\n```\r\n\r\n但后来一想,发现这只是达到了部分乱序的效果而已,要如何才能达到全部元素随机乱序的效果呢?\r\n\r\n### sort + Math.random\r\n\r\n常见的一种实现方案就是使用数组的 sort 排序方法,原理就是 sort 的 compareFunction 匿名函数的返回值小于 0 则升序排列,大于 0 则降序排列,由于 Math.random() 得到的是 0-1 区间的数,Math.random() - 0.5 有 50% 的概率大于 0,50% 的概率小于 0。 \r\n\r\n```javascript\r\nfunction shuffle(arr) {\r\n    return arr.concat().sort(function() {\r\n        return Math.random() - 0.5;\r\n    })\r\n}\r\n```\r\n\r\n但是这并不是最好的解决方案,sort 排序存在的问题就是元素位置概率不均,某个元素排序后位置不变或者调换在相邻位置的概率更高,测试如下: \r\n\r\n```javascript\r\nvar count = new Array(7).fill(0);\r\n\r\nfor(var i=0; i\u003c10000; i++) {\r\n    var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\r\n    arr = shuffle(arr);\r\n    count[arr.indexOf('a')]++;\r\n}\r\n\r\nconsole.log(count); // 一次随机乱序的结果 =\u003e [3033, 2927, 1899, 1143, 585, 284, 129]\r\n```\r\n\r\n测试进行了 10000 次的乱序排序,可以看出 'a' 元素出现在第一个位置的次数远高于出现在其他位置的次数,也就是说本应当出现在每个位置的次数应该是差不多的,实际上却差别很大,这种差异大或者不公平的结果的出现,说明这种方案并不是一个很好的解决方案。 \r\n\r\n### v8 对 sort 的实现\r\n\r\n想要知道为什么 sort 排序会出现元素分布不均的情况,就要了解底层的实现方式。v8 源码中对 sort 的实现,出于性能考虑,对于短数组(数组长度小于等于10)使用的是插入排序,长数组(数组长度大于10)使用的是快速排序和插入排序的混合排序。[v8源码地址](https://github.com/v8/v8/blob/master/src/js/array.js)。\r\n\r\n![image](https://user-images.githubusercontent.com/20440496/47947200-f83f2400-df52-11e8-9cd2-2379d20799b5.png)\r\n\r\n插入排序的源码:\r\n\r\n```javascript\r\nfunction InsertionSort(a, from, to) {\r\n\tfor (var i = from + 1; i \u003c to; i++) {\r\n\t\tvar element = a[i];\r\n\t\tfor (var j = i - 1; j \u003e= from; j--) {\r\n\t\t\tvar tmp = a[j];\r\n\t\t\tvar order = comparefn(tmp, element);\r\n\t\t\tif (order \u003e 0) {\r\n\t\t\t\ta[j + 1] = tmp;\r\n\t\t\t} else {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t\ta[j + 1] = element;\r\n\t}\r\n};\r\n```\r\n\r\n简单来说就是将第一个元素视为有序序列,遍历数组,将之后的元素依次插入这个构建的有序序列中。其中 comparefn() 是关键, comparefn 部分:\r\n\r\n![comparefn ](https://user-images.githubusercontent.com/20440496/47947492-54f10d80-df58-11e8-9719-a83f6d47f795.png)\r\n\r\n具体分析 sort 的分布不均的情况,可参考冴羽的[JavaScript专题之乱序](https://github.com/mqyqingfeng/Blog/issues/51)。\r\n\r\n关于 underscore 源码的解读,解读地址: [Underscore.analysis.js](https://github.com/webproblem/Blog/blob/master/%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/underscore/Underscore.1.8.3.analysis.js)。\r\n\r\n### Fisher–Yates shuffle\r\n\r\n那么有没有更好的实现方案呢?答案是肯定是有的。先来看看 underscore 源码对数组乱序的实现。\r\n\r\nPS:自己研读 underscore 源码时加的注释。\r\n\r\n```javascript\r\n  /**\r\n   * 得到一个随机乱序的集合副本\r\n   * var arr = ['a', 'b', 'c', 'd'];\r\n   * _.shuffle(arr); // 一次随机的结果 =\u003e [\"b\", \"c\", \"d\", \"a\"]\r\n   */\r\n  _.shuffle = function(obj) {\r\n    // 传入 Infinity 参数是为了一次性返回乱序的结果,如果不传,每次执行都会返回一个单一的随机项\r\n    return _.sample(obj, Infinity);\r\n  };\r\n\r\n  /**\r\n   * 从集合中产生一个随机样本\r\n   * 原理是遍历对象元素,将当前元素与另一个随机元素调换位置,直到遍历结束\r\n   * 数组乱序讲解参考文章:\r\n   * https://github.com/mqyqingfeng/Blog/issues/51\r\n   * https://github.com/hanzichi/underscore-analysis/issues/15\r\n   * @param obj    需要乱序的对象\r\n   * @param n      返回的随机元素个数,如果值为空,会返回一个单一的随机项\r\n   * @param guard  暂没发现这个参数的作用\r\n   */\r\n  _.sample = function(obj, n, guard) {\r\n    // 返回单一的随机项\r\n    if (n == null || guard) {\r\n      if (!isArrayLike(obj)) obj = _.values(obj);\r\n      return obj[_.random(obj.length - 1)];\r\n    }\r\n    var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);\r\n    var length = getLength(sample);\r\n    // 防止 n 的值为负数,且 n 的值不能超过对象元素的数量,确保下面的 for 循环正常遍历\r\n    n = Math.max(Math.min(n, length), 0);\r\n    var last = length - 1;\r\n    for (var index = 0; index \u003c n; index++) {\r\n      // 获取随机调换位置元素的下标\r\n      var rand = _.random(index, last);\r\n      var temp = sample[index];\r\n      sample[index] = sample[rand];\r\n      sample[rand] = temp;\r\n    }\r\n    return sample.slice(0, n);\r\n  };\r\n```\r\n\r\nunderscore 实现的大致思路就是遍历数组元素时,将当前元素随机与后面的另一个数组元素的位置进行互换,直到遍历结束。\r\n\r\n这种实现思路就是所谓的 [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) 算法,且时间复杂度为 O(n) ,性能上是最优的。\r\n\r\n按照这个思路再次实现如下:\r\n\r\n```javascript\r\nfunction shuffle(arr) {\r\n    var rand, temp;\r\n    for(var i=0; i\u003carr.length; i++) {\r\n        rand = i + Math.floor(Math.random() * (arr.length - i));\r\n        temp = arr[i];\r\n        arr[i] = arr[rand];\r\n        arr[rand] = temp;\r\n    }\r\n    return arr;\r\n}\r\n```\r\n\r\n再来测试这个方案的效果: \r\n\r\n```javascript\r\nvar count = new Array(7).fill(0);\r\n\r\nfor(var i=0; i\u003c10000; i++) {\r\n    var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\r\n    arr = shuffle(arr);\r\n    count[arr.indexOf('b')]++;\r\n}\r\nconsole.log(count); // 一次随机乱序排序的结果 =\u003e [1403, 1413, 1448, 1464, 1451, 1456, 1365]\r\n```\r\n\r\n可以看到 ‘b’ 元素出现在各个位置的次数大致是均匀的,达到了真正的乱序效果。\r\n\r\n### 其他实现方案\r\n\r\n还有一种实现思路,可能不是最优的方案。 大致思路就是随机挑选数组中的任意一个元素存放到新数组中,且该元素从原数组中移出,重复这样的操作直到原数组中的元素为空,新数组就是乱序后的结果。\r\n\r\n```javascript\r\nfunction shuffle(arr) {\r\n    var newArr = [], rand;\r\n    arr = arr.concat();\r\n    while(arr.length) {\r\n        rand = Math.floor(Math.random() * arr.length);\r\n        newArr.push(arr[rand]);\r\n        arr.splice(rand, 1);\r\n    }\r\n    return newArr;\r\n}\r\n```\r\n\r\n### 总结\r\n\r\n* 常见的 sort + Math.random 方式乱序其实也是属于局部乱序,并没有达到所有元素都打乱顺序的效果。原因是因为 v8 底层对于短数组使用的是插入排序,长数组使用的是混合排序。\r\n* Fisher–Yates shuffle 算法应该是最优的实现方案,原理是遍历数组,将当前元素与在它后面的任意一个元素交换位置,直到遍历结束。\r\n\r\n### 参考\r\n\r\n* https://github.com/mqyqingfeng/Blog/issues/51\r\n* https://github.com/hanzichi/underscore-analysis/issues/15\r\n* https://blog.oldj.net/2017/01/23/shuffle-an-array-in-javascript/\r\n* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle","author":{"url":"https://github.com/webproblem","@type":"Person","name":"webproblem"},"datePublished":"2018-11-02T16:19:45.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/7/Blog/issues/7"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:8dcdcf6c-832f-c991-6f44-85c3b0fab6b3
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-id94C0:38680B:DFB43F:11C112E:69759A68
html-safe-nonce1ce6fcb2048b97c198ccdad8a02c17be03c648a84f2afdd8a98746a3c596f1e8
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5NEMwOjM4NjgwQjpERkI0M0Y6MTFDMTEyRTo2OTc1OUE2OCIsInZpc2l0b3JfaWQiOiI3ODc0OTQ1NDY5NTM5MjYxMDMyIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0=
visitor-hmacb7546876953bd3be822fb8185abcc0bd45edf485276fae7242a39ea4b805e5e6
hovercard-subject-tagissue:376878034
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/webproblem/Blog/7/issue_layout
twitter:imagehttps://opengraph.githubassets.com/e64cf77ec048ed4df1b1e7edb8f06d3cdc2f10b4192f335ee8913bdaf7fb7ce2/webproblem/Blog/issues/7
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/e64cf77ec048ed4df1b1e7edb8f06d3cdc2f10b4192f335ee8913bdaf7fb7ce2/webproblem/Blog/issues/7
og:image:alt前言 前段时间看到过一道实现数组乱序的面试题,也在《如何轻松拿到淘宝前端 offer》一文中看到作者提到数组乱序的问题,竟然还涉及到 v8 引擎方面的知识,正好近期在拜读 underscore 的源码,自己也没有了解过这方面的知识点,在此就总结下关于数组乱序的知识。 面试题 看到的面试题大致是这样的:var arr = ['a', 'b', 'c', 'd', 'c']; 实现数组乱序 。 ...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernamewebproblem
hostnamegithub.com
expected-hostnamegithub.com
None4a4bf5f4e28041a9d2e5c107d7d20b78b4294ba261cab243b28167c16a623a1f
turbo-cache-controlno-preview
go-importgithub.com/webproblem/Blog git https://github.com/webproblem/Blog.git
octolytics-dimension-user_id20440496
octolytics-dimension-user_loginwebproblem
octolytics-dimension-repository_id115346710
octolytics-dimension-repository_nwowebproblem/Blog
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id115346710
octolytics-dimension-repository_network_root_nwowebproblem/Blog
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release488b30e96dfd057fbbe44c6665ccbc030b729dde
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/7#start-of-content
https://patch-diff.githubusercontent.com/
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwebproblem%2FBlog%2Fissues%2F7
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2Fwebproblem%2FBlog%2Fissues%2F7
Sign up https://patch-diff.githubusercontent.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=webproblem%2FBlog
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/7
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/7
Reloadhttps://patch-diff.githubusercontent.com/webproblem/Blog/issues/7
webproblem https://patch-diff.githubusercontent.com/webproblem
Bloghttps://patch-diff.githubusercontent.com/webproblem/Blog
Notifications https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Fork 15 https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Star 113 https://patch-diff.githubusercontent.com/login?return_to=%2Fwebproblem%2FBlog
Code https://patch-diff.githubusercontent.com/webproblem/Blog
Issues 10 https://patch-diff.githubusercontent.com/webproblem/Blog/issues
Pull requests 0 https://patch-diff.githubusercontent.com/webproblem/Blog/pulls
Actions https://patch-diff.githubusercontent.com/webproblem/Blog/actions
Projects 0 https://patch-diff.githubusercontent.com/webproblem/Blog/projects
Security 0 https://patch-diff.githubusercontent.com/webproblem/Blog/security
Insights https://patch-diff.githubusercontent.com/webproblem/Blog/pulse
Code https://patch-diff.githubusercontent.com/webproblem/Blog
Issues https://patch-diff.githubusercontent.com/webproblem/Blog/issues
Pull requests https://patch-diff.githubusercontent.com/webproblem/Blog/pulls
Actions https://patch-diff.githubusercontent.com/webproblem/Blog/actions
Projects https://patch-diff.githubusercontent.com/webproblem/Blog/projects
Security https://patch-diff.githubusercontent.com/webproblem/Blog/security
Insights https://patch-diff.githubusercontent.com/webproblem/Blog/pulse
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/webproblem/Blog/issues/7
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/webproblem/Blog/issues/7
从underscore源码看数组乱序https://patch-diff.githubusercontent.com/webproblem/Blog/issues/7#top
JavaScripthttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22JavaScript%22
underscorehttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22underscore%22
https://github.com/webproblem
https://github.com/webproblem
webproblemhttps://github.com/webproblem
on Nov 2, 2018https://github.com/webproblem/Blog/issues/7#issue-376878034
https://user-images.githubusercontent.com/20440496/47947861-d7310000-df5f-11e8-9f53-9717d2d093cc.png
v8源码地址https://github.com/v8/v8/blob/master/src/js/array.js
https://user-images.githubusercontent.com/20440496/47947200-f83f2400-df52-11e8-9cd2-2379d20799b5.png
https://user-images.githubusercontent.com/20440496/47947492-54f10d80-df58-11e8-9719-a83f6d47f795.png
JavaScript专题之乱序https://github.com/mqyqingfeng/Blog/issues/51
Underscore.analysis.jshttps://github.com/webproblem/Blog/blob/master/%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/underscore/Underscore.1.8.3.analysis.js
Fisher–Yates shufflehttps://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
JavaScript专题之乱序 mqyqingfeng/Blog#51https://github.com/mqyqingfeng/Blog/issues/51
JavaScript 数组乱序 lessfish/underscore-analysis#15https://github.com/lessfish/underscore-analysis/issues/15
https://blog.oldj.net/2017/01/23/shuffle-an-array-in-javascript/https://blog.oldj.net/2017/01/23/shuffle-an-array-in-javascript/
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shufflehttps://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
JavaScripthttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22JavaScript%22
underscorehttps://github.com/webproblem/Blog/issues?q=state%3Aopen%20label%3A%22underscore%22
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.