├── .gitignore ├── Algorithm ├── ACM │ ├── DP.js │ ├── JD201601.js │ ├── JD201602.js │ ├── JD201701.js │ ├── baidu20160427.js │ ├── findNBSTAcc.js │ ├── pushInPop.js │ └── robotWalking.js ├── KMP.js ├── Sortion │ ├── bucketSortion.js │ ├── heapSortion.js │ ├── insertionSort.js │ ├── mergeSort.js │ ├── mergeSortBottomUp.js │ ├── non-recursive-quickSortion.js │ ├── originMergeSortion.js │ ├── quickSortDigging.js │ ├── quickSortionThreeWay.js │ ├── quickSortionTwoWay.js │ ├── radixSortion.js │ ├── selectionSort.js │ ├── shellSort.js │ ├── sortHelper.js │ └── sortNotAllowMerge.js ├── dataStructures │ ├── BFPRT.js │ ├── NumberOf1Between1AndN_Solution.js │ ├── TreeNodeSerializeAndDeserialize.js │ ├── bigNumAdd.js │ ├── deleteListNodeDuplication.js │ ├── findLeftOfLtRightOfGt.js │ ├── isPalindrome.js │ ├── noStructReverseStack.js │ ├── radixConvert.js │ └── reverseLinkNode.js ├── demo-test.js ├── inverseOrderPair.js ├── leetCode │ ├── NO.103-zigzagLevelOrder.js │ ├── NO.41-firstMissingPosition.js │ ├── NO.82.js │ └── NO.x-remove-repeat-listNode.js ├── objectFindLess.js └── util │ ├── linkNode.js │ └── treeNode.js ├── ArrayMethods ├── forEachEffect.js ├── instanceOfBug.html ├── otherChain.html ├── reduce.js └── removes.js ├── CSS ├── CSS3 │ ├── first-child.html │ └── sticky.html ├── Flexbox │ ├── diagramChart.html │ └── verticalCenter.html ├── Problem │ └── zIndexInvalid.html ├── ThreeColumnleftRightFixedWidth │ ├── flexMethods.html │ ├── floatMethods.html │ ├── grailMethods.html │ ├── positionMethods.html │ └── wingMethods.html ├── TwoColumnleftRightFixedWidth │ ├── leftFixedWidth-flexbox.html │ ├── leftFixedWidth-float.html │ ├── leftFixedWidth-floatWrap.html │ ├── leftFixedWidth-grail.html │ ├── leftFixedWidth-position.html │ └── leftFixedWidth-wing.html ├── background.html ├── mobileAdaptation.md ├── quit │ ├── autoHeight.html │ ├── line-height-with-diffvalue.html │ └── positionAutoHeight.html ├── viewport │ └── firmViewport.html └── zIndexInvalid │ ├── createNewStackContext.html │ ├── parentChildRelative.html │ └── sameLevelSmallThanChild.html ├── DOM ├── JS │ ├── lazyLoad.js │ └── lazyLoadI.js ├── compressImage.html ├── images │ └── google.png ├── insertAdjacentElement.html ├── lazyLoad.html ├── lazyLoad1.html ├── querySelectorAll.html └── textContent-innerText-innerHtml.html ├── DailyProblem ├── 201706 │ └── zeptoExtend.js ├── 201708 │ ├── 163SeriesDP.js │ ├── 37WrittenExam.js │ ├── CrashDollyCanLeaveTrack.js │ ├── DJI.js │ ├── al.html │ ├── computeBacketLeakStage.js │ ├── drag.html │ ├── fanpu01.html │ ├── fanpu02.html │ ├── gbits.js │ ├── lazyMan.js │ ├── meitu.js │ ├── muchMakeUpFlower.js │ ├── nowcoderDungeonEscape.js │ ├── sharesXiaomi.js │ └── toutiao.html ├── 201711 │ ├── h5Drag.html │ └── webWorker │ │ ├── main.html │ │ └── webWorkerExample.js ├── 2017-10-25toutiao │ └── index.html ├── 2017-4-15WPS │ ├── 2017-4-15WPS02.js │ ├── 2017-4-15WPS04.js │ ├── 2017-4-15WPS06.js │ └── README.md ├── 2017-4-18toutiao │ ├── 2016-4-18toutiao.html │ ├── README.md │ └── question1.png ├── 2017-4-27toutiao │ ├── 01.md │ ├── 03.html │ └── README.md ├── 2017-5-10fanpu │ ├── aiqiyi.js │ └── index.html └── 2017-5-19 │ ├── 01.js │ ├── 02.js │ └── 03.js ├── EventLoop ├── Native │ └── README.md └── Nodejs │ ├── 7-20-demo.js │ ├── README.md │ ├── nextTick.js │ ├── recursion-setImmediate.js │ └── setImmediate.js ├── GraphQL ├── helloworld.js └── package.json ├── JS ├── CompatibleRequestAnimationFrame.js ├── EventEmit.js ├── JSONP │ └── JSONP.html ├── MVVM.html ├── MiddleWare.js ├── Promise │ ├── Promise-polyfill.js │ ├── compareWhichRequestIsQuick.js │ ├── data │ │ ├── data1.json │ │ └── data2.json │ ├── produceChar.js │ ├── promise-ajaxLoadImg.html │ ├── promise-all.js │ ├── promise-race.js │ ├── promise-resolve.js │ ├── promiseErrCatch.js │ ├── readFilePromise.js │ ├── thenReturnPromise01.js │ └── thenReturnPromise02.js ├── async │ └── asyncGenertor.js ├── autoExecuteMoreHandler.js ├── bind-polyfill.js ├── cookie-crossdomain │ ├── getCookie.php │ └── index.php ├── curryContinuedInvoke.js ├── cvteDiffDemo.js ├── dataSingleDirectionBind.html ├── extends │ ├── combinationInheritance.js │ ├── constructorStealing.js │ ├── parasiticCombination.js │ ├── parasiticExtends.js │ ├── prototypalInheritace.js │ └── prototypeExtends.js ├── fileReaderDemo.html ├── flatteningToArr.js ├── formValidator │ ├── es6Primary.html │ ├── es6Proxy.html │ ├── js │ │ ├── es6Proxy.js │ │ └── primary.js │ └── proxyDemo │ │ └── pipeExecute.js ├── myPromise.js ├── new-polyfill.js ├── quitAsyncAwait.js ├── textboxSelect.html ├── touches.html ├── underscore │ ├── debounce.js │ ├── debouncePage.html │ ├── throttle.js │ └── throttlePage.html ├── vue-computed.html ├── vue-mvvm.html └── window-name-cross-domain │ ├── data.php │ ├── index.html │ └── proxy.html ├── Network └── index.md ├── Node └── memory-leak │ ├── index.js │ └── package.json ├── README.md └── webpack └── treeShakingTheory ├── .babelrc ├── .gitignore ├── bundle.js ├── car.js ├── engine.js ├── package.json ├── treeShakingTheory.html └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules -------------------------------------------------------------------------------- /Algorithm/ACM/DP.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/12. 3 | */ 4 | function f0(cweight, cidx, w, g, p, n) { 5 | if (cidx == n - 1) 6 | if (p[cidx] + cweight <= w) 7 | return g[cidx] 8 | else 9 | return 0 10 | else { 11 | if (p[cidx] + cweight <= w) 12 | return Math.max( 13 | g[cidx] + f0(p[cidx] + cweight, cidx + 1, w, g, p, n), 14 | f0(cweight, cidx + 1, w, g, p, n) 15 | ) 16 | else 17 | return f0(cweight, cidx + 1, w, g, p, n) 18 | } 19 | } 20 | 21 | /** 22 | * 动态规划 23 | * @param n 金矿的数量 24 | * @param w 工人数 25 | * @param g 金矿数组 26 | * @param p 用工量数组 27 | * @returns {Array} 28 | */ 29 | function f1(n, w, g, p) { 30 | var preResult = new Array(p.length) 31 | var results = new Array(p.length) 32 | var max = 0 33 | // 填充边界格子的值 34 | for (var i = 0; i <= w; i++) { 35 | if (i < p[0]) { 36 | preResult[i] = 0 37 | } else { 38 | preResult[i] = g[0] 39 | } 40 | } 41 | 42 | // 填充其余格子的值,外层循环是金矿数量,内层循环是工人数 43 | for (i = 0; i < n; i++) { 44 | for (var j = 0; j <= w; j++) { 45 | if (j < p[i]) { 46 | results[j] = preResult[j] 47 | } else { 48 | results[j] = Math.max(preResult[j], preResult[j - p[i]] + g[i]) 49 | } 50 | max = results[j] > max ? results[j] : max 51 | } 52 | preResult = results.slice() 53 | } 54 | // console.log(`max price is ${max}`) 55 | // return results 56 | return max 57 | } 58 | 59 | function prodRand(min, max) { 60 | return min + ~~((max - min) * Math.random()) 61 | } 62 | 63 | var n = 5 64 | var w = 10 65 | // 金矿数组 66 | var g = [400, 500, 200, 300, 350] 67 | // 用工量数组 68 | var p = [5, 5, 3, 4, 3] 69 | console.log(f1(n, w, g, p)) 70 | console.log(f0(0, 0, w, g, p, n)) 71 | console.log(f0(0, 0, 10, [6,3,5,4,6], [2,2,6,5,4], 5)) -------------------------------------------------------------------------------- /Algorithm/ACM/JD201601.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 选举游戏(京东2016实习生真题) 3 | 小东和其他小朋友正在玩一个关于选举的游戏。选举是通过投票的方式进行的,得票最多的人将获胜。 4 | 5 | 小东是编号为1的候选者,此外还有其他的候选者参加选举。根据初步的调查情况,所有准备投票的小朋友都有一定的投票倾向性,小东如果要获得胜利,必须争取部分准备为其他候选人投票的小朋友。由于小东的资源较为有限,她希望用最小的代价赢得胜利,请你帮忙计算她最少需要争取的选票数。 6 | 7 | 输入 8 | 输入有若干组,每组包含两行,第一行为一个正整数n(2<=n<=100),表示候选者的数量,第二行为每个候选人预期得到的选票数,以空格分开,每人的预期得票数在1到1000之间(包含1和1000)。 9 | 经过小东的争取后,可能出现候选人得票数为0或超过1000的情况。 10 | 11 | 样例输入 12 | 5 13 | 5 1 11 2 8 14 | 4 15 | 1 8 8 8 16 | 2 17 | 7 6 18 | 19 | 输出 20 | 对每组测试数据,单独输出一行,内容为小东最少需要争取的选票数。 21 | 样例输出 22 | 4 23 | 6 24 | 0 25 | 26 | 时间限制 27 | C/C++语言:1000MS 28 | 其他语言:3000MS 29 | 内存限制 30 | C/C++语言:65536KB 31 | 其他语言:589824KB 32 | * */ 33 | (function (str) { 34 | 35 | var arr = str.split(" "); 36 | // int 37 | arr.forEach(function (ele, ind) { 38 | arr[ind] = +ele; 39 | }); 40 | 41 | var goal = arr.splice(0, 1)[0]; 42 | 43 | var desc = function (a, b) { 44 | return b - a; 45 | }; 46 | arr.sort(desc); 47 | 48 | var result = 0; 49 | while (goal <= arr[0]) { 50 | arr[0] = arr[0] - 1; 51 | goal += 1; 52 | result += 1; 53 | arr.sort(desc); 54 | } 55 | console.log(result); 56 | 57 | })("5 1 11 2 8"); -------------------------------------------------------------------------------- /Algorithm/ACM/JD201602.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 铺地砖(京东2016实习生真题) 3 | 小东最近承接了一个工程,为一块广场铺设地砖。待铺设的广场是矩形的,大小为N*M平米,业主要求铺设的地砖规格统一,大小为a*a平米。地砖可以超出待铺设的区域,但必须将指定的区域完全覆盖。铺设时,要求地砖边缘需与指定区域边缘平行,且必须用整块的地砖铺设,不允许将地砖破碎铺设。 4 | 5 | 为节约成本,小东需要知道铺设最少需要多少地砖。请你帮忙计算她最少需要采购的地砖数。 6 | 7 | 输入 8 | 输入的第一行为一个正整数T,表示有T组测试数据。随后的T行中,每行为一组测试数据。每组测试数据包含由3个正整数构成,分别为N、M和a,其中1<=N, M, a <=10^9。 9 | 样例输入 10 | 1 11 | 6 6 4 12 | 13 | 输出 14 | 对每组测试数据,单独输出一行,为所需采购的地砖数。 15 | 样例输出 16 | 4 17 | 时间限制 18 | C/C++语言:1000MS 19 | 其他语言:3000MS 20 | 内存限制 21 | C/C++语言:65536KB 22 | 其他语言:589824KB 23 | */ 24 | (function (str) { 25 | 26 | var arr = str.split(" "); 27 | 28 | var n = +arr[0], m = +arr[1], a = +arr[2]; 29 | var widthC = Math.ceil(n / a); 30 | var heightC = Math.ceil(m / a); 31 | 32 | console.log(widthC * heightC); 33 | })("6 6 4"); -------------------------------------------------------------------------------- /Algorithm/ACM/baidu20160427.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 度度熊有一个N个数的数组,他想将数组从大到小排好序,但是萌萌的度度熊只会下面这个操作: 3 | 任取数组中的一个数然后将它放置在数组的最后一个位置。 4 | 问最少操作多少次可以使得数组从小到大有序? 5 | * */ 6 | 7 | /* 8 | * 思路: 9 | * 10 | * 先将原数组排序, 11 | * 排序好的数组跟原数组比较, 12 | * 在原数组中寻找符合元素顺序的个数, 13 | * 用数组的长度减去符合元素顺序的个数,得到的就是要移动的次数 14 | * 15 | * */ 16 | 17 | (function (arr) { 18 | var sort = arr.slice().sort(function (a, b) { 19 | return a - b; 20 | }); 21 | 22 | var q = 0, len = sort.length; 23 | for (var i = 0; i < len; i++) { 24 | if (arr[i] === sort[q]) { 25 | q++; 26 | } 27 | } 28 | 29 | console.log(len - q); 30 | 31 | })([9, 17, 19, 7]); -------------------------------------------------------------------------------- /Algorithm/ACM/findNBSTAcc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 求包含n个节点的二叉查找树的种类数 3 | * Created by 海枯 on 2017/11/13. 4 | */ 5 | 6 | function main(n) { 7 | if (n == 0) 8 | return 0 9 | else if (n == 1) 10 | return 1 11 | else if (n == 2) 12 | return 2 13 | var dp = new Array(n) 14 | dp[0] = 1 15 | dp[1] = 1 16 | dp[2] = 2 17 | for (var i = 3; i <= n; i++) { 18 | var c = 0 19 | for (var j = 1; j <= i; j++) 20 | c += dp[j - 1] * dp[i - j] 21 | dp[i] = c 22 | } 23 | return dp[n] 24 | } 25 | console.log(main(5)) -------------------------------------------------------------------------------- /Algorithm/ACM/pushInPop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/11/18. 3 | * 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。 4 | * 假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列, 5 | * 但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 6 | */ 7 | 8 | /** 9 | * 10 | * @param pushV 11 | * @param popV 12 | * @returns {boolean} 13 | * @constructor 14 | */ 15 | function IsPopOrder(pushV, popV) { 16 | // write code here 17 | var i, len = popV.length 18 | var stack = [] 19 | // init 20 | for (var j = 0; pushV[j] != popV[0] && j < len; j++) 21 | stack.push(pushV[j]) 22 | // 找不到该元素 23 | if (j >= len && pushV[len - 1] != popV[0]) 24 | return false 25 | for (i = 1; i < len; i++) { 26 | var item = popV[i] 27 | var prev = popV[i - 1] 28 | // 前面的值比当前值小 29 | if (item < prev) 30 | if (stack[stack.length - 1] != item) 31 | return false 32 | else 33 | stack.pop() 34 | // 前面的值比当前值大 35 | else { 36 | for (var k = j + 1; pushV[k] != item && k < len; k++) 37 | stack.push(pushV[k]) 38 | // 找不到该元素 39 | if (k >= len && pushV[len - 1] != item) 40 | return false 41 | } 42 | } 43 | return true 44 | } 45 | 46 | console.log(IsPopOrder([1, 2, 3, 4, 5], [4, 5, 3, 2, 1])) 47 | console.log(IsPopOrder([1, 2, 3, 4, 5], [4, 3, 5, 1, 2])) -------------------------------------------------------------------------------- /Algorithm/ACM/robotWalking.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/24. 3 | * 一排有N个位置,一个机器人在最开始停留在P位置上, 4 | * 如果P==0位置,下一分钟机器人一定向右移动到1位置; 5 | * 如果P==N-1,下一分钟机器人一定向左移动到N-2位置。 6 | * 如果P在0和N-1之间,下一分钟机器人一定回向左或右移动。 7 | * 求K分钟的时候,机器人到达T位置有多少种走法。 8 | * 9 | * 函数为int f(int N, int P, int K, int T),返回值为走法的数量 10 | */ 11 | 12 | /** 13 | * 暴力递归法 14 | * @param N 一共N个位置 15 | * @param P 当前位置(从第0个位置开始) 16 | * @param K 第K分钟后 17 | * @param T 目标位置(从第0个位置开始) 18 | */ 19 | function f(N, P, K, T) { 20 | if (N < 2 || P < 0 || T < 0 || N < P + 1 || K < 1 || N < T + 1) 21 | return 0 22 | 23 | if (K == 1) 24 | return P == T ? 1 : 0 25 | 26 | if (P == 0) 27 | return f(N, P + 1, K - 1, T) 28 | 29 | if (P == N - 1) 30 | return f(N, P - 1, K - 1, T) 31 | 32 | return f(N, P + 1, K - 1, T) + f(N, P - 1, K - 1, T) 33 | } 34 | // console.log(f(3, 0, 4, 1)) 35 | 36 | /** 37 | * DP法 38 | * @param N 一共N个位置 39 | * @param P 当前位置(从第0个位置开始) 40 | * @param K 第K分钟后 41 | * @param T 目标位置(从第0个位置开始) 42 | */ 43 | function f1(N, P, K, T) { 44 | if (N < 2 || P < 0 || T < 0 || N < P + 1 || K < 1 || N < T + 1) 45 | return 0 46 | 47 | let ans = new Array(K + 1) 48 | 49 | for (let i = 1; i <= K; i++) { 50 | let inner = new Array(N) 51 | if (i == 1) { 52 | inner[T] = 1 53 | for (let j = 0; j < T; j++) 54 | inner[j] = 0 55 | for (let j = T + 1; j < N; j++) 56 | inner[j] = 0 57 | } else { 58 | inner[0] = ans[i - 1][1] 59 | inner[N - 1] = ans[i - 1][N - 2] 60 | 61 | for (let j = 1; j < N - 1; j++) 62 | inner[j] = ans[i - 1][j - 1] + ans[i - 1][j + 1] 63 | } 64 | ans[i] = inner 65 | } 66 | return ans[K][P] 67 | } 68 | // console.log(f1(3, 0, 4, 1)) 69 | 70 | function main() { 71 | const SUM = 1000 72 | // 对数器 73 | for (let i = 0; i < SUM; i++) { 74 | let N = ~~(Math.random() * 5) * 5 75 | let P = ~~(Math.random() * N) 76 | let K = ~~(Math.random() * 10) + 2 77 | let T = ~~(Math.random() * N) 78 | 79 | let res1 = f(N, P, K, T) 80 | let res2 = f1(N, P, K, T) 81 | if (res1 !== res2) { 82 | console.log('error answer!') 83 | } 84 | } 85 | } 86 | main() -------------------------------------------------------------------------------- /Algorithm/KMP.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/11/1. 3 | */ 4 | function kMP(source, match) { 5 | if (source.length < match.length) 6 | return -1 7 | var next = getNextArray(match) 8 | var i = 0, j = 0 9 | while (i < source.length && j < match.length) { 10 | if (source[i] == match[j]) { 11 | i++ 12 | j++ 13 | } else if (next[j] == -1) 14 | i++ 15 | else 16 | j = next[j] 17 | } 18 | return j === match.length ? i - j : -1 19 | } 20 | 21 | function getNextArray(str) { 22 | var next = new Array(str.length) 23 | var lastm = 0 24 | next[0] = -1 25 | next[1] = 0 26 | var pos = 2 27 | while (pos < str.length) { 28 | if (str[pos - 1] === str[lastm]) 29 | next[pos++] = ++lastm 30 | else if (lastm > 0) 31 | lastm = next[lastm] 32 | else { 33 | lastm = 0 34 | next[pos++] = lastm 35 | } 36 | } 37 | return next 38 | } 39 | console.log(kMP('abcabcabx', 'babcabx')) 40 | // console.log(kMP('abcabcabx', 'abcabcabx')) -------------------------------------------------------------------------------- /Algorithm/Sortion/bucketSortion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/7/24. 3 | * 桶排序:典型的一种以空间换时间的排序算法 4 | * 步骤: 5 | * 1. 创建一个定量的空桶数组 6 | * 2. 遍历数组,将数组元素一个个加入桶中。对于有多个重复元素,设置数组值区分个数 7 | * 3. 对每个不是空的桶排序 8 | * 缺陷: 9 | * 1. 待排序的元素不能为负数,不能为小数 10 | * 2. 空间复杂度不确定,要看待排序元素中最大值是多少 11 | */ 12 | 13 | var {productRand} = require('./sortHelper'), 14 | n = 100 15 | 16 | function bucketSortion(array, max) { 17 | // 创建空桶 18 | var buckets = new Array(max); 19 | // 将数组元素依次放入特定的桶中 20 | for (var i = 0; i < array.length; i++) 21 | if (!buckets[array[i]]) 22 | buckets[array[i]] = 1; 23 | else 24 | buckets[array[i]]++; 25 | // 从桶中取元素放进原数组中 26 | for (var j = 0, k = 0; j < buckets.length; j++) 27 | while (buckets[j] != null && buckets[j]-- > 0) 28 | array[k++] = j; 29 | 30 | return array; 31 | } 32 | 33 | var example1 = productRand(1, 100, n); 34 | console.log(bucketSortion(example1, example1.length)); -------------------------------------------------------------------------------- /Algorithm/Sortion/heapSortion.js: -------------------------------------------------------------------------------- 1 | // 堆排序 2 | // 步骤:创建最大堆树,把最大堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出 3 | function heapSortion(array) { 4 | 5 | // 交换 6 | function swap(array, i, k) { 7 | var temp = array[i] 8 | array[i] = array[k] 9 | array[k] = temp 10 | } 11 | 12 | // 最大堆调整,使得子节点永远小于父节点 13 | function maxHeapify(array, index, maxLength) { 14 | var max, 15 | // 取得父节点的左子树index 16 | left , 17 | // 取得父节点的右子数index 18 | right 19 | 20 | while (true) { 21 | max = index 22 | left = 2 * index + 1 23 | right = 2 * (index + 1) 24 | 25 | if (left < maxLength && array[index] < array[left]) { 26 | max = left 27 | } 28 | if (right < maxLength && array[max] < array[right]) { 29 | max = right 30 | } 31 | 32 | if (max != index) { 33 | swap(array, max, index) 34 | index = max 35 | } else { 36 | break 37 | } 38 | } 39 | } 40 | 41 | // 创建最大堆:将堆所有数据重新排序,使其成为最大堆 42 | function buildMaxHeap(array) { 43 | var i 44 | , parent = Math.floor(array.length / 2) - 1 45 | 46 | for (i = parent; i >= 0; i--) { 47 | maxHeapify(array, i, array.length) 48 | } 49 | } 50 | 51 | function sort(array) { 52 | 53 | buildMaxHeap(array) 54 | 55 | for (var i = array.length - 1; i > 0; i--) { 56 | swap(array, 0, i) 57 | 58 | maxHeapify(array, 0, i) 59 | } 60 | 61 | return array 62 | } 63 | 64 | return sort(array) 65 | } 66 | 67 | console.log(heapSortion([4, 1, 3, 2, 16, 9, 10, 14, 8, 7])); 68 | 69 | var {productRand, swap} = require('./sortHelper'), 70 | n = 100 71 | function heapSortion1(array) { 72 | // min从索引0开始,根据根节点推算出左子树和右子树 73 | function heapAdjust(array, i, max) { 74 | var m = Math.floor(i / 2); 75 | var left = m * 2 + 1; 76 | var right = m * 2 + 2; 77 | var adjustMax = m; 78 | if (i <= max) { 79 | if (left <= max && array[left] > array[m]) 80 | adjustMax = left; 81 | // 原本写成这样的。。if (right <= max && array[right] > array[m]) 82 | // 并不能判断right一定大于left 83 | if (right <= max && array[right] > array[adjustMax]) 84 | adjustMax = right; 85 | if (adjustMax != m) { 86 | swap(array, m, adjustMax); 87 | // 检测调整后的是否为最大堆 88 | heapAdjust(array, adjustMax, max); 89 | } 90 | } 91 | } 92 | 93 | function __heapSortion(array, length) { 94 | var lastIdx = length - 1; 95 | 96 | for (var size = lastIdx; size > 0 ; size--) { 97 | //构建最大堆 98 | for (var i = size % 2 ? size : size - 1; i > 0; i -= 2) { 99 | heapAdjust(array, i, size); 100 | } 101 | // 最大堆的堆顶与最后第N个元素做交换 102 | swap(array, 0, size); 103 | } 104 | return array; 105 | } 106 | 107 | return __heapSortion(array, array.length); 108 | } 109 | 110 | var example1 = productRand(1, 100, n) 111 | console.log(heapSortion1(example1)); -------------------------------------------------------------------------------- /Algorithm/Sortion/insertionSort.js: -------------------------------------------------------------------------------- 1 | // 插入排序 2 | 3 | var arr = [4, 2, 5, 3, 8, 6, 10, 2], len = arr.length; 4 | 5 | // 普通的交换法的直接排序 6 | function swapInsertionSort(rootArr) { 7 | var arr = rootArr.slice(); 8 | 9 | var swap = function (array, i, j) { 10 | var temp = array[i]; 11 | array[i] = array[j]; 12 | array[j] = temp; 13 | } 14 | var i, j, length = arr.length; 15 | // i 循环的次数 16 | for (i = 1; i < length; i++) { 17 | // j 保证前j个顺序相同 18 | for (j = i; j > 0; j--) { 19 | if (arr[j - 1] > arr[j]) { 20 | swap(arr, j - 1, j); 21 | } else { 22 | break; 23 | } 24 | } 25 | } 26 | console.log(arr); 27 | } 28 | 29 | swapInsertionSort(arr); 30 | 31 | // 优化交换的次数---直接排序从头选temp,从头排 32 | function insertionSort(rootArr) { 33 | var arr = rootArr.slice(); 34 | 35 | var length = arr.length, i, j, temp; 36 | 37 | for (i = 1; i < length; i++) { 38 | temp = arr[i]; 39 | 40 | for (j = i - 1; j >= 0 && arr[j] > temp; j--) { 41 | arr[j + 1] = arr[j]; 42 | } 43 | arr[j + 1] = temp; 44 | } 45 | 46 | console.log(arr); 47 | } 48 | 49 | insertionSort(arr); 50 | 51 | // 如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目,简称二分查找排序 52 | 53 | function binarySearchInsertionSort(rootArr) { 54 | 55 | function binarySearch(array, start, end, temp) { 56 | var middle; 57 | while (start <= end) { 58 | middle = Math.floor((start + end) / 2); 59 | if (array[middle] > temp) { 60 | 61 | if (middle == 0) return middle; 62 | else if (array[middle - 1] < temp) { 63 | return middle; 64 | } else { 65 | end = middle - 1; 66 | } 67 | } else { 68 | if (array[middle + 1] >= temp) { 69 | return middle + 1; 70 | } else { 71 | start = middle + 1; 72 | } 73 | } 74 | } 75 | return end + 1; 76 | } 77 | 78 | function insertionSort(arr) { 79 | var arr = rootArr.slice(); 80 | var i, j, k, temp, length = arr.length; 81 | for (i = 1; i < length; i++) { 82 | temp = arr[i]; 83 | 84 | // 前面那数小于temp时,跳过无需排序 85 | if (arr[i - 1] < temp) continue; 86 | 87 | k = binarySearch(arr, 0, i - 1, temp); 88 | 89 | for (j = i; j > k; j--) { 90 | arr[j] = arr[j - 1]; 91 | } 92 | arr[k] = temp; 93 | } 94 | return arr; 95 | } 96 | 97 | console.log(insertionSort(rootArr)); 98 | } 99 | 100 | binarySearchInsertionSort(arr); -------------------------------------------------------------------------------- /Algorithm/Sortion/mergeSort.js: -------------------------------------------------------------------------------- 1 | // 归并排序(Merge sort) 2 | 3 | var arr = [4, 2, 5, 3, 8, 6, 10, 2] 4 | 5 | function mergeSort(rootArr) { 6 | var arr = rootArr.slice() 7 | , length = arr.length 8 | 9 | if (length == 1) { 10 | return arr; 11 | } 12 | var mid = Math.floor(length / 2) 13 | , left = arr.slice(0, mid) 14 | , right = arr.slice(mid) 15 | return merge(mergeSort(left), mergeSort(right)) 16 | } 17 | 18 | function merge(left, right) { 19 | var arr = [] 20 | 21 | while (left.length > 0 && right.length > 0) { 22 | if (left[0] < right[0]) { 23 | arr.push(left.shift()) 24 | } else { 25 | arr.push(right.shift()) 26 | } 27 | } 28 | return arr.concat(left, right) 29 | } 30 | 31 | console.log(mergeSort(arr)); -------------------------------------------------------------------------------- /Algorithm/Sortion/mergeSortBottomUp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 自底向上的归并排序 3 | * Created by 海枯 on 2017/7/1. 4 | */ 5 | 6 | function mergeSortBU(array, n) { 7 | // 第一轮sz = 1,第二轮sz = 2,第三轮sz = 4, 第四轮sz = 8 8 | for (var sz = 1; sz <= n; sz += sz) { 9 | for (var k = 0; k + sz < n; k += sz + sz) { 10 | __merge(array, k, k + sz - 1, Math.min(k + sz + sz - 1, n - 1)) 11 | } 12 | } 13 | } 14 | 15 | // 合并[l, ... , mid] 与 [mid + 1, ... , r] 16 | function __merge(array, l, mid, r) { 17 | // 新建个能装下两个数组长度的数组 18 | var twice = new Array(r - l + 1) 19 | // 复制原数组要排序的值,做映射 20 | for (var i = l; i <= r; i++) 21 | twice[i - l] = array[i] 22 | 23 | var lInit = l, rInit = mid + 1 24 | 25 | for (var k = l; k <= r; k++) { 26 | if (lInit > mid ) { 27 | array[k] = twice[rInit - l] 28 | rInit++ 29 | }else if (rInit > r || twice[lInit - l] < twice[rInit - l]) { 30 | array[k] = twice[lInit - l] 31 | lInit++ 32 | } else { 33 | array[k] = twice[rInit - l] 34 | rInit++ 35 | } 36 | } 37 | } 38 | 39 | function productRand(min, max, n) { 40 | var arr = new Array(n) 41 | for (var i = 0; i < n; i++) { 42 | arr[i] = ~~(Math.random() * (max - min)) + min 43 | } 44 | return arr 45 | } 46 | 47 | const n = 100 48 | 49 | var example1 = productRand(0, 100, n) 50 | console.log("BeforeSort:") 51 | console.log(example1.toString()) 52 | 53 | mergeSortBU(example1, n) 54 | 55 | console.log("AfterSort:") 56 | console.log(example1.toString()) -------------------------------------------------------------------------------- /Algorithm/Sortion/non-recursive-quickSortion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/10/20. 3 | */ 4 | function quickSortion(arr) { 5 | var l = 0, r = arr.length - 1 6 | var stack = [] 7 | stack.push({l, r}) 8 | while (stack.length > 0) { 9 | var popEle = stack[stack.length - 1] 10 | l = popEle['l'] 11 | r = popEle['r'] 12 | stack.pop() 13 | 14 | var balance = partition(arr, l, r) 15 | l < balance - 1 && stack.push({l, r: balance - 1}) 16 | r > balance + 1 && stack.push({l: balance + 1, r}) 17 | } 18 | return arr 19 | } 20 | 21 | function partition(arr, l, r) { 22 | var provit = arr[l] 23 | var i = l, j 24 | for (j = l + 1; j <= r; j++) 25 | if (arr[j] < provit) 26 | swap(arr, j, ++i) 27 | swap(arr, l, i) 28 | return i 29 | } 30 | function swap(arr, l, j) { 31 | if (l == j) return 32 | arr[l] = arr[l] ^ arr[j] 33 | arr[j] = arr[l] ^ arr[j] 34 | arr[l] = arr[j] ^ arr[l] 35 | } 36 | console.log(quickSortion([6,5,4,3,2,1])) -------------------------------------------------------------------------------- /Algorithm/Sortion/originMergeSortion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/6/30. 3 | */ 4 | 5 | // 递归使用归并排序,对arr[l ... r]的范围进行排序 6 | function __mergeSort(arr, l, r) { 7 | if (l >= r) return; 8 | // 根据l和r的偏移量取mid 9 | var mid = Math.floor((r + l) / 2) 10 | __mergeSort(arr, l, mid) 11 | __mergeSort(arr, mid + 1, r) 12 | // 归并排序优化1: 13 | // 归并排序后的数组是有序的,只需执行无序的情况 14 | // 归并排序优化2: 15 | // 当执行到递归末尾的时候,可以考虑使用插入排序去优化 16 | if (arr[mid] > arr [mid + 1]) 17 | __merge(arr, l, mid, r) 18 | } 19 | 20 | // 将arr[l ... mid] 与 arr[mid + 1 ... r]两部分合并 21 | function __merge(arr, l, mid, r) { 22 | var twice = new Array(r - l + 1) 23 | 24 | for (var i = l; i <= r; i++) 25 | twice[i - l] = arr[i] 26 | 27 | var lPoint = l, rPoint = mid + 1 28 | 29 | // 在原数组上改变对应的值,使其一部分是有序的 30 | for (var k = l; k <= r; k++) { 31 | if (lPoint > mid) { 32 | arr[k] = twice[rPoint - l] 33 | rPoint++ 34 | } else if (rPoint > r) { 35 | arr[k] = twice[lPoint - l] 36 | lPoint++ 37 | } else if (twice[lPoint - l] < twice[rPoint - l]) { 38 | arr[k] = twice[lPoint - l] 39 | lPoint++ 40 | } else { 41 | arr[k] = twice[rPoint - l] 42 | rPoint++ 43 | } 44 | 45 | } 46 | } 47 | 48 | // 归并排序 main方法 49 | function mergeSort(array, n) { 50 | __mergeSort(array, 0, n - 1) 51 | } 52 | 53 | var productRand = require('./sortHelper') 54 | 55 | const n = 100 56 | 57 | var example1 = productRand(0, 100, n) 58 | console.log("BeforeSort:") 59 | console.log(example1.toString()) 60 | 61 | mergeSort(example1, n) 62 | 63 | console.log("AfterSort:") 64 | console.log(example1.toString()) 65 | 66 | var example2 = productRand(0, 500, n) 67 | console.log("BeforeSort:") 68 | console.log(example2.toString()) 69 | 70 | mergeSort(example2, n) 71 | 72 | console.log("AfterSort:") 73 | console.log(example2.toString()) -------------------------------------------------------------------------------- /Algorithm/Sortion/quickSortDigging.js: -------------------------------------------------------------------------------- 1 | var {productRand, swap} = require('./sortHelper'), 2 | n = 100 3 | 4 | // 快速排序--挖坑填数+分治法 5 | 6 | // 过程如下: 7 | // 取第一个元素作为基准元素 72 8 | // 规定小于或等于基准元素的数字放左边,大于基准元素的数字放右边 9 | // 从右向左的变量为 j = len - 1 ,从左往右的变量为 i = 0 10 | 11 | // 第一趟 j = 9, j-- 找比72小的元素,找到了48。将72替换成48。此时 j = 8; 12 | // 数组为[48, 6, 57, 88, 60, 42, 83, 73, 48, 85] 13 | 14 | // 第二趟 i = 0, i++ 找比72大的元素,找到了88。将48替换成88。此时 i = 4; 15 | // 数组为[48, 6, 57, 88, 60, 42, 83, 73, 88, 85] 16 | 17 | // 第三趟 j = 8, j-- 找比72小的元素,找到了42。将88替换成42。此时 j = 5; 18 | // 数组为[48, 6, 57, 42, 60, 42, 83, 73, 88, 85] 19 | 20 | // 第四趟 i = 4, j++ 找比72大的元素,i 和 j相遇,此次循环结束。将 j = i = 5的位置写入72 21 | // 数组为[48, 6, 57, 42, 60, 72, 83, 73, 88, 85] 22 | 23 | // 该次排序结束 小于72的都放在左边 大于72的都放在右边 24 | // 按照此步骤继续递归 25 | var arr = [7, 6, 5, 4, 3, 2], len = arr.length; 26 | 27 | function quickSortDiggingOrigin(arr) { 28 | var len = arr.length; 29 | if (len <= 1) { 30 | return []; 31 | } 32 | 33 | var i = 0, j = len - 1; 34 | var basic = arr[0]; 35 | 36 | var nonce = basic; 37 | 38 | while (i !== j) { 39 | for (; j !== i; j--) { 40 | nonce = arr[j]; 41 | if (basic > arr[j]) { 42 | arr[i] = nonce; 43 | break; 44 | } 45 | } 46 | 47 | for (; i !== j; i++) { 48 | nonce = arr[i]; 49 | if (basic < arr[i]) { 50 | arr[j] = nonce; 51 | break; 52 | } 53 | } 54 | } 55 | 56 | arr[i] = basic; 57 | // console.log(arr); 58 | 59 | var left = arr.slice(0, i + 1); 60 | var right = arr.slice(i + 1); 61 | 62 | return quickSortDiggingOrigin(left).concat(arr[i], quickSortDiggingOrigin(right)); 63 | } 64 | 65 | console.log("quickSortDiggingOrigin: " + quickSortDiggingOrigin(arr)); 66 | 67 | /* 68 | * in-place第二种内部交换法 69 | * 70 | * 思路: 71 | * 将pivot设置为最后一个元素, 72 | * 3 7 8 5 2 1 9 5 4 73 | * pivot = 4,storeInd = 0, i = 0 74 | * 用i做该数组的遍历: 75 | * 比较该数是否比pivot大 76 | * 是 ---> storeInd 与 i 位置的元素交换,且storeInd++ 77 | * 第一轮:i = 0,storeInd = 0, 3 与其本身做交换 78 | * 第二轮:i = 4, storeInd = 1, 7与2交换 79 | * 3 2 8 5 7 1 9 5 4 80 | * 第三轮:i = 5, storeInd = 2, 8与1交换 81 | * 3 2 1 5 7 8 9 5 4 82 | * 83 | * storeInd = 3,此后没有小于pivot的数,结束此次循环 84 | * 此时,storeInd的数与pivot的数进行交换 85 | * 3 2 1 4 7 8 9 5 5 86 | * 87 | * 下轮递归执行: 88 | * [3, 2, 1]与[7, 8, 9, 5, 5] 89 | * */ 90 | function quickSortionInPlace(array, n) { 91 | __quickSortionInPlace(array, 0, n - 1) 92 | } 93 | function __quickSortionInPlace(array, l, r) { 94 | if (l >= r) return; 95 | 96 | var mid = __partition(array, l, r) 97 | __quickSortionInPlace(array, l, mid) 98 | __quickSortionInPlace(array, mid + 1, r) 99 | } 100 | // 返回j,使得arr[l, ... j-1) < arr[j] ; arr[j+1 ... r] > arr[j] 101 | function __partition(array, l, r) { 102 | var provit = array[l] 103 | var j = l 104 | for (var i = l + 1; i <= r; i++) 105 | if (array[i] < provit) 106 | swap(array, ++j, i) 107 | swap(array, l, j) 108 | return j 109 | } 110 | var example1 = productRand(1, 100, n) 111 | console.log('Before sorting:' + example1.toString()) 112 | quickSortionInPlace(example1, n) 113 | console.log('after sorting: ' + example1.toString()) 114 | 115 | // 算法的一点点小优化 116 | var quickSortDiggingReform = function (arr) { 117 | var i = 0, len = arr.length, j = len - 1, norm = arr[i]; 118 | if (len <= 1) return []; 119 | 120 | while (i < j) { 121 | 122 | while (i < j && arr[j] >= norm) j--; 123 | if (i < j) 124 | arr[i++] = arr[j]; 125 | 126 | while (i < j && arr[i] < norm) i++; 127 | if (i < j) 128 | arr[j--] = arr[i]; 129 | 130 | } 131 | arr[i] = norm; 132 | var left = arr.slice(0, i + 1); 133 | var right = arr.slice(i + 1); 134 | return quickSortDiggingReform(left).concat(arr[i], quickSortDiggingReform(right)); 135 | } 136 | 137 | console.log("quickSortDiggingReform: " + quickSortDiggingReform(arr)); 138 | -------------------------------------------------------------------------------- /Algorithm/Sortion/quickSortionThreeWay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 快排三路排序 3 | * 原理:先设立一个基准数,分别维护小于基准数,等于基准数,大于基准数,这三个区间 4 | * Created by 海枯 on 2017/7/2. 5 | */ 6 | var {productRand, swap} = require('./sortHelper') 7 | 8 | function __partition(array, l, r) { 9 | var randIdx = l + ~~((r - l + 1) * Math.random()) 10 | swap(array, l, randIdx) 11 | 12 | var e = array[l] 13 | var lt = l // arr[l+1 ... lt] < v 14 | var gt = r + 1 // arr[gt ... r] > v 15 | var i = l + 1 // arr[lt + 1 ... i) == v 16 | 17 | while (i < gt) { 18 | if (array[i] < e) { 19 | swap(array, lt + 1, i) 20 | lt++ 21 | i++ 22 | } else if (array[i] > e) { 23 | swap(array, gt - 1, i) 24 | gt-- 25 | } else { 26 | i++ 27 | } 28 | } 29 | swap(array, l, lt) 30 | return lt 31 | } 32 | 33 | function __quickSortion(array, l, r) { 34 | if (l >= r) return 35 | 36 | var v = __partition(array, l, r) 37 | __quickSortion(array, l, v - 1) 38 | __quickSortion(array, v + 1, r) 39 | } 40 | 41 | function quickSortionTH(array, n) { 42 | __quickSortion(array, 0, n - 1) 43 | } 44 | 45 | var n = 100 46 | var example1 = productRand(0, 100, n) 47 | console.log('beforeSortion: ' + example1.toString()) 48 | 49 | quickSortionTH(example1, n) 50 | 51 | console.log('afterSortion: ' + example1.toString()) -------------------------------------------------------------------------------- /Algorithm/Sortion/quickSortionTwoWay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 双路快排: 3 | * 利用两个变量做标记,这两个变量分别位于最前和最后的索引位置 4 | * 最前的索引寻找比他大的数,最后的索引寻找比大小的数,交换位置, 5 | * 不断重复以上过程 6 | * Created by 海枯 on 2017/7/2. 7 | */ 8 | var {productRand, swap} = require('./sortHelper') 9 | 10 | function __partition(array, l, r) { 11 | // 取数组随机元素作为基准数,并与第一个元素交换位置 12 | var privotIdx = l + ~~((r - l + 1) * Math.random()) 13 | swap(array, l, privotIdx) 14 | 15 | var i = l + 1, j = r 16 | while (true) { 17 | while (i <= r && array[i] < array[l]) i++ 18 | while (j >= l + 1 && array[j] > array[l]) j-- 19 | if (i >= j) break 20 | swap(array, i, j) 21 | // 上一个i++不符合要求,所以要再下一个元素 22 | i++ 23 | j-- 24 | } 25 | swap(array, l, j) 26 | return j 27 | } 28 | function __quickSort(array, l, r) { 29 | if (l >= r) return 30 | var i = __partition(array, l, r) 31 | // 对基准左边的元素排序 32 | __quickSort(array, l, i - 1) 33 | // 对基准右边的元素排序 34 | __quickSort(array, i + 1, r) 35 | } 36 | 37 | function quickSortionTW(array, n) { 38 | __quickSort(array, 0, n - 1) 39 | } 40 | 41 | var n = 100 42 | var example1 = productRand(0, 100, n) 43 | console.log('beforeSortion: ' + example1.toString()) 44 | 45 | quickSortionTW(example1, n) 46 | 47 | console.log('afterSortion: ' + example1.toString()) -------------------------------------------------------------------------------- /Algorithm/Sortion/radixSortion.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/6/25. 3 | * 基数排序原理: 4 | * 利用了队列的思想: 5 | * 首先按照个位进行排序,将排序结果放在0-9的盒子中 6 | * 依次从0-9盒子中取出来,对十位及以上的数字进行排序 7 | * 最终得到的数字就是排好序的结果 8 | */ 9 | 10 | // 构建queue队列类 11 | function Queue() { 12 | this.dataStore = [] 13 | this.length = 0 14 | } 15 | 16 | Queue.constructor = Queue 17 | Queue.prototype = { 18 | enqueue (element) { 19 | this.dataStore.push(element) 20 | this.length++ 21 | }, 22 | dequeue () { 23 | this.length-- 24 | return this.dataStore.shift() 25 | } 26 | } 27 | 28 | /** 29 | * 基数排序--根据位数的大小加入队列中 30 | * @param nums 要排序的数字 31 | * @param queues 队列数组 32 | * @param type 位数,0表示个位,1表示十位... 33 | */ 34 | function enqueue(nums, queues, type) { 35 | for (var i = 0; i < nums.length; i++) { 36 | // 当前位的数字 37 | var radixNum = nums[i] / Math.pow(10, type) % 10 38 | queues[Math.floor(radixNum)].enqueue(nums[i]) 39 | } 40 | dequeue(nums, queues) 41 | } 42 | 43 | /** 44 | * 基数排序--将队列中的结果更新到原数组中 45 | * @param nums 46 | * @param queues 47 | */ 48 | function dequeue(nums, queues) { 49 | var i = 0, j = 0 50 | while (j < queues.length) { 51 | while (queues[j].length > 0) { 52 | nums[i++] = queues[j].dequeue() 53 | } 54 | j++ 55 | } 56 | } 57 | 58 | /** 59 | * 求数组中最大元素的长度 60 | * @param nums 61 | * @returns {number} 62 | */ 63 | function maxLen(nums) { 64 | var max = 0 65 | for (var i = 0; i < nums.length; i++) 66 | if (max < nums[i].toString().length) 67 | max = nums[i].toString().length 68 | 69 | return max 70 | } 71 | 72 | function radixSortion(nums) { 73 | var queues = [], 74 | maxLength = maxLen(nums) 75 | // 创建10个桶 76 | for (var i = 0; i < 10; i++) 77 | queues[i] = new Queue() 78 | // 从最低位排到最高位 79 | for (var k = 0; k < maxLength; k++) 80 | enqueue(nums, queues, k) 81 | 82 | return nums 83 | } 84 | 85 | (function () { 86 | var nums = [] 87 | for (var rand = 0; rand < 15; rand++) { 88 | nums[rand] = Math.ceil(Math.random() * 1000) 89 | } 90 | console.log(radixSortion(nums)) 91 | })() 92 | -------------------------------------------------------------------------------- /Algorithm/Sortion/selectionSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/4/18. 3 | * 4 | * 选择排序: 5 | * 基本原理:首先在未排序的序列中找到最小(最大)元素,存放到排序序列的起始位置, 6 | * 然后再从剩余未排序元素中继续寻找最小(最大)元素,然后放到已排序序列的末尾。 7 | */ 8 | 9 | function selectionSort(arr) { 10 | var cp = arr.slice(); 11 | 12 | for (var i = 0; i < cp.length; i++) { 13 | var curr = cp[i], 14 | shuffle = cp.slice(i), 15 | min = Math.min.apply(null, shuffle), 16 | minInd = cp.indexOf(min), 17 | temp; 18 | 19 | if (shuffle.length > 1 && min !== curr) { 20 | temp = cp[minInd]; 21 | cp[minInd] = curr; 22 | cp[i] = temp; 23 | } 24 | } 25 | return cp; 26 | } 27 | 28 | function selectionSortNoMin(arr) { 29 | var cp = arr.slice(), 30 | min, 31 | minInd, 32 | temp 33 | ; 34 | 35 | for (var i = 0; i < cp.length; i++) { 36 | min = cp[i]; 37 | minInd = i; 38 | 39 | for (var j = i + 1; j < cp.length; j++) { 40 | temp = cp[j]; 41 | if (temp < min) { 42 | min = temp; 43 | minInd = j; 44 | } 45 | } 46 | 47 | if (i !== minInd) { 48 | temp = cp[i]; 49 | cp[minInd] = temp; 50 | cp[i] = min; 51 | } 52 | 53 | } 54 | 55 | return cp; 56 | } 57 | 58 | console.log(selectionSort([8, 5, 2, 6, 9, 3, 1, 4, 0, 7])); 59 | 60 | console.log(selectionSortNoMin([8, 5, 2, 6, 9, 3, 1, 4, 0, 7])); -------------------------------------------------------------------------------- /Algorithm/Sortion/shellSort.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/4/18. 3 | * 4 | * 希尔排序原理: 5 | * 希尔排序是直接插入排序一种高效的改进版本,它的做法不是每次一个元素挨着一个元素的比较。 6 | * 通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。 7 | * 然后算法再取越来越小的步长排序,算法的最后一步就是普通的插入排序。 8 | * 9 | * 算法思路: 10 | * 1. 先取一个正整数d1(d1= 1)位置,即所有记录成为一个组, 14 | * 最后对这个组进行插入排序。一般选d1约为 n / 2,d2 为 d1 / 2, d3为 d2 / 2, ... , di = 1 15 | */ 16 | 17 | function swap(arr, i, k) { 18 | var temp = arr[i]; 19 | arr[i] = arr[k]; 20 | arr[k] = temp; 21 | } 22 | 23 | function shellSort(arr) { 24 | var swapCount = 0; 25 | 26 | var cp = arr.slice(), 27 | len = cp.length, 28 | gap = Math.floor(len / 2); 29 | 30 | while (gap > 0) { 31 | for (var i = gap; i < len; i++) { 32 | /*if (cp[i] < cp[i - gap]) { 33 | swap(cp, i, i - gap); 34 | }*/ 35 | for (var j = i; j > 0; j -= gap) { 36 | if (cp[j] < cp[j - gap]) { 37 | swap(cp, j - gap, j); 38 | swapCount++; 39 | } else { 40 | break; 41 | } 42 | } 43 | } 44 | gap = Math.floor(gap / 2); 45 | } 46 | console.log("shellSort move's number:"+swapCount); 47 | return cp; 48 | } 49 | 50 | function directInsertionSort(arr) { 51 | var cp = arr.slice(), 52 | leng = cp.length, 53 | temp, 54 | swapCount = 0; 55 | 56 | for (var i = 1; i < leng; i++) { 57 | temp = cp[i]; 58 | 59 | for (var j = i; j >= 0; j--) { 60 | swapCount++; 61 | if (cp[j - 1] > temp) { 62 | cp[j] = cp[j - 1]; 63 | } else { 64 | cp[j] = temp; 65 | break; 66 | } 67 | } 68 | } 69 | console.log("directInsertionSort move's number:" + swapCount); 70 | return cp; 71 | } 72 | var arr = [8, 5, 2, 6, 9, 3, 1, 4, 0, 7]; 73 | var arr1 = [5, 4, 3, 2, 1, 0]; 74 | 75 | 76 | console.log(directInsertionSort(arr)); 77 | 78 | console.log(shellSort(arr)); 79 | 80 | console.log(directInsertionSort(arr1)); 81 | console.log(shellSort(arr1)); -------------------------------------------------------------------------------- /Algorithm/Sortion/sortHelper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/7/2. 3 | */ 4 | module.exports = { 5 | productRand (min, max, n) { 6 | var arr = new Array(n) 7 | for (var i = 0; i < n; i++) { 8 | arr[i] = ~~(Math.random() * (max - min)) + min 9 | } 10 | return arr 11 | }, 12 | swap (array, i, j) { 13 | var temp = array[i] 14 | array[i] = array[j] 15 | array[j] = temp 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Algorithm/Sortion/sortNotAllowMerge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017-5-10fanpu/5/9. 3 | * 合并两个数组,要求先排序后合并 4 | * 5 | * 原理:间接利用了归并排序的思想, 6 | * 先将两数组排好序,再合并排序 7 | */ 8 | 9 | function mergeSort(arr) { 10 | if (arr.length == 1) return arr; 11 | 12 | var mid = Math.floor(arr.length / 2), 13 | left = arr.slice(0, mid), 14 | right = arr.slice(mid); 15 | 16 | return merge(mergeSort(left), mergeSort(right)); 17 | } 18 | 19 | function merge(left, right) { 20 | var lInd = 0, rightInd = 0, arr = []; 21 | while(lInd != left.length && rightInd != right.length) { 22 | if (left[lInd] < right[rightInd]) { 23 | arr.push(left[lInd++]) 24 | } else { 25 | arr.push(right[rightInd++]) 26 | } 27 | } 28 | return arr.concat((lInd == left.length ? right.slice(rightInd) : left.slice(lInd))) 29 | } 30 | 31 | var left = [4, 2, 5, 3], right = [8, 6, 10, 2] 32 | 33 | console.log(merge(mergeSort(left), mergeSort(right))); 34 | -------------------------------------------------------------------------------- /Algorithm/dataStructures/BFPRT.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/9. 3 | */ 4 | /** 5 | * 查找第n大的值(查找第n小的值) 6 | * @constructor 7 | */ 8 | 9 | var {swap} = require('../Sortion/sortHelper') 10 | function Bfprt(arr, left, right, k) { 11 | var midInmidIdx = getProvitIdx(arr, left, right, k) 12 | var partIdx = partition(arr, left, right, midInmidIdx) 13 | 14 | // (+1表示最大为第1大,没有第0大) 15 | var num = partIdx - left + 1 16 | if (num == k) 17 | return partIdx 18 | else if (num > k) 19 | return Bfprt(arr, left, partIdx - 1, k) 20 | else 21 | return Bfprt(arr, partIdx + 1, right, k - num) 22 | } 23 | 24 | function getProvitIdx(arr, left, right) { 25 | if (right - left < 5) 26 | return insertSortReturnMid(arr, left, right) 27 | else { 28 | var midSwap = left 29 | for (var i = left; i + 4 <= right; i += 5) { 30 | var partMid = insertSortReturnMid(arr, i, i + 4) 31 | swap(arr, midSwap++, partMid) 32 | } 33 | return Bfprt(arr, left, midSwap - 1, (midSwap - 1 - left >> 1) + 1) 34 | } 35 | } 36 | 37 | function insertSortReturnMid(arr, left, right) { 38 | for (var i = left + 1; i <= right; i++) { 39 | var j = i - 1 40 | var ele = arr[i] 41 | while (j >= left && ele < arr[j]) 42 | arr[j + 1] = arr[j--] 43 | arr[j + 1] = ele 44 | } 45 | return (left + right) >> 1 46 | } 47 | 48 | function partition(arr, left, right, provitIdx) { 49 | swap(arr, left, provitIdx) 50 | 51 | var provit = arr[left] 52 | var j = left 53 | 54 | for (var i = left + 1; i <= right; i++) { 55 | if (provit > arr[i]) 56 | swap(arr, ++j, i) 57 | } 58 | swap(arr, left, j) 59 | return j 60 | } 61 | 62 | function main() { 63 | var arr1 = [6,5,4,3,1,14,153,1432,1312] 64 | var arr1Idx = Bfprt(arr1, 0, arr1.length-1, 2) 65 | console.log("第2小的数字的索引", arr1Idx) 66 | console.log("第2小的数字", arr1[arr1Idx]) 67 | } 68 | 69 | main() -------------------------------------------------------------------------------- /Algorithm/dataStructures/NumberOf1Between1AndN_Solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/12. 3 | */ 4 | /* 5 |       我们从低位到高位求每位1出现的次数,累加求和即可 6 |         例如:求0~abcde中1的个数,现在我们求c这一位中1出现的次数,其他位雷同 7 |         有两部分组成 8 |         第一部分:ab * 100,表示当ab这两位在0~ab-1范围内时,de可以从0~99取值 9 |           第二部分:如果c>1时,当ab为ab时1的个数为0~99 10 |                   如果c=1时,当ab为ab时1的个数为de + 1 11 |                 如果c<0时,当ab为ab是1的个数为0 12 |     */ 13 | function NumberOf1Between1AndN_Solution(n) { 14 | if (n < 0) return 0; 15 | var high = n, low, temp, cur, num = 0, i = 1; 16 | while (high != 0) { 17 | 18 | var curPow = Math.pow(10, i) 19 | var curPowLess = Math.pow(10, i - 1) 20 | 21 | high = parseInt(n / curPow); 22 | temp = n % curPow; 23 | cur = parseInt(temp / curPowLess); 24 | low = temp % curPowLess; 25 | if (cur === 1) { 26 | num += high * curPowLess + low + 1; 27 | } else if (cur < 1) { 28 | num += high * curPowLess; 29 | } else { 30 | num += (high + 1) * curPowLess; 31 | } 32 | i++; 33 | } 34 | return num; 35 | } 36 | 37 | function NumberOf1Between1AndN_Solution2(n) 38 | { 39 | // write code here 40 | if (n < 0) 41 | return 0 42 | var ans = 1 43 | for (var i = 2; i <= n; i++) { 44 | ans += numberOf1(i) 45 | } 46 | return ans 47 | } 48 | 49 | function numberOf1(n) { 50 | var num = 0 51 | while (n > 0) { 52 | if (n % 10 == 1) 53 | num++ 54 | n = ~~(n / 10) 55 | } 56 | return num 57 | } 58 | console.log(NumberOf1Between1AndN_Solution(21)) 59 | 60 | console.log(NumberOf1Between1AndN_Solution2(21)) -------------------------------------------------------------------------------- /Algorithm/dataStructures/TreeNodeSerializeAndDeserialize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/31. 3 | */ 4 | function TreeNode(x) { 5 | this.val = x; 6 | this.left = null; 7 | this.right = null; 8 | } 9 | 10 | function Serialize(root) { 11 | if (root == null) 12 | return '#' 13 | var arr = [root.val] 14 | return arr.concat(Serialize(root.left), 15 | Serialize(root.right)) 16 | } 17 | 18 | function Deserialize(s) { 19 | if (!s.length) 20 | return null 21 | var n = s.shift() 22 | var root 23 | if (n == '#') 24 | root = null 25 | else { 26 | root = new TreeNode(n) 27 | root.left = Deserialize(s) 28 | root.right = Deserialize(s) 29 | } 30 | return root 31 | } 32 | 33 | var root = new TreeNode(8) 34 | root.left = new TreeNode(6) 35 | root.right = new TreeNode(10) 36 | root.left.left = new TreeNode(5) 37 | root.left.right = new TreeNode(7) 38 | root.right.left = new TreeNode(9) 39 | root.right.right = new TreeNode(11) 40 | 41 | var serialize = Serialize(root) 42 | console.log(serialize) 43 | console.log(Deserialize(serialize)) -------------------------------------------------------------------------------- /Algorithm/dataStructures/bigNumAdd.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/8. 3 | */ 4 | /** 5 | * 大数相加防止溢出 6 | * @param n1 7 | * @param n2 8 | */ 9 | function bigNumAdd(n1, n2) { 10 | 11 | // 考虑到应从个位数相加,故个位数应为第0个元素 12 | var numToArr1 = n1.toString().split('').reverse() 13 | var numToArr2 = n2.toString().split('').reverse() 14 | 15 | // 补0 16 | var far = numToArr1.length - numToArr2.length 17 | var shouldAddZero = far < 0 18 | ? numToArr1 19 | : numToArr2 20 | for (var k = 0; k < Math.abs(far);k++) 21 | shouldAddZero.push(0) 22 | 23 | var len = numToArr1.length 24 | // 存储结果的数组,考虑到最大一位有进位时最终结果会多一位数 25 | var result = new Array(len + 1).fill(0) 26 | 27 | var i 28 | for (i = 0; i < len; i++) { 29 | result[i] = result[i] + +numToArr1[i] + +numToArr2[i] 30 | result[i + 1] = Math.floor(result[i] / 10) 31 | result[i] = result[i] % 10 32 | } 33 | 34 | //去除最高位的0 35 | if (result[result.length-1] == 0) 36 | result.pop() 37 | // print 38 | console.log(result.reverse().join('')) 39 | } 40 | 41 | bigNumAdd(222, 333) 42 | bigNumAdd(222, 999) 43 | bigNumAdd(222, 9999) -------------------------------------------------------------------------------- /Algorithm/dataStructures/deleteListNodeDuplication.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/31. 3 | * 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 4 | * 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 5 | */ 6 | function ListNode(x) { 7 | this.val = x; 8 | this.next = null; 9 | } 10 | 11 | // 初始化数据 12 | ListNode.prototype.init = function (arr, refs) { 13 | if (!arr.length) 14 | return this 15 | 16 | let lastE = arr.shift() 17 | let newRet = new ListNode(lastE); 18 | (refs || this).next = newRet 19 | return this.init(arr, newRet) 20 | } 21 | 22 | /** 23 | * 基本思路:先用prev记录上一个不重复的节点 24 | * 当有元素重复时,一直找到重复元素的最后一个元素, 25 | * 这时将prev.next指向最后一个重复元素的next。 26 | * 另外注意处理边界的情况 27 | * @param p 链表的head 28 | * @returns {*} 处理后链表的head 29 | */ 30 | function deleteDuplication(p) { 31 | // write code here 32 | if (p == null || p.next == null) 33 | return p 34 | let headIsSet = false, retHead = null 35 | let run = p, prev = null 36 | while (run != null) { 37 | if (run.next == null || run.val != run.next.val) { 38 | if (!headIsSet) { 39 | retHead = run 40 | headIsSet = true 41 | } 42 | prev = run 43 | run = run.next 44 | } else { 45 | while (run.next != null && run.val == run.next.val) 46 | run = run.next; 47 | if (prev == null) { 48 | retHead = run.next 49 | run = run.next 50 | } else { 51 | prev.next = run.next; 52 | run = prev.next 53 | } 54 | } 55 | 56 | } 57 | return retHead 58 | } 59 | 60 | let link1 = new ListNode(1).init([2, 3, 3, 4, 4, 5]) 61 | let link2 = new ListNode(2).init([2, 2, 3, 3, 4, 4, 5]) 62 | let link3 = new ListNode(1).init([2, 3, 3, 4, 4, 5, 5]) 63 | console.log(deleteDuplication(link1)) 64 | console.log(deleteDuplication(link2)) 65 | console.log(deleteDuplication(link3)) -------------------------------------------------------------------------------- /Algorithm/dataStructures/findLeftOfLtRightOfGt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/18. 3 | */ 4 | 5 | /** 6 | * 找出数组里面比前面都小,后面都大的数 7 | * 时间复杂度O(N),空间复杂度O(N) 8 | * 思路:从左到右找到遍历到该元素时的最大元素存进一个数组中。 9 | * 另一个数组装着从右到左遍历时最小的元素。 10 | * 最后如果两个数组对应位置的数字一样,这个数就符合题意 11 | * @param arr 12 | */ 13 | function findLeftOfLtRightOfGt(arr) { 14 | var i, len = arr.length 15 | 16 | var leftToRightMax = new Array(len) 17 | var rightToLeftMin = new Array(len) 18 | 19 | for (i = 0; i < len; i++) { 20 | if (i == 0) 21 | leftToRightMax[i] = arr[i] 22 | else 23 | leftToRightMax[i] = Math.max(arr[i], leftToRightMax[i - 1]) 24 | } 25 | 26 | for (i = len - 1; i >= 0; i--) { 27 | if (i == len - 1) 28 | rightToLeftMin[i] = arr[i] 29 | else 30 | rightToLeftMin[i] = Math.min(arr[i], rightToLeftMin[i + 1]) 31 | } 32 | 33 | var j = 0 34 | var ans = [] 35 | while (j < len) { 36 | if (leftToRightMax[j] == rightToLeftMin[j]) { 37 | ans.push(arr[j]) 38 | } 39 | j++ 40 | } 41 | return ans 42 | } 43 | console.log(findLeftOfLtRightOfGt([1, 3, 2, 4, 5, 9, 8])) 44 | -------------------------------------------------------------------------------- /Algorithm/dataStructures/isPalindrome.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/6/25. 3 | * 利用栈判断是否为回文的原理: 4 | * 首先将字符串从左到右入栈。 5 | * 出栈时将出栈元素跟字符串第N个元素比较,任意一个不相同则不是回文 6 | */ 7 | 8 | function Stack() { 9 | this.dataStore = [] 10 | this.top = 0 11 | this.length = () => this.top 12 | } 13 | 14 | Stack.constructor = Stack 15 | Stack.prototype = { 16 | push (ele) { 17 | this.dataStore[this.top++] = ele 18 | }, 19 | // 模拟过程,其实没有改变dataStore 20 | pop () { 21 | return this.dataStore[--this.top] 22 | } 23 | } 24 | 25 | function isPalindrome(string) { 26 | let i, 27 | stack = new Stack(), 28 | totalLen = string.length 29 | for (i = 0; i < totalLen; i++) 30 | stack.push(string[i]) 31 | 32 | while (stack.length() > Math.floor(totalLen / 2)) { 33 | if (string[totalLen - stack.length()] != stack.pop()) 34 | return false 35 | } 36 | return true 37 | } 38 | 39 | console.log(isPalindrome('abba')) // true 40 | console.log(isPalindrome('hello')) // false 41 | console.log(isPalindrome('racecar')) // true 42 | -------------------------------------------------------------------------------- /Algorithm/dataStructures/noStructReverseStack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/18. 3 | */ 4 | 5 | /** 6 | * 不用存储空间,反转一个栈 7 | * 思路: 8 | * 假设栈[1,2,3,4] 9 | * 整体思想是把栈底元素取出来,保存在递归变量里面,然后一步步把tmp变量push进来 10 | * 流程: 11 | * i = 0,tmp = 1 stack = [2, 3, 4] 12 | * i = 1,tmp = 2 stack = [3, 4] 13 | * i = 2,tmp = 3 stack = [4] 14 | * i = 3,tmp = 4 stack = [] 15 | * @param stack 16 | */ 17 | function noUseStorgeReverseStack(stack) { 18 | if (stack.length == 0) 19 | return; 20 | var last = getLastElement(stack) 21 | noUseStorgeReverseStack(stack) 22 | stack.push(last) 23 | } 24 | 25 | function getLastElement(stack) { 26 | var pop = stack.pop() 27 | if (stack.length == 0) 28 | return pop; 29 | else { 30 | var last = getLastElement(stack) 31 | stack.push(pop) 32 | return last 33 | } 34 | } 35 | 36 | var stack = [1, 2, 5, 8, 10] 37 | noUseStorgeReverseStack(stack) 38 | console.log(stack) -------------------------------------------------------------------------------- /Algorithm/dataStructures/radixConvert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/6/19. 3 | * 4 | * 十进制转换为N进制采用了栈的思想 5 | */ 6 | 7 | function Stack(init) { 8 | this.dataStore = init || [] 9 | // 栈顶元素位置 10 | this.top = (init && init.length) || 0 11 | // 栈顶元素 12 | this.peek = () => this.dataStore[this.top - 1] 13 | this.length = () => this.top 14 | } 15 | Stack.constructor = Stack 16 | 17 | Stack.prototype = { 18 | push (ele) { 19 | this.dataStore[this.top++] = ele 20 | }, 21 | pop () { 22 | return this.dataStore[--this.top] 23 | }, 24 | clear () { 25 | this.dataStore = [] 26 | this.top = 0 27 | } 28 | } 29 | 30 | // 十进制转N进制具体代码实现 31 | function numToN(num, n) { 32 | // 8 % 2 = 0, 8 / 2 = 4 33 | // 4 % 2 = 0, 4 / 2 = 2 34 | // 2 % 2 = 0, 2 / 2 = 1 35 | // 1 % 2 = 1, 1 / 2 = END 36 | 37 | let stack = new Stack(), mod, converted 38 | 39 | do { 40 | mod = num % n 41 | stack.push(mod) 42 | num = num / n 43 | } while (num >= 1) 44 | 45 | converted = '' 46 | while (stack.length() > 0) 47 | converted += stack.pop() 48 | return converted 49 | } 50 | // 将十进制八进制为二进制 51 | let result = numToN(8, 2) 52 | console.log(result) 53 | 54 | -------------------------------------------------------------------------------- /Algorithm/dataStructures/reverseLinkNode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/4/23. 3 | */ 4 | function LinkList(val) { 5 | this.val = val 6 | this.next = null 7 | } 8 | function DoubleLinkList(val) { 9 | this.val = val 10 | this.prev = null 11 | this.next = null 12 | } 13 | 14 | function reserveLinkNode(root) { 15 | if (root == null || root.next == null) 16 | return root 17 | var prev = null, cur = root, n = root.next 18 | while (cur) { 19 | cur.next = prev 20 | prev = cur 21 | cur = n 22 | n = n && n.next 23 | } 24 | return prev 25 | } 26 | 27 | var l1 = new LinkList(1) 28 | var l2 = new LinkList(3) 29 | var l3 = new LinkList(5) 30 | l1.next = l2 31 | l2.next = l3 32 | 33 | console.log(reserveLinkNode(l1)) 34 | 35 | function reserveDoubleLinkNode(root) { 36 | if (root == null || root.next == null) 37 | return root 38 | var pre = null, cur = root, n = root.next 39 | while (cur) { 40 | cur.next = pre 41 | if (pre) 42 | pre.prev = cur 43 | pre = cur 44 | cur = n 45 | n = n && n.next 46 | } 47 | pre.prev = null 48 | return pre 49 | } 50 | 51 | var r1 = new DoubleLinkList(1) 52 | var r2 = new DoubleLinkList(3) 53 | var r3 = new DoubleLinkList(5) 54 | r1.next = r2 55 | r2.prev = r1 56 | r2.next = r3 57 | r3.prev = r2 58 | 59 | console.log(reserveDoubleLinkNode(r1)) -------------------------------------------------------------------------------- /Algorithm/inverseOrderPair.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 逆序对: 3 | * 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。 4 | * 输入:1,2,3,4,5,6,7,0 5 | * 输出:7 6 | * Created by 海枯 on 2017/8/19. 7 | */ 8 | 9 | var cnt; 10 | 11 | function InversePairs(array) { 12 | cnt = 0; 13 | if (array != null) 14 | mergeSortUp2Down(array, 0, array.length - 1); 15 | return cnt; 16 | } 17 | 18 | /** 19 | * 归并排序(从上往下) 20 | * @param a 21 | * @param start 22 | * @param end 23 | */ 24 | function mergeSortUp2Down(a, start, end) { 25 | if (start >= end) 26 | return; 27 | var mid = (start + end) >> 1; 28 | 29 | mergeSortUp2Down(a, start, mid); 30 | mergeSortUp2Down(a, mid + 1, end); 31 | 32 | merge(a, start, mid, end); 33 | } 34 | 35 | /** 36 | * 将一个数组中的两个相邻有序区间合并成一个 37 | * @param a 38 | * @param start 39 | * @param mid 40 | * @param end 41 | */ 42 | function merge(a, start, mid, end) { 43 | // 记录tmp数组便于更新arr原数组的值 44 | var tmp = new Array(end - start + 1) 45 | 46 | var i = start, j = mid + 1, k = 0; 47 | // 只要有一边超过了边界就跳出 48 | while (i <= mid && j <= end) { 49 | if (a[i] <= a[j]) 50 | // 按照数字的顺序将数存进tmp数组中 51 | tmp[k++] = a[i++]; 52 | else { 53 | tmp[k++] = a[j++]; 54 | // 当前左数组序号与最后一个序号相差多少,即得出有多少数比他大 55 | // 如左:1 2 3 4,右:0 5 6 7。 56 | // 第一比较回合:左1与右0,当比较到左1>左0时,表示左的后面都比0大, 57 | // 因为左右都是递增数组,既然左边第1个元素都比右边1大,那么左边的所有元素也肯定比右1大。 58 | cnt += mid - i + 1;  // core code, calculate InversePairs............ 59 | } 60 | } 61 | // 填充左右比较数组没有加进来的元素 62 | while (i <= mid) 63 | tmp[k++] = a[i++]; 64 | while (j <= end) 65 | tmp[k++] = a[j++]; 66 | // 更新原数组 67 | for (k = 0; k < tmp.length; k++) 68 | a[start + k] = tmp[k]; 69 | } 70 | 71 | console.log(InversePairs('1,2,3,4,5,6,7,0'.split(','))) 72 | 73 | function FindGreatSum(array) { 74 | var size = array.length; 75 | var max = array[0]; 76 | var tmp = max; 77 | for (var i = 1; i < size; i++) { 78 | var item = array[i]; 79 | if (tmp >= 0) 80 | tmp += item 81 | else 82 | tmp = item 83 | if (tmp > max) 84 | max = tmp 85 | } 86 | return max; 87 | } 88 | console.log(FindGreatSum([2, 8, 1, 5, 9])) -------------------------------------------------------------------------------- /Algorithm/leetCode/NO.103-zigzagLevelOrder.js: -------------------------------------------------------------------------------- 1 | const { buildTreeNode } = require('../util/treeNode') 2 | 3 | /** 4 | * Definition for a binary tree node. 5 | * function TreeNode(val) { 6 | * this.val = val; 7 | * this.left = this.right = null; 8 | * } 9 | */ 10 | /** 11 | * 题解: 12 | * 1. DFS的解题要点:想办法在level层数上做文章 13 | * 2. BFS的解题要点:在层级遍历的末尾加分隔符(如null) 14 | * @param {TreeNode} root 15 | * @return {number[][]} 16 | */ 17 | const zigzagLevelOrder = (root) => { 18 | let ans = [] 19 | const traversal = (root, result, level = 0) => { 20 | if (root == null) return 21 | if (result.length === level) { 22 | result[level] = [] 23 | } 24 | if (level % 2 === 0) { 25 | result[level].push(root.val) 26 | } else { 27 | result[level].unshift(root.val) 28 | } 29 | 30 | traversal(root.left, result, level + 1) 31 | traversal(root.right, result, level + 1) 32 | } 33 | traversal(root, ans) 34 | return ans 35 | } 36 | 37 | const example1TreeNode = buildTreeNode([3,9,20,null,null,15,7]) 38 | console.log(zigzagLevelOrder(example1TreeNode)) -------------------------------------------------------------------------------- /Algorithm/leetCode/NO.41-firstMissingPosition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * in-place法:将数组的值交换到对应的下标下,如果对应的下标没有值,说明是缺失的元素 3 | * @param {number[]} nums 4 | * @return {number} 5 | */ 6 | const swap = (arr, i, j) => { 7 | const tmp = arr[i] 8 | arr[i] = arr[j] 9 | arr[j] = tmp 10 | } 11 | 12 | const firstMissingPositive = (nums) => { 13 | if (nums.length < 1) return 1 14 | for (let i = 0;i < nums.length;i++) { 15 | while (nums[i] > 0 && nums[i] <= nums.length && nums[nums[i] - 1] !== nums[i]) { 16 | swap(nums, i, nums[i] - 1) 17 | } 18 | } 19 | 20 | for (let j = 0;j < nums.length;j++) { 21 | if (j + 1 !== nums[j]) { 22 | return j + 1 23 | } 24 | } 25 | return nums.length + 1 26 | }; 27 | 28 | console.log(firstMissingPositive([1])) 29 | console.log(firstMissingPositive([1,2,0])) 30 | console.log(firstMissingPositive([3,4,-1,1])) 31 | console.log(firstMissingPositive([7,8,9,11,12])) -------------------------------------------------------------------------------- /Algorithm/leetCode/NO.82.js: -------------------------------------------------------------------------------- 1 | const { buildLinkNode, ListNode } = require('../util/linkNode') 2 | 3 | /** 4 | * 题解:三指针法: 5 | * 1. 先建立一个假元素,装着最终链表的头指针 6 | * 2. 建立2个变量,l与r,当l与r相同时,r一直往最右侧移动 7 | * 3. 如果l与r相等时,说明没有重复节点 8 | * @param {ListNode} head 头结点 9 | */ 10 | var deleteDuplicates = function(head) { 11 | let mock = new ListNode(-1) 12 | const ansHead = mock 13 | 14 | let l = head 15 | let r = head 16 | 17 | while (l) { 18 | while(r.next && r.next.val === l.val) { 19 | r = r.next 20 | } 21 | 22 | if (l === r) { 23 | mock.next = r 24 | mock = r 25 | } 26 | l = r = r.next 27 | } 28 | mock.next = l 29 | return ansHead.next 30 | }; 31 | 32 | const example1 = buildLinkNode([1,2,3,3,4,4,5]) 33 | console.log(deleteDuplicates(example1)) 34 | 35 | const example2 = buildLinkNode([2,2,3,3]) 36 | console.log(deleteDuplicates(example2)) -------------------------------------------------------------------------------- /Algorithm/leetCode/NO.x-remove-repeat-listNode.js: -------------------------------------------------------------------------------- 1 | const { buildLinkNode } = require('../util/linkNode'); 2 | 3 | /** 4 | * 编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。 5 | * @param {ListNode} head 6 | * @return {ListNode} 7 | */ 8 | var removeDuplicateNodes = function(head) { 9 | if (head == null) { 10 | return null 11 | } 12 | const headOrigin = head 13 | let hash = { 14 | [head.val]: 1 15 | } 16 | 17 | while (head.next) { 18 | const nextVal = head.next.val 19 | if (nextVal in hash) { 20 | head.next = head.next.next 21 | } else { 22 | hash[nextVal] = 1 23 | head = head.next 24 | } 25 | } 26 | return headOrigin 27 | }; 28 | 29 | const listNode = buildLinkNode([1,2,3,3,2,1]) 30 | console.log(removeDuplicateNodes(listNode)) -------------------------------------------------------------------------------- /Algorithm/objectFindLess.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/4/17. 3 | * 获取字符串中出现次数最少的字符 4 | */ 5 | function getRareChar(str) { 6 | let hash = {}; 7 | // 将各个字符名字、首次出现位置及出现次数存到hash表 8 | for (let i = 0, len = str.length; i < len; i++) { 9 | // 如果hash[str[i]]不存在,则对其进行初始化 10 | hash[str[i]] = hash[str[i]] || {index: i, count: 0}; 11 | hash[str[i]].count++; // count计数自增 12 | } 13 | // 因为哈希表不好排序,将它转成数组 14 | return Object.keys(hash).map(function (key) { 15 | return Object.assign({char: key}, hash[key]); 16 | // 根据count属性进行升序排序 17 | }).sort(function (a, b) { 18 | return a.count - b.count; 19 | // 取出count最小的 20 | }).filter(function (e, i, arr) { 21 | return e.count === arr[0].count; 22 | // 在count值最小的集合里面再根据index属性进行升序排序 23 | }).sort(function (a, b) { 24 | return a.index - b.index; 25 | })[0].char; 26 | } 27 | // 测试数据 28 | var str = 'ablfdasfdarleoeorwqajhfdsafdlladaasrjhehafdalhewadadfahwesaew'; 29 | console.log(getRareChar(str)); -------------------------------------------------------------------------------- /Algorithm/util/linkNode.js: -------------------------------------------------------------------------------- 1 | function ListNode(val) { 2 | this.val = val; 3 | this.next = null; 4 | } 5 | 6 | const usefulLinkNode = { 7 | ListNode, 8 | buildLinkNode(nodeLists) { 9 | if (nodeLists.length < 1) return null 10 | const headVal = nodeLists.shift() 11 | const headNode = new ListNode(headVal) 12 | headNode.next = usefulLinkNode.buildLinkNode(nodeLists) 13 | return headNode 14 | } 15 | } 16 | 17 | module.exports = usefulLinkNode -------------------------------------------------------------------------------- /Algorithm/util/treeNode.js: -------------------------------------------------------------------------------- 1 | function TreeNode(val) { 2 | this.val = val 3 | this.left = null 4 | this.right = null 5 | } 6 | 7 | const usefulTreeNode = { 8 | TreeNode, 9 | 10 | buildTreeNode(treeArr) { 11 | if (treeArr.length < 1) return null 12 | 13 | let treeRoot = new TreeNode(treeArr.shift()) 14 | let queues = [treeRoot] 15 | 16 | while (treeArr.length) { 17 | const first = queues[0] 18 | const lv = treeArr.shift() 19 | if (lv != null) { 20 | queues.push((first.left = new TreeNode(lv))) 21 | } 22 | 23 | const rv = treeArr.shift() 24 | if (rv != null) { 25 | queues.push(first.right = new TreeNode(rv)); 26 | } 27 | queues.shift() 28 | } 29 | 30 | return treeRoot 31 | } 32 | } 33 | 34 | module.exports = usefulTreeNode 35 | 36 | // [3,9,20,null,null,15,7] 37 | // console.log(usefulTreeNode.buildTreeNode([3,9,20,null,null,15,7])) -------------------------------------------------------------------------------- /ArrayMethods/forEachEffect.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var arr = [3, 3, 5, 1, 6, 9, 1];// arr.length = 7 4 | 5 | /** 6 | * 在iteration方法中,如果在回调数组中为当前数组添加了新的元素,那么那些新的元素是不是遍历到的 7 | * 如果在回调数组中对当前数组进行了其他修改,,比如改变某个元素的值或者删除某个元素,遍历操作会受到未预期的影响 8 | */ 9 | /*arr.forEach(function (p1, p2, p3) { 10 | arr.push(p1 + 1); 11 | console.log(p1); 12 | });*/ 13 | 14 | /** 15 | * 遍历过程 16 | * 1. [3, 3, 5, 1, 6, 9, 1] 17 | * ↑ 18 | * 2. [3, 5, 1, 6, 9, 1] 19 | * ↑ 20 | * 3. [3, 1, 6, 9, 1] 21 | * ↑ 22 | * 4. [3, 1, 9, 1] 23 | * ↑ 24 | * 5. [3, 1, 9] 25 | */ 26 | var copy = arr.slice(); 27 | copy.forEach(function (p1, p2, p3) { 28 | // console.log(p1); 29 | copy.splice(p2, 1); 30 | console.log(p3); 31 | }); 32 | 33 | /* 34 | * 向数组增加元素时,可以接收任意数量的参数,push方法将元素添加到数组的末尾,返回值是增加后数组的元素 35 | * */ 36 | console.log(arr.push(10)); // 8 37 | 38 | /** 39 | * unshift将元素添加到数组的开头,并返回数组的长度 40 | */ 41 | console.log(arr.unshift(11)); 42 | -------------------------------------------------------------------------------- /ArrayMethods/instanceOfBug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 12 | 20 | 21 | -------------------------------------------------------------------------------- /ArrayMethods/otherChain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 |

I'm iframe element

12 | 13 | 16 | -------------------------------------------------------------------------------- /ArrayMethods/reduce.js: -------------------------------------------------------------------------------- 1 | var values = [1, 2, 3, 4, 5]; 2 | 3 | /** 4 | * reduce 的参数为一个回调函数,一个初始值 5 | * 回调函数的参数是 上一次累加的值,当前的元素值,当前值的索引,当前数组 6 | * @type {*} 7 | */ 8 | var sum = values.reduce(function (prev, cur, index, array) { 9 | if (index <= 2) 10 | return prev + cur; 11 | else 12 | return prev; 13 | }, 3); 14 | 15 | /** 16 | * reduceRight的参数与reduce相同,但遍历顺序是从右边开始的 17 | * @type {*} 18 | */ 19 | var rightSum = values.reduceRight(function (prev, cur, index, array) { 20 | if (index <= 2) 21 | return prev + cur; 22 | else 23 | return prev; 24 | }); 25 | 26 | console.log(sum); 27 | 28 | console.log(rightSum); 29 | -------------------------------------------------------------------------------- /ArrayMethods/removes.js: -------------------------------------------------------------------------------- 1 | var arr = [3, 3, 5, 1, 6, 9, 1];// arr.length = 7 2 | 3 | /* 4 | * shift方法用于删除数组头部的元素,返回值为该元素的值,如果数组为空,将返回undefined 5 | * */ 6 | 7 | console.log(arr.shift()); // 3 8 | console.log(arr); // [ 3, 5, 1, 6, 9, 1 ] 9 | /* 10 | * pop方法从数组中删除最后一个元素,返回值为该元素的值。 11 | */ 12 | 13 | console.log(arr.pop()); // 1 14 | console.log(arr); // [ 3, 5, 1, 6, 9 ] 15 | -------------------------------------------------------------------------------- /CSS/CSS3/first-child.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | first-child与first-of-type的区别 6 | 15 | 16 | 17 |
18 | 19 | 20 | 111 21 |

222

22 |

333

23 |
24 | 25 | -------------------------------------------------------------------------------- /CSS/CSS3/sticky.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sticky Example 6 | 40 | 41 | 42 |
43 |
44 |
A
45 |
Andrew W.K.
46 |
Apparat
47 |
Arcade Fire
48 |
At The Drive-In
49 |
Aziz Ansari
50 |
51 |
52 |
C
53 |
Chromeo
54 |
Common
55 |
Converge
56 |
Crystal Castles
57 |
Cursive
58 |
59 |
60 |
E
61 |
Explosions In The Sky
62 |
63 |
64 |
T
65 |
Ted Leo & The Pharmacists
66 |
T-Pain
67 |
Thrice
68 |
TV On The Radio
69 |
Two Gallants
70 |
71 |
72 | 73 | -------------------------------------------------------------------------------- /CSS/Flexbox/diagramChart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 32 | 33 | 34 |
35 | 36 | 55 | 56 | -------------------------------------------------------------------------------- /CSS/Flexbox/verticalCenter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | verticalCenter 6 | 28 | 29 | 30 |
31 |
32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /CSS/Problem/zIndexInvalid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | z-index失效的情况 6 | 24 | 25 | 26 |
27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /CSS/ThreeColumnleftRightFixedWidth/flexMethods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左右块自适应,中间固定宽度 6 | 31 | 32 | 33 |
34 |
left
35 |
36 | midmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmidmid 37 |
38 |
right
39 |
40 | 41 | -------------------------------------------------------------------------------- /CSS/ThreeColumnleftRightFixedWidth/floatMethods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左右块自适应,中间固定宽度 6 | 26 | 27 | 28 |
float: left
29 |
float:right
30 |
中间块宽度自适应
31 | 32 | -------------------------------------------------------------------------------- /CSS/ThreeColumnleftRightFixedWidth/grailMethods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 【圣杯布局】左右块自适应,中间固定宽度 6 | 36 | 37 | 38 | 39 |
40 |
center
41 |
left
42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /CSS/ThreeColumnleftRightFixedWidth/positionMethods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左右块自适应,中间固定宽度 6 | 30 | 31 | 32 |
33 |
left
34 |
mid
35 |
right
36 |
37 | 38 | -------------------------------------------------------------------------------- /CSS/ThreeColumnleftRightFixedWidth/wingMethods.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 【双飞翼布局】左右块自适应,中间固定宽度 6 | 34 | 35 | 36 |
37 |
center
38 |
39 |
left
40 | 41 | 42 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-flexbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 22 | 23 | 24 | 25 |
26 |
left
27 |
right
28 |
29 | 30 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-float.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 24 | 25 | 26 | 27 |
28 |
left房间辣椒了简历看了空间了空间来看健康减肥考虑时间了看风景阿里加减肥啦可使肌肤卢卡斯加了
29 |
right房间辣椒了简历看了空间了空间来看健康减肥考虑时间了看风景阿里加减肥啦可使肌肤卢卡斯加了
30 |
31 | 32 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-floatWrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 26 | 27 | 28 |
29 |
RIGHT
30 |
31 |
LEFT
32 | 33 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-grail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 32 | 33 | 34 |
35 |
r
36 |
l
37 |
38 | 39 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-position.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 31 | 32 | 33 | 34 |
35 |
left
36 |
right
37 |
38 | 39 | -------------------------------------------------------------------------------- /CSS/TwoColumnleftRightFixedWidth/leftFixedWidth-wing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 左边固定宽度布局 6 | 29 | 30 | 31 |
32 |
r
33 |
34 |
l
35 | 36 | -------------------------------------------------------------------------------- /CSS/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Background各种属性学习 6 | 20 | 21 | 22 |
200 * 200
23 | 24 | -------------------------------------------------------------------------------- /CSS/mobileAdaptation.md: -------------------------------------------------------------------------------- 1 | # 移动端适配的相关概念以及几种方案总结 2 | 3 | ## 适配相关概念 4 | 5 | 1. **布局视口(layout viewport)**:html元素的上一级容器即顶级容器,用于解决页面在手机上显示的问题。大部分移动设备都将这个视口分辨率设置为`980px`,所以PC上的网页基本上能在手机上呈现,只不过看上去很小,一般默认可以通过手动缩放网页。获取当前布局视口用`document.documentElement.clientWidth` 6 | 2. **视觉视口(visual viewport)**:指用户可见页面区域,即屏幕显示器的物理像素。获取当前的视觉视口可以用`window.innerWidth` 7 | 3. **理想视口(ideal viewport)**:也就是我们通常说的屏幕分辨率。比如Iphone5屏幕分辨率是320。 8 | 9 | ## 使用viewport元标签控制布局 10 | 11 | 如下的viewport元标签的属性 12 | `` 13 | 14 | 以下是每个属性的介绍: 15 | 16 | 属性名 | 取值 | 描述 17 | ------| ----- | ----- 18 | width | 正整数或device-width | 定义**layout viewport**的值 19 | height | 正整数或`device-height` | 定义viewport `height`,单位为像素,一般不用 20 | initial-scale | [0,0 - 10.0] | 定义初始缩放值。比如:设置`initial-width=1.5` 就是将`visual viewport`设置成`ideal viewport`宽度的`1 /1.5倍`。 21 | maximum-scale | [0.0 - 10.0 ] | 用户能够放大的最大比例 22 | minimum-scale | [0,0 - 10.0] | 用户能缩小的最小比例,一般不设置,因为太小的字不方便阅读 23 | user-scalable | yes/no | 定义是否允许用户手动缩放页面,默认值为yes 24 | 25 | `width`的详细介绍:设置为`device-width`时表示`layout viewport`的宽度等于`ideal viewport`的值。同时设置`width`与`intital-scale`时,最终的视口宽度等于两者较大的那一个。也就是说①当`layout viewport`小于`visual viewport`时,视口宽度最终是`visual viewport`的值(经测试,`layout viewport`的值**也会**自动变成`visual viewport`)②当`layout viewport`大于`visual viewport`时,视口宽度最终是`layout viewport`的值(经测试,`visual viewport`的值**不会**变成这时`layout viewport`的值) 26 | 27 | `initial-scale`的详细介绍:**缩放比例 = `ideal layout` / `visual layout`** 。`ideal viewport`是不会改变的,这个值是为了改变`visual viewport`。缩放比例也有默认值,没有设置`initial-scale`时,浏览器会取适当的缩放比例使`布局视口`正好铺满屏幕即有 **可视视口(visual viewport)尺寸=理想视口尺寸(ideal viewport)**。也就是说设置`width=device-width`与设置`initial-scale=1.0`效果相同。 28 | 29 | ## 方案 30 | 31 | 1. 荔枝FM的方案:将`layout viewport`定义为设计稿的宽度,这样的好处在于css像素对应设计稿的px(以640px为例),不需要进行单位换算。但是有几点需要注意的地方。 32 | 1. 为了保证最终的视口的值都是640px,而不会变成其他值(前面说过,最终视口的值会取width与initial-scale属性的最大值)。要把`visual viewport`设置成与`layout viewport`一样大,即设置`initial-scale`的值为 `ideal viewport / 640`。之前也有一个属性代替了这个操作,`target-densitydpi=device-dpi`,但资料显示`target-densitydpi=device-dpi`是一个被抛弃的属性,不推荐使用 33 | 34 | 2. 网易的纯REM方案: 35 | 1. 采用`理想视口`作为`可视视口`的尺寸,只需要把缩放比定为1。`` 36 | 2. 计算 html 元素的 font-size 37 | > 750px 是设计稿的宽度(以iphone6的物理像素数为标准),100是期望的换算比例,即设计稿中 100px 的长度对应css中 1rem,将设计稿中的长度数值除以 100 得到的就是以 rem 为单位的 css 长度的数值,设计稿的宽换算为以 rem 为单位的 css 长度应为 (750/100) rem,同时设计稿的宽对应可视视口的宽,即有 (750/100) rem = 可视视口宽,1 rem = 可视视口宽 * (100/750),(100/750)就是我们要的系数 38 | 39 | 在页面初始化时设置一下 html 元素的 font-size: 40 | 41 | `document.documentElement.style.fontSize = window.innerWidth / 7.5 + 'px';` 42 | 43 | 3. 最后一种方案也是最合理的---来自于手淘的最佳实践 44 | 1. 以上两种方案都存在一个问题,就是在retina屏幕上没有处理`dpr(device pixel ratio)`的副作用,何为`dpr`:`物理像素 / 设备独立的像素(ideal viewport)`。在JS中可以通过`window.devicePixelRatio`获取当前设备的`dpr`。 45 | 2. 为何要处理`dpr`:在retina屏幕上,物理像素会被放大为原本的`dpr`倍。这时候就会存在以下几个问题 46 | - 图片变模糊了 47 | - `border: 1px`问题,边框自然会被放大为`dpr`倍 48 | - ... 49 | 3. 解决方案:使用`initial-scale=1/dpr`对含有px单位的元素做处理,但是单纯这么做会导致字体元素的大小都会缩小。如何解决这个问题呢?答案就是在第二种方案的`根元素设置fontSize`的基础上再乘以一个`dpr`,这样对于以`rem`衡量的元素又能正常适配了。 50 | 51 | 52 | 参考阅读: 53 | - [网易和淘宝移动WEB适配方案再分析](https://zhuanlan.zhihu.com/p/25216275) 54 | - [移动端高清、多屏适配方案](http://div.io/topic/1092) 55 | - [说说移动前端中 viewport (视口)](http://www.css88.com/archives/5975) -------------------------------------------------------------------------------- /CSS/quit/autoHeight.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | top与bottom固定高度,中间内容自适应高度 6 | 27 | 28 | 29 |
30 |
31 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /CSS/quit/line-height-with-diffvalue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | line-height取不同种值的demo 6 | 29 | 30 | 31 |
32 |

33 | Avoid unexpected results by using unitless line-height. 34 | Length and percentage line-heights have poor inheritance behavior ... 35 |

36 |
37 | 38 |
39 |

40 | Avoid unexpected results by using unitless line-height. 41 | Length and percentage line-heights have poor inheritance behavior ... 42 |

43 |
44 | 45 |
46 |

47 | Avoid unexpected results by using unitless line-height. 48 | Length and percentage line-heights have poor inheritance behavior ... 49 |

50 |
51 | 52 | -------------------------------------------------------------------------------- /CSS/quit/positionAutoHeight.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frehaiku/Audition/79e84c6154036a68f082e811f0483dc5a3a3553a/CSS/quit/positionAutoHeight.html -------------------------------------------------------------------------------- /CSS/viewport/firmViewport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 仿荔枝FM 固定layout viewport布局 6 | 16 | 21 | 22 | 23 |

w100 jljlfjal

24 |

w50

25 | 26 | -------------------------------------------------------------------------------- /CSS/zIndexInvalid/createNewStackContext.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSS3 Transform create new stacking context 6 | 36 | 37 | 38 |

CSS3 Transform create new stacking context

39 |
40 |

CSS3 transform create a new stacking context.

41 |

Making child element's z-index effect to the new stacking context.

42 |

When you depend on the default stacking context(Code in HTML), CSS3 transform maybe let you in trouble.

43 |

To avoid this:

44 |

Please remove CSS3 transform after transform end.

45 |
46 | 47 |

Example

48 | 49 |
50 | parent element (default stacking context) 51 |
52 | child element z-index: 2 53 |

54 |
.top-el {position: absolute; z-index: 2;}
55 |
56 |
57 |
58 |



59 | sibling element z-index: 1 60 |
.bottom-el {position: absolute; z-index: 1;}
61 |
62 | 93 | 94 | -------------------------------------------------------------------------------- /CSS/zIndexInvalid/parentChildRelative.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 父子关系时,失效 6 | 26 | 27 | 28 |
29 |
30 |
31 | 32 | -------------------------------------------------------------------------------- /CSS/zIndexInvalid/sameLevelSmallThanChild.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | zIndex失效的情况---相同层级下,小zIndex的子级Zindex很大(却不起作用) 6 | 28 | 29 | 30 |
31 |
32 |
33 |
我是设置了zIndex为999的文本段落
34 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /DOM/JS/lazyLoad.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/5/25. 3 | */ 4 | window.onload = function() { 5 | 6 | var placeholder = document.querySelector('.placeholder'), 7 | small = placeholder.querySelector('.img-small') 8 | 9 | // 1: load small image and show it 10 | var img = new Image(); 11 | img.src = small.src; 12 | img.onload = function () { 13 | small.classList.add('loaded'); 14 | }; 15 | 16 | // 2: load large image 17 | var imgLarge = new Image(); 18 | imgLarge.src = placeholder.dataset.large; 19 | imgLarge.onload = function () { 20 | imgLarge.classList.add('loaded'); 21 | }; 22 | placeholder.appendChild(imgLarge); 23 | } -------------------------------------------------------------------------------- /DOM/JS/lazyLoadI.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/7. 3 | */ 4 | window.onload = init 5 | 6 | let timer, debTimer; 7 | // 节流 8 | function throttle(fn, interval) { 9 | return function () { 10 | if (!timer) { 11 | timer = setTimeout(() => { 12 | fn() 13 | timer = null 14 | }, interval) 15 | } 16 | } 17 | } 18 | // 防抖 19 | function debounce(fn, interval) { 20 | return function () { 21 | debTimer != null && clearTimeout(debTimer) 22 | debTimer = setTimeout(() => fn(), interval) 23 | } 24 | } 25 | 26 | function init() { 27 | let lazyBox = document.getElementById('lazyBox') 28 | let imgs = document.getElementsByTagName('img') 29 | let lazyImgs = [] 30 | for (let i = 0; i < imgs.length; i++) { 31 | imgs[i].dataset.src && lazyImgs.push(imgs[i]) 32 | } 33 | 34 | lazyBox.onscroll = throttle(onscroll, 500) 35 | 36 | let maxHgt = window.innerHeight 37 | 38 | function onscroll() { 39 | console.log(window.scrollY) 40 | let dels = [] 41 | for (let i = 0; i < lazyImgs.length; i++) { 42 | let lazyImg = lazyImgs[i] 43 | let rect = lazyImg.getBoundingClientRect() 44 | if (rect.top >= 0 && rect.top <= maxHgt) { 45 | lazyImg.src = lazyImg.dataset.src 46 | dels.push(i) 47 | } 48 | } 49 | dels.forEach(item => lazyImgs.splice(item, 1)) 50 | isScrollBottom() 51 | } 52 | 53 | function isScrollBottom() { 54 | let uri = "http://img.hkuboss.cn/mine/horizontal-img-220-124.jpg" 55 | if (lazyBox.scrollHeight == lazyBox.scrollTop + lazyBox.clientHeight) { 56 | let fragment = document.createElement('img') 57 | fragment.src = uri 58 | fragment.width = 300 59 | fragment.height = 300 60 | lazyBox.appendChild(fragment) 61 | } 62 | } 63 | 64 | onscroll() 65 | } -------------------------------------------------------------------------------- /DOM/compressImage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | compressImage DEMO 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 105 | 106 | -------------------------------------------------------------------------------- /DOM/images/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frehaiku/Audition/79e84c6154036a68f082e811f0483dc5a3a3553a/DOM/images/google.png -------------------------------------------------------------------------------- /DOM/insertAdjacentElement.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 |
12 |
bbbbbbbb
13 |
cccccccc
14 |
15 | 39 | 40 | -------------------------------------------------------------------------------- /DOM/lazyLoad.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 懒加载图片效果 6 | 34 | 35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /DOM/querySelectorAll.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | querySelector 6 | 7 | 8 |
9 |
10 | outside bbbbbbb 11 |
inner bbbbbbb
12 |
13 |
ccccc
14 |
15 | 16 | 38 | 39 | -------------------------------------------------------------------------------- /DOM/textContent-innerText-innerHtml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | textContent-innerText-innerHtml的区别 6 | 7 | 8 | 9 |

10 | 11 | <\/script> 12 | 13 |

14 | 15 |
16 | 21 |
22 | 23 | 82 | 83 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-15WPS/2017-4-15WPS02.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/4/15. 3 | * 题目要求: 4 | * for (var i = 0; i < 5; i++) { 5 | //在此处编写代码 6 | //每隔1秒钟按顺序输出i值 7 | } 8 | */ 9 | 10 | for (var i = 0; i < 5; i++) { 11 | (index => { 12 | setTimeout(() => { 13 | console.log(index); 14 | }, (index + 1) * 1000); 15 | })(i); 16 | } 17 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-15WPS/2017-4-15WPS04.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/4/15. 3 | * 题目要求: 4 | * 请用JavaScript实现map的数据结构,要求数据只能通过map提供的接口进行访问 5 | * 6 | * 我的疑问:啥是map?就是对象吗? 7 | */ 8 | 9 | /*function JsMap() {} 10 | 11 | Object.defineProperty(JsMap, 'data', { 12 | writable: false, 13 | configurable: true, 14 | enumerable: true 15 | }); 16 | 17 | JsMap.prototype = { 18 | constructor: JsMap, 19 | getMap (key) { 20 | if (key in this.data) { 21 | return this.data[key]; 22 | } 23 | }, 24 | setMap (key, value) { 25 | this.data[key] = value; 26 | } 27 | }; 28 | 29 | var instance = new JsMap(); 30 | instance.setMap('name', 'haiku'); 31 | console.log(instance.getMap('name'));*/ 32 | 33 | function createMap() { 34 | var map = {}; 35 | map.length = 0; 36 | return { 37 | set: function (name, value) { 38 | map.length++; 39 | map[name] = value; 40 | }, 41 | 42 | get: function (name) { 43 | return map[name]; 44 | } 45 | } 46 | } 47 | 48 | var t = createMap(); 49 | var t1 = createMap(); 50 | 51 | t.set('arr', [1, 2, 3, 4]); 52 | // t.get('arr').push(5); 53 | 54 | console.log(t.get('arr')); 55 | 56 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-15WPS/2017-4-15WPS06.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/4/15. 3 | * 题目要求: 4 | * 给定一个排好序的整数数组,判断其中是否存在两个数之和等于指定的值, 5 | * 时间复杂度最好能达到O(n)。例如:[1, 2, 3, 4, 5, 9], 指定值为12, 结果为true 6 | */ 7 | 8 | function twoPointerAdd (arr, aim) { 9 | return arr.some((ele, ind) => { 10 | let cp = arr.slice(); 11 | cp.splice(ind, 1); 12 | 13 | if (cp.indexOf(aim - ele) !== -1) { 14 | return true; 15 | } 16 | }) 17 | } 18 | 19 | console.log(twoPointerAdd([1, 2, 3, 4, 5, 9], 16)); 20 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-15WPS/README.md: -------------------------------------------------------------------------------- 1 | ## 2017-04 WPS广州场笔试题分享与总结 2 | 3 | 声明:题解不代表最终答案,若有更好的实现方式或发现错误,请提PR更正 4 | 5 | > A,B,C分别输出什么? 6 | 7 | ```javascript 8 | var arr = []; 9 | arr['a'] = 1; 10 | console.log(arr.length); // A 11 | arr['2'] = 2; 12 | console.log(arr.length); // B 13 | arr.length = 0; 14 | console.log(arr); // C 15 | ``` 16 | 17 | > 要求每隔1秒钟按顺序输出i值 [题解](./2017-4-15WPS02.js) 18 | 19 | ```javascript 20 | for (var i = 0; i < 5; i++) { 21 | //在此处编写代码 22 | } 23 | ``` 24 | 25 | > 如下代码运行结果是? 26 | 27 | ```javascript 28 | var f = function g() { 29 | return 23; 30 | }; 31 | typeof g(); //输出什么 32 | ``` 33 | 34 | > 以下代码运行结果是什么? 35 | 36 | ```javascript 37 | function showCase(value) { 38 | switch (value) { 39 | case 'A': 40 | console.log(1); 41 | break; 42 | case 'string': 43 | console.log(2); 44 | break; 45 | case undefined: 46 | console.log(3); 47 | break; 48 | case 'undefined': 49 | console.log(4); 50 | break; 51 | default: 52 | console.log(5); 53 | break; 54 | } 55 | } 56 | 57 | showCase(new String('A')); 58 | ``` 59 | 60 | > 请用JavaScript实现map的数据结构,要求数据只能通过map提供的接口进行访问 [题解](./2017-4-15WPS04.js) 61 | 62 | > 给定一个排好序的整数数组,判断其中是否存在两个数之和等于指定的值,时间复杂度最好能达到O(n)。例如:[1, 2, 3, 4, 5, 9], 指定值为12, 结果为true [题解](./2017-4-15WPS06.js) -------------------------------------------------------------------------------- /DailyProblem/2017-4-18toutiao/README.md: -------------------------------------------------------------------------------- 1 | ## 2017-04 今日头条笔试题 2 | 3 | 声明:题解不代表最终答案,若有更好的实现方式或发现错误,请提PR更正 4 | 5 | ![今日头条前端题](./question1.png) 6 | 7 | [我的代码实现](./2016-4-18toutiao.html) 8 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-18toutiao/question1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frehaiku/Audition/79e84c6154036a68f082e811f0483dc5a3a3553a/DailyProblem/2017-4-18toutiao/question1.png -------------------------------------------------------------------------------- /DailyProblem/2017-4-27toutiao/01.md: -------------------------------------------------------------------------------- 1 | > 有A,B,C,D和E共5所学校。在一次检查评比中,已知E肯定不是第二名或第三名,他们相互进行推测。A说,E一定是第一名;B说,我校是第二名;C说,A校最差;D说,C不是最好;E说,D是第一名。结果只有实际排名为第一和第二名的学校说的是真话了, 其他学校都说错了。 2 | 3 | 解答: 4 | 将文字转换成数字符号,更易于解题。 5 | A ==> E = 1 6 | B ==> B = 2 7 | C ==> A = 5 8 | D ==> C != 1 9 | E ==> D = 1 10 | 枚举法,假设A为真,看看条件是否符合;假设B为真,看看条件是否符合;依次内推 11 | 12 | 1. 若A为真,即E为第1名。E若为第1即说了真话,即D为第1。这与E排名矛盾,排除该选项 13 | 2. 若B为真。只满足这条件有点难判断,跳过 14 | 3. 若C为真,A为第5名。则E不为第1名。 15 | 1. E ==> D = 1,E可能为第二名。也可能不是前两名。 16 | 1. 题目已知E不能为2,3。若E为第二名,排除该种情况 17 | 2. 若E不是前3名,D不为第一名。所以C!=1不成立。C为第一,B为第二,A为第五。题目已知E不为2,3名,即E为第四名。D为第三(**条件成立**) 18 | 4. (还会有多种情况吗?接下来继续枚举)若D为真,C不为1。 19 | 1. 假设C为2,此时D = 1。A=5成立,E!=1。D != 1。与D=1矛盾,排除 20 | 2. 假设C前2名。A != 5 21 | 1. A为前两名,E = 1, D = 1。两者都是第一名,排除 22 | 2. A不为前两名,E != 1 23 | 1. E不为前3名, D != 1。 条件不足无法判断 24 | 5. 若E为真,E = 2,D = 1,与题目已知条件冲突,排除 25 | 26 | 故最后结果是 第一名为C,第二名为B,第三名为D,第四名为E,第五名为A -------------------------------------------------------------------------------- /DailyProblem/2017-4-27toutiao/03.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 25 | 26 | 27 | 32 |
33 |
34 |
35 | 36 | 70 | 73 | 74 | -------------------------------------------------------------------------------- /DailyProblem/2017-4-27toutiao/README.md: -------------------------------------------------------------------------------- 1 | # 4-27头条一面需手写的题目 2 | 3 | > 1. 有A,B,C,D和E共5所学校。在一次检查评比中,已知E肯定不是第二名或第三名,他们相互进行推测。A说,E一定是第一名;B说,我校是第二名;C说,A校最差;D说,C不是最好;E说,D是第一名。结果只有实际排名为第一和第二名的学校说的是真话了, 其他学校都说错了。 4 | 5 | > 2. 请用算法实现,从给定的无序、不重复的数组A中,取出N个数,使其相加和为M。并给出算法的时间/空间复杂度 6 | 7 | > 3. 请用纯CSS实现一个自适应正方形,宽是屏幕宽度的50%,且水平垂直居中于屏幕中央。 8 | 9 | 10 | - [x] [第一题题解](01.md) 11 | - [ ] 第二题题解 12 | - [x] [第三题题解](03.html) -------------------------------------------------------------------------------- /DailyProblem/2017-5-10fanpu/aiqiyi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/5/14. 3 | */ 4 | (function (line) { 5 | var input_arrays = line.split(' '); 6 | var row = +input_arrays[0]; 7 | var lie = +input_arrays[1]; 8 | input_arrays.splice(0, 2); 9 | 10 | var arr = []; 11 | for (var i = 0; i < row; i++) { 12 | var inner = []; 13 | for (var j = 0; j < lie; j++) { 14 | inner.push(+input_arrays[j+lie*i]); 15 | } 16 | arr.push(inner); 17 | } 18 | 19 | var result = []; 20 | 21 | /** 22 | * 23 | * @param sOuter 行开始index 24 | * @param sInner 列开始index 25 | * @param mW 最大行序号 26 | * @param mH 最大列序号 27 | */ 28 | function dp(sInner, sOuter, mW, mH) { 29 | //最上面向右 30 | for (var wr = sInner; wr < mW; wr++) { 31 | if (result.indexOf(arr[sOuter][wr]) == -1) { 32 | result.push(arr[sOuter][wr]); 33 | } 34 | } 35 | //最上面向下 36 | for (var hb = sOuter + 1; hb < mH; hb++) { 37 | if (result.indexOf(arr[hb][mW - 1]) == -1) { 38 | result.push(arr[hb][mW - 1]); 39 | } 40 | } 41 | //最下面向左 42 | for (var wl = mW - 2; wl >= sInner; wl--) { 43 | if (result.indexOf(arr[mH - 1][wl]) == -1) { 44 | result.push(arr[mH - 1][wl]); 45 | } 46 | } 47 | //最下面向上 48 | for (var ht = mH - 2; ht > sOuter; ht--) { 49 | if (result.indexOf(arr[ht][sInner]) == -1) { 50 | result.push(arr[ht][sInner]); 51 | } 52 | } 53 | if (++sInner != --mW && ++sOuter != --mH) { 54 | dp(sInner, sOuter, mW, mH); 55 | } 56 | // console.log(result); 57 | } 58 | // console.log(arr); 59 | dp(0, 0, lie, row); 60 | console.log(result.join(' ')); 61 | })('3 4 1 2 3 4 5 6 7 8 9 10 11 13'); -------------------------------------------------------------------------------- /DailyProblem/2017-5-19/01.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/5/20. 3 | */ 4 | /** 5 | * 牛牛想对一个数做若干次变换,直到这个数只剩下一位数字。 6 | 变换的规则是:将这个数变成 所有位数上的数字的乘积。比如285经过一次变换后转化成2*8*5=80. 7 | 问题是,要做多少次变换,使得这个数变成个位数。 8 | 输入描述: 9 | 输入一个整数。小于等于2,000,000,000。 10 | 11 | 12 | 输出描述: 13 | 输出一个整数,表示变换次数。 14 | 15 | 输入例子: 16 | 285 17 | 18 | 输出例子: 19 | 2 20 | **/ 21 | 22 | function addNum(num) { 23 | var input = num, count = 0, chen; 24 | while (input.length > 1) { 25 | chen = +input.split('')[0]; 26 | input = input.split('').forEach(function (a, ind) { 27 | if (ind > 0) 28 | chen *= +a; 29 | }); 30 | input = chen.toString(); 31 | count++; 32 | } 33 | console.log(count); 34 | } 35 | addNum("999"); -------------------------------------------------------------------------------- /DailyProblem/2017-5-19/02.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/5/20. 3 | */ 4 | /* 5 | * 6 | * 时间限制:1秒 7 | 空间限制:32768K 8 | 给出一个区间[a, b],计算区间内“神奇数”的个数。 9 | 神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数。 10 | 比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数。同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数。 11 | 输入描述: 12 | 输入为两个整数a和b,代表[a, b]区间 (1 ≤ a ≤ b ≤ 10000)。 13 | 14 | 15 | 输出描述: 16 | 输出为一个整数,表示区间内满足条件的整数个数 17 | 18 | 输入例子: 19 | 11 20 20 | 21 | 输出例子: 22 | 6 23 | * */ 24 | 25 | (function (str) { 26 | function isShenqi(num) { 27 | var str = num.toString(), pin; 28 | for (var i = 0; i < str.length; i++) { 29 | for (var j = 0; j < str.length; j++) { 30 | if (i !== j) { 31 | pin = +(str[i] + str[j]); 32 | if (pin.toString().length >= 2 && isZhi(pin)) { 33 | return true; 34 | } 35 | } 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | function isZhi(num) { 42 | for (var i = 2; i <= num - 1; i++) { 43 | if (num % i == 0) { 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | 50 | var arr = str.split(' '), count = 0; 51 | for (var i = +arr[0]; i <= +arr[1]; i++) { 52 | if (isShenqi(i)) { 53 | count++; 54 | } 55 | } 56 | console.log(count); 57 | })("11 20"); -------------------------------------------------------------------------------- /DailyProblem/2017-5-19/03.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/5/20. 3 | */ 4 | /* 5 | * 时间限制:1秒 6 | 空间限制:32768K 7 | 牛牛举办了一次编程比赛,参加比赛的有3*n个选手,每个选手都有一个水平值a_i.现在要将这些选手进行组队,一共组成n个队伍,即每个队伍3人.牛牛发现队伍的水平值等于该队伍队员中第二高水平值。 8 | 例如: 9 | 一个队伍三个队员的水平值分别是3,3,3.那么队伍的水平值是3 10 | 一个队伍三个队员的水平值分别是3,2,3.那么队伍的水平值是3 11 | 一个队伍三个队员的水平值分别是1,5,2.那么队伍的水平值是2 12 | 为了让比赛更有看点,牛牛想安排队伍使所有队伍的水平值总和最大。 13 | 如样例所示: 14 | 如果牛牛把6个队员划分到两个队伍 15 | 如果方案为: 16 | team1:{1,2,5}, team2:{5,5,8}, 这时候水平值总和为7. 17 | 而如果方案为: 18 | team1:{2,5,8}, team2:{1,5,5}, 这时候水平值总和为10. 19 | 没有比总和为10更大的方案,所以输出10. 20 | 21 | 输入描述: 22 | 输入的第一行为一个正整数n(1 ≤ n ≤ 10^5) 23 | 24 | 第二行包括3*n个整数a_i(1 ≤ a_i ≤ 10^9),表示每个参赛选手的水平值. 25 | 26 | 27 | 输出描述: 28 | 输出一个整数表示所有队伍的水平值总和最大值. 29 | 30 | 输入例子: 31 | 2 32 | 5 2 8 5 1 5 33 | 34 | 输出例子: 35 | 10 36 | * */ 37 | 38 | (function (count, str) { 39 | var arr = str.split(' ') 40 | , ans = 0 41 | arr.sort(function (a, b) { 42 | return b - a; 43 | }) 44 | 45 | for (var i = 0; i < count; i++) { 46 | ans += parseInt(arr[i*2 + 1], 10) 47 | } 48 | console.log(ans) 49 | })("2", "5 2 8 5 1 5"); -------------------------------------------------------------------------------- /DailyProblem/201706/zeptoExtend.js: -------------------------------------------------------------------------------- 1 | let key 2 | function type(obj) { 3 | return obj == null ? String(obj) : Object.prototype.toString.call(obj).match(/\w+(?=\])/)[0].toLowerCase() 4 | } 5 | function isObject(obj) { 6 | return type(obj) == 'object' 7 | } 8 | function isArray(arr) { 9 | return type(arr) == 'array' 10 | } 11 | function extend(target, source, deep) { 12 | for (key in source) 13 | if (deep && (isObject(source[key]) || isArray(source[key]))) { 14 | if (isObject(source[key])) 15 | target[key] = {} 16 | if (isArray(source[key])) 17 | target[key] = [] 18 | extend(target[key], source[key], deep) 19 | } else if (source[key] != void 0) target[key] = source[key] 20 | } 21 | 22 | let source = { 23 | a: {b: 2}, 24 | c: [1,5,8], 25 | d: '123str', 26 | e: 123 27 | }, target = {} 28 | 29 | 30 | function $extends(...args) { 31 | let target 32 | if (typeof args[0] === 'boolean') { 33 | target = args[1] 34 | args.slice(2).forEach(e => extend(target, e, true)) 35 | } else { 36 | target = args[0] 37 | args.slice(1).forEach(e => extend(target, e)) 38 | } 39 | return target 40 | } 41 | 42 | console.log($extends(true, target, source)) 43 | 44 | target.a.b = 3 45 | target.c.push(10) 46 | 47 | console.log(source) 48 | console.log(target) -------------------------------------------------------------------------------- /DailyProblem/201708/163SeriesDP.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/6. 3 | */ 4 | function number1(n, k) { 5 | return process(1, n, k); 6 | } 7 | // n个数,1~k 8 | function process(pre, n, k) { 9 | if (n == 0) { 10 | return 1; 11 | } 12 | let sum = 0; 13 | for (let cur = pre; cur <= k; cur++) { 14 | sum += process(cur, n - 1, k); 15 | } 16 | for (let cur = 1; cur < pre; cur++) { 17 | sum += (pre % cur) != 0 ? process(cur, n - 1, k) : 0; 18 | } 19 | return sum % 1000000007; 20 | } 21 | 22 | console.log(number1(3, 4)) -------------------------------------------------------------------------------- /DailyProblem/201708/CrashDollyCanLeaveTrack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/10. 3 | */ 4 | function main(trackMax, arr) { 5 | // better describe to obj 6 | var maps = [] 7 | arr.forEach(item => { 8 | var obj = {} 9 | obj.power = +item[0] 10 | obj.locate = +item[1] 11 | obj.direction = +item[2] 12 | maps.push(obj) 13 | }) 14 | // sortion according to locate 15 | maps.sort(function (p, n) { 16 | var l = p.locate - n.locate 17 | return !l ? p.direction - n.direction : l 18 | }) 19 | var continous = 0 20 | var length = maps.length 21 | var ans = 0 22 | while (continous != length) { 23 | continous=0 24 | for (var i = 0; i < length; i++) { 25 | var cur = maps[i] 26 | var power = cur.power 27 | var dir = cur.direction 28 | var locate = cur.locate 29 | if (power > 0 && locate >= 0 && locate <= trackMax - 1) { 30 | if (dir == -1) { 31 | if (locate == 0) { 32 | // reset to 0, voiding to next time judge 33 | cur.locate = -1 34 | cur.power = 0 35 | ans++ 36 | } else { 37 | var prevBlock = maps[i-1] 38 | // 碰撞,前一个块有能量 39 | if (i > 0 && prevBlock.locate == locate - 1 && prevBlock.power > 0) { 40 | cur.locate = locate + 1 41 | cur.direction = -(dir) 42 | cur.power-- 43 | } else if (i > 0 && prevBlock.locate == locate - 1 && prevBlock.power <= 0) { 44 | if (power >= 2) { 45 | prevBlock.locate-- 46 | if (prevBlock.locate == 0) 47 | ans++ 48 | cur.locate-- 49 | cur.pow -= 2 50 | } else { 51 | cur.power-- 52 | } 53 | 54 | } else { 55 | cur.locate = locate - 1 56 | cur.power-- 57 | } 58 | } 59 | } else if (dir == 1) { 60 | var endInc = trackMax - 1 61 | if (cur.locate == endInc) { 62 | // reset to 0, voiding to next time judge 63 | cur.power = 0 64 | cur.locate = endInc+1 65 | ans++ 66 | } else { 67 | var next = maps[i + 1] 68 | // 碰撞,前一个块有能量 69 | if (next.locate - 1 == locate && next.power > 0) { 70 | cur.locate = locate - 1 71 | cur.direction = -(dir) 72 | cur.power-- 73 | } else if (next.locate - 1 == locate && next.power <= 0) { 74 | if (power >= 2) { 75 | cur.locate++ 76 | next.locate++ 77 | if (next.locate == endInc) 78 | ans++ 79 | cur.pow -= 2 80 | } else { 81 | cur.power-- 82 | } 83 | } 84 | } 85 | 86 | } 87 | } else { 88 | continous++ 89 | } 90 | } 91 | } 92 | console.log(ans) 93 | } 94 | 95 | main(6, [['1', '1', '-1'], ['1', '5', '1']]) 96 | main(6, [['1', '5', '1'], ['1', '1', '-1']]) 97 | main(6, [[5, 0, 1], [5, 1, -1]]) -------------------------------------------------------------------------------- /DailyProblem/201708/al.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 |
9 |
点我
10 |
11 | 12 |
13 | 14 |
15 | 74 | 75 | -------------------------------------------------------------------------------- /DailyProblem/201708/computeBacketLeakStage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/10. 3 | */ 4 | function main(H, x, y, h, s) { 5 | h = h >= H ? H : h 6 | var beyondhTime = h / x 7 | if (s <= beyondhTime) 8 | return x * s 9 | else { 10 | var nextSeconds = Math.ceil(beyondhTime) 11 | var mayLeak = nextSeconds - beyondhTime 12 | var nextSecL = h + (mayLeak * x) - (mayLeak * y) 13 | if (s == nextSeconds) { 14 | return nextSecL 15 | } 16 | if (x > y) { 17 | var much = s - nextSeconds 18 | var ans = nextSecL + much * (x - y) 19 | return ans > H ? H : ans 20 | } else 21 | return h 22 | } 23 | } 24 | 25 | console.log(main(10, 2, 1, 3, 5)) 26 | console.log(main(10, 1, 2, 2, 5)) 27 | console.log(main(10, 1, 2, 9, 5)) 28 | console.log(main(10, 2, 1, 10, 5)) 29 | console.log(main(10, 2, 1, 9, 5)) -------------------------------------------------------------------------------- /DailyProblem/201708/drag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Drag Demo 6 | 16 | 17 | 18 |
19 | 50 | 51 | -------------------------------------------------------------------------------- /DailyProblem/201708/fanpu01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 44 | 45 | 46 | 47 | 48 | 61 | 62 | 112 | 113 | -------------------------------------------------------------------------------- /DailyProblem/201708/gbits.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/29. 3 | * 4 | * G社正在开发一共新的战棋类游戏,在这个游戏中, 5 | * 角色只能向2个方向移动:右、下。移动需要消耗行动力, 6 | * 游戏地图上划分M*N个格子,当角色移动到某个格子上时, 7 | * 行动力就会加上格子上的值K(-100~100),当行动力<=0时游戏失败, 8 | * 请问要从地图左上角移动到地图右下角至少需要多少起始行动力, 9 | * 注意(玩家初始化到起始的左上角格子时也需要消耗行动力) 10 | */ 11 | 12 | /*2 3 13 | -2 -3 1 14 | -5 -10 1*/ 15 | 16 | var iMax = 2 17 | var jMax = 3 18 | var arr = [ 19 | [-2, -3, 1], 20 | [-5, -10, 1] 21 | ] 22 | 23 | function f1(...args) { 24 | var ans = 0; 25 | 26 | function f11(arr, i, j) { 27 | if (arr.length == 0) return 0 28 | if (i <= 0 && j <= 0) 29 | return arr[0][0] 30 | if (i == 0) 31 | return arr[0][j] + f11(arr, 0, j - 1) 32 | if (j == 0) 33 | return arr[i][0] + f11(arr, i - 1, 0) 34 | var m = Math.max( 35 | f11(arr, i, j - 1), 36 | f11(arr, i - 1, j) 37 | ) 38 | if (m < 0 && m < ans) 39 | ans = m 40 | return arr[i][j] + m 41 | } 42 | 43 | f11.apply(null, args) 44 | return Math.abs(ans) + 1 45 | } 46 | 47 | // console.log(f1(arr, iMax - 1, jMax - 1)) 48 | 49 | 50 | function f2(arr, i, j) { 51 | if (arr.length == 0) return 0 52 | var ans = 0 53 | var dp = new Array(i) 54 | //first 55 | var inner = new Array(j) 56 | inner[0] = arr[0][0] 57 | for (var k = 1; k < j; k++) 58 | inner[k] = inner[k - 1] + arr[0][k] 59 | dp[0] = inner 60 | 61 | for (var g = 1; g < i; g++) { 62 | inner = new Array(j) 63 | inner[0] = arr[g][0] + dp[g - 1][0] 64 | for (var h = 1; h < j; h++) { 65 | var m = Math.max(dp[g - 1][h], inner[h - 1]) 66 | inner[h] = m + arr[g][h] 67 | if (m < ans) 68 | ans = m 69 | } 70 | dp[g] = inner 71 | } 72 | return Math.abs(ans) + 1 73 | // console.log(ans) 74 | // return dp[i - 1][j - 1] 75 | } 76 | 77 | function f3(arr, i, j) { 78 | var ans = 0 79 | var dp = new Array(j) 80 | dp[0] = arr[0][0] 81 | // init 82 | for (let i = 1; i < j; i++) 83 | dp[i] = arr[0][i] + dp[i - 1] 84 | 85 | for (let a = 1; a < i; a++) 86 | for (let n = 0; n < j; n++) 87 | if (n == 0) 88 | dp[0] = arr[a][0] + dp[0] 89 | else { 90 | let m = Math.max(dp[n - 1], dp[n]) 91 | if (m < 0 && m < ans) { 92 | ans = m 93 | } 94 | dp[n] = m + arr[a][n] 95 | } 96 | return Math.abs(ans) + 1 97 | } 98 | // console.log(f3(arr, iMax, jMax)) 99 | function test() { 100 | // 对数器 101 | for (var z = 0; z < 500; z++) { 102 | var row = ~~(Math.random() * 25) + 1 103 | var column = ~~(Math.random() * 25) + 1 104 | var arr = new Array(row) 105 | var inner 106 | for (var j = 0; j < row; j++) { 107 | inner = new Array(column) 108 | for (var i = 0; i < column; i++) { 109 | inner[i] = ~~(Math.random() * 100) - 50 110 | } 111 | arr[j] = inner 112 | } 113 | 114 | var res1 = f1(arr, row - 1, column - 1) 115 | var res2 = f2(arr, row, column) 116 | var res3 = f3(arr, row, column) 117 | 118 | if (res1 != res2 || res1 != res3 || res2 != res3) { 119 | console.log('fucking man') 120 | console.log(`${JSON.stringify(arr)}`) 121 | console.log(`The row is ${row}`) 122 | console.log(`The column is ${column}`) 123 | } 124 | } 125 | console.log('end...') 126 | } 127 | test() -------------------------------------------------------------------------------- /DailyProblem/201708/lazyMan.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/20. 3 | */ 4 | var LazyMan = (function () { 5 | class LazyMan { 6 | 7 | constructor(name) { 8 | this.queue = [] 9 | this.push(() => { 10 | console.log(`welcome ${name}`) 11 | this.queue.shift() 12 | this.next() 13 | }) 14 | 15 | setTimeout(() => { 16 | this.next() 17 | }, 0) 18 | } 19 | 20 | push(fn) { 21 | this.queue.push(fn) 22 | } 23 | 24 | next() { 25 | if (this.queue.length != 0) { 26 | this.queue[0].call() 27 | } 28 | } 29 | 30 | eat(food) { 31 | this.push(() => { 32 | console.log(`eat ${food}`) 33 | this.queue.shift() 34 | this.next() 35 | }) 36 | return this 37 | } 38 | 39 | sleep(seconds) { 40 | this.push(() => { 41 | setTimeout(() => { 42 | console.log(`wake up after ${seconds}s`) 43 | this.queue.shift() 44 | this.next() 45 | }, 1000 * seconds) 46 | }) 47 | return this 48 | } 49 | 50 | sleepFirst(seconds) { 51 | this.queue.unshift(() => { 52 | setTimeout(() => { 53 | console.log(`wake up first after ${seconds}s`) 54 | this.queue.shift() 55 | this.next() 56 | }, 1000 * seconds) 57 | }) 58 | return this 59 | } 60 | } 61 | return function (name) { 62 | return new LazyMan(name) 63 | } 64 | })() 65 | 66 | LazyMan("Hank").sleep(1).eat("dinner").sleepFirst(3) -------------------------------------------------------------------------------- /DailyProblem/201708/muchMakeUpFlower.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/11. 3 | */ 4 | 5 | /** 6 | * 7 | * @param n 进了n种花 8 | * @param m 要求m种不一样 9 | * @param r 每种花需要放r朵 10 | * @param arr 11 | * @returns {number} 12 | */ 13 | function main(n, m, r, arr) { 14 | var con = 0 15 | var ans = 0 16 | var can = [] 17 | if (m > n) 18 | ans = 0 19 | else { 20 | while (n - con >= m) { 21 | con = 0 22 | for (var i = 0; i < n; i++) { 23 | if (arr[i] >= r) { 24 | can.push(i) 25 | if (can.length >= m) { 26 | ans++ 27 | desciVal(arr, can, r) 28 | can = [] 29 | } 30 | } else if (arr[i] < r) 31 | con++ 32 | } 33 | } 34 | } 35 | console.log(ans) 36 | } 37 | 38 | function desciVal(arr, idxs, r) { 39 | idxs.forEach(function (item) { 40 | arr[item] -= r 41 | }) 42 | } 43 | main(3,2,3,[7,7,9]) -------------------------------------------------------------------------------- /DailyProblem/201708/nowcoderDungeonEscape.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/7. 3 | */ 4 | var hell = [ 5 | ['.', '.', '.'], 6 | ['.', '.', '.'], 7 | ['.', '.', '.'] 8 | ] 9 | 10 | var startX = 0, startY = 1 11 | 12 | var allow = [ 13 | {x: 1, y: 0}, 14 | {x: 0, y: 1}, 15 | {x: -1, y: 0}, 16 | {x: 0, y: -1} 17 | ] 18 | 19 | function maxji(arr, k, d) { 20 | arr = arr.map(e => +e) 21 | // console.log(arr) 22 | return process(arr, k, k-1, k, d, 0, 1) 23 | } 24 | 25 | /** 26 | * 27 | * @param arr 28 | * @param prev 29 | * @param curr 30 | * @param k 选k个学生 31 | * @param d 要求相邻两个学生的位置编号的差不超过d 32 | * @param count 当前已经选的学生数 33 | * @param result 累乘的结果 34 | */ 35 | function process(arr, prev, curr, k, d, count, result) { 36 | if (prev - curr > d || (curr <= 0 && count != d)) 37 | return 0 38 | if (k == count) 39 | return result 40 | return Math.max( 41 | // 选当前元素 42 | process(arr, curr, curr - 1, k, d, count + 1, arr[curr] * result), 43 | process(arr, prev, curr - 1, k, d, count, result) 44 | ) 45 | } 46 | // var str = '-1 -15 2 3 4' 47 | var str = '1 15 2 3 4' 48 | // var str = '4 3 2 -15 -1' 49 | console.log(maxji(str.split(' '), 3, 31)) -------------------------------------------------------------------------------- /DailyProblem/201708/sharesXiaomi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/31. 3 | 4 | 链接:https://www.nowcoder.com/questionTerminal/9370d298b8894f48b523931d40a9a4aa 5 | 来源:牛客网 6 | 风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 7 | 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示, 8 | 数组中第i个元素(prices[i])代表该股票第i天的股价。 9 | 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。 10 | 若两次交易机会都放弃,收益为0。 11 | 设计算法,计算你能获得的最大收益。 12 | 输入数值范围:2<=n<=100,0<=prices[i]<=100 13 | 14 | 示例1: 15 | 输入 16 | 3,8,5,1,7,8 17 | 输出 18 | 12 19 | */ 20 | 21 | function m1(arr, cur, buy, sell, buyIdx) { 22 | if (buy == 0 && sell == 0 || cur <= 0) 23 | return 0 24 | // 已买入,必须卖出 25 | if (buy < sell) { 26 | return sold(arr, cur, buy, sell, buyIdx) 27 | } else { 28 | // 买入 29 | var a = m1(arr, cur - 1, buy, sell, buyIdx), 30 | b = m1(arr, cur - 1, buy - 1, sell, cur) 31 | console.log(`m1:${a}`) 32 | console.log(`m1:${b}`) 33 | return Math.max( 34 | a, b 35 | ) 36 | } 37 | } 38 | 39 | // 卖 40 | function sold(arr, cur, buy, sell, buyIdx) { 41 | if (buy == 0 && sell == 0 || cur <= 0) 42 | return 0 43 | var buyPrice = arr[buyIdx] 44 | var a = arr[cur] - buyPrice + m1(arr, cur - 1, buy, sell - 1, buyIdx) 45 | var b = sold(arr, cur - 1, buy, sell, buyIdx) 46 | console.log(`sold:${a}`) 47 | console.log(`sold:${b}`) 48 | var ans = Math.max(a, b) 49 | return ans 50 | } 51 | var arr = [3, 8, 5, 1, 7, 8] 52 | var max = arr.length - 1 53 | console.log(m1(arr, max, 2, 2, -1)); -------------------------------------------------------------------------------- /DailyProblem/201711/h5Drag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 47 | 48 | 49 |
50 |
51 | 垃
52 | 圾
箱 53 |
54 |
55 |
列表1
56 |
列表2
57 |
列表3
58 |
列表4
59 |
列表5
60 |
列表6
61 |
62 |
63 | 64 | 112 | 113 | -------------------------------------------------------------------------------- /DailyProblem/201711/webWorker/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | workWorker demo 6 | 7 | 8 | web worker的演示,请打开console看结果 9 | 10 | 20 | 21 | -------------------------------------------------------------------------------- /DailyProblem/201711/webWorker/webWorkerExample.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/11/22. 3 | */ 4 | self.onmessage = (event) => { 5 | var data = event.data 6 | data.sort((a, b) => a - b) 7 | self.postMessage(data) 8 | } -------------------------------------------------------------------------------- /EventLoop/Native/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript中的event loop 2 | 3 | 所有任务分为同步任务和异步任务。 4 | 5 | 同步任务指的是,在主线程上排队执行任务,只有前一个任务执行完毕,才执行后一个任务; 6 | 7 | 异步任务不会进入主进程,而是进入任务队列,只有“任务队列”通知主进程,某个异步任务可以执行了,该任务才会进入主进程。 8 | 9 | 异步机制的运行机制如下: 10 | 11 | 1. 所有同步任务在主线程中执行,形成一个执行栈 12 | 2. 存在一个任务队列,只要异步任务都有了结果,就在任务队列之中放置一个事件 13 | 3. 执行栈执行完时,就会读取任务队列的事件。那些对应的异步任务,于是结束等待状态进入执行栈,开始执行。 14 | 15 | 主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。 16 | 17 | 如下图(转自Philip Roberts的演讲[《Help, I'm stuck in an event-loop》](https://vimeo.com/96425312)) 18 | ![iamge](http://image.beekka.com/blog/2014/bg2014100802.png) 19 | 20 | 主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在任务队列中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取“任务队列”,依次执行那些事件所对应的回调函数。 21 | 22 | ## 定时器 23 | 24 | 除了放置异步任务的事件,“任务队列”还可以放置定时事件,即指定某些代码在多少时间之后执行。这叫做“定时器”功能。 25 | 26 | 如以下代码: 27 | 28 | ```js 29 | console.log(1); 30 | setTimeout(() => console.log(2)) 31 | console.log(3); 32 | ``` 33 | 34 | 该代码执行的流程是,先输出1,再输出3,最后输出2。setTimeout会在当前代码执行完(执行栈清空)以后,立即执行(0秒间隔)指定的回调函数。 35 | 36 | 需要注意的是,setTimeout()只是将事件插入了“任务队列”,必须等到当前代码(执行栈)执行完,主线程才会去执行指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以没有办法保证,回调函数一定会在setTimeout()指定的时间后执行。 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /EventLoop/Nodejs/7-20-demo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2019/7/20. 3 | */ 4 | setTimeout(() => { 5 | console.log('timer1'); 6 | Promise.resolve().then(function () { 7 | console.log('promise1') 8 | }) 9 | }, 0) 10 | 11 | setTimeout(() => { 12 | console.log('timer2') 13 | Promise.resolve().then(function () { 14 | console.log('promise2') 15 | }) 16 | }, 0) 17 | 18 | /* 19 | * Node里执行顺序: 20 | * timer1 21 | * timer2 22 | * promise1 23 | * promise2 24 | * */ 25 | 26 | /* 27 | class Test {}; 28 | global.test = new Test() 29 | 30 | function run5(bigData) { 31 | const innerData = new Buffer(100); 32 | // 被闭包引用,创建一个 context: context1。 33 | // context1 引用 bigData,innerData。 34 | // closure 为 function run5() 35 | // run5函数没有 context,所以 context1 没有previous。 36 | // 在 run5中新建的函数将绑定上 context1。 37 | ​ 38 | test.outClosure5 = function () { 39 | // 此函数闭包 context 指向 context1。 40 | void bigData; 41 | const closureData = new Buffer(100); 42 | // 被闭包使用,创建 context: context2。 43 | // outClosure5 函数有 context1,previous 指向 context1。 44 | // 在 outClosure5 中新建的函数将绑定上context2。 45 | ​ 46 | test.innerClosure5 = function () { 47 | // 此函数闭包 context 指向 context2。 48 | void innerData; 49 | } 50 | test.innerClosure5_1 = function () { 51 | // 此函数闭包 context 指向 context2。 52 | void closureData; 53 | } 54 | }; 55 | test.outClosure5_1 = function () {} 56 | test.outClosure5(); 57 | } 58 | 59 | ​ 60 | run5(new Buffer(1000));*/ 61 | -------------------------------------------------------------------------------- /EventLoop/Nodejs/README.md: -------------------------------------------------------------------------------- 1 | # Node.js中的Event Loop 2 | 3 | Node.js的运行机制不同于浏览器环境。 4 | 5 | Node.js的运行机制如下。 6 | 7 | 1. V8引擎解析JavaScript脚本 8 | 2. 解析后的代码,调用Node API 9 | 3. libuv库负责Node API的执行。它将不同的任务分配给不同进程,形成一个Event Loop,以异步的方式将任务的执行结果返回给V8引擎 10 | 4. V8引擎将结果返回给用户 11 | 12 | `process.nextTick`方法可以在当前“执行栈”的尾部---下一次Event Loop(主线程读取任务队列)之前触发回调函数 13 | 14 | ```js 15 | process.nextTick(() => { 16 | console.log(1) 17 | process.nextTick(() => console.log(2)) 18 | }) 19 | 20 | setTimeout(() => console.log(3)) 21 | ``` 22 | 23 | 上述代码中,由于`process.nextTick`方法指定的回调函数,总是在当前“执行栈”的尾部触发,所以不仅函数nextTick比`setTimeout`指定的回调函数先执行,而且“嵌套的内部函数”也比timeout先执行。这说明,如果有多个`process.nextTick`语句,将全部在当前执行栈执行。 24 | 25 | 而setImmediate方法则是当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout()很像。 26 | 27 | ```js 28 | setImmediate(function () { 29 | console.log(1) 30 | setImmediate(function () { 31 | console.log(2) 32 | }) 33 | }) 34 | 35 | setTimeout(function () { 36 | console.log('TIMEOUT FIRED') 37 | }) 38 | ``` 39 | 40 | 上述代码中,setImmediate与setTimeout各自添加了一个回调函数A和timeout,都是在下一次Event Loop触发。那么哪个先执行呢,答案是不确定的。 41 | 运行结果有可能输出`1---TIMEOUT FIRED---2`或`TIMEOUT FIRED---1---2` 42 | 43 | Node.js文档称,在setImmediate指定的回调函数中,总是排在setTimeout的前面。实际上,这种情况只发生在递归调用的时候。 44 | 45 | ```js 46 | setImmediate(function () { 47 | setImmediate(function A() { 48 | console.log(1) 49 | setImmediate(function B() { 50 | console.log(2) 51 | }) 52 | }) 53 | 54 | setTimeout(function timeout() { 55 | console.log('TIMEOUT FIRED') 56 | }, 0) 57 | }) 58 | 59 | // 1 60 | // TIMEOUT FIRED 61 | // 2 62 | ``` 63 | 64 | 可以看出setImmediate总是将事件注册到下一轮Event Loop,所以函数B在下一轮Loop执行。 65 | 66 | 由此看到nextTick与Immediate的一个区别,多个nextTick总是在当期执行栈一次执行完。多个setImmediate可能则需要多次loop才能执行完。 -------------------------------------------------------------------------------- /EventLoop/Nodejs/nextTick.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/5/10. 3 | */ 4 | process.nextTick(() => { 5 | console.log(1) 6 | process.nextTick(() => console.log(2)) 7 | }) 8 | 9 | setTimeout(() => console.log(3)) 10 | 11 | // 1 12 | // 2 13 | // 3 -------------------------------------------------------------------------------- /EventLoop/Nodejs/recursion-setImmediate.js: -------------------------------------------------------------------------------- 1 | var start = new Date() 2 | setImmediate(function () { 3 | console.log('immediate') 4 | }) 5 | setTimeout(function () { 6 | console.log('timeout') 7 | }, 500) 8 | 9 | process.nextTick(function () { 10 | var end = new Date 11 | console.log('nextick') 12 | }) 13 | while (new Date - start < 500) {} 14 | 15 | // nexttick 16 | // timeout 17 | // immediate 18 | 19 | setImmediate(function () { 20 | console.log(1); 21 | }, 0); 22 | 23 | setTimeout(function () { 24 | console.log(2); 25 | }, 0); 26 | 27 | new Promise(function (resolve) { 28 | console.log(3); 29 | resolve(); 30 | console.log(4); 31 | }).then(function () { 32 | console.log(5); 33 | }); 34 | 35 | console.log(6); 36 | 37 | process.nextTick(function () { 38 | console.log(7); 39 | }); 40 | 41 | console.log(8); 42 | 43 | //输出结果是3 4 6 8 7 5 2 1 -------------------------------------------------------------------------------- /EventLoop/Nodejs/setImmediate.js: -------------------------------------------------------------------------------- 1 | setImmediate(function () { 2 | console.log(1) 3 | setImmediate(function () { 4 | console.log(2) 5 | }) 6 | }) 7 | 8 | setTimeout(function () { 9 | console.log('TIMEOUT FIRED') 10 | }, 0) 11 | 12 | // 1 13 | // TIMEOUT FIRED 14 | // 2 15 | // 或者 16 | // TIMEOUT FIRED 17 | // 1 18 | // 2 19 | -------------------------------------------------------------------------------- /GraphQL/helloworld.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frehaiku/Audition/79e84c6154036a68f082e811f0483dc5a3a3553a/GraphQL/helloworld.js -------------------------------------------------------------------------------- /GraphQL/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "express": "^4.16.3", 4 | "express-graphql": "^0.6.12", 5 | "graphql": "^0.13.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /JS/CompatibleRequestAnimationFrame.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/17. 3 | */ 4 | let lastTime = 0 5 | var vendor = ['wekbit', 'moz'] 6 | 7 | for (let i = 0; !(global.requestAnimationFrame) && i < vendor.length; i++) { 8 | global.requestAnimationFrame = `${vendor[i]}RequestAnimationFrame` 9 | global.cancelAnimationFrame = `${vendor[i]}CancelAnimationFrame` 10 | } 11 | 12 | if (1) { 13 | global.requestAnimationFrameCustomed = function (callback) { 14 | let currTime = Date.now() 15 | let timeToCall = Math.max(0, 16.7 - (currTime - lastTime)) 16 | console.log(`timetoCall:${timeToCall}`) 17 | let id = global.setTimeout(() => { 18 | callback(currTime + timeToCall) 19 | }, timeToCall) 20 | lastTime = currTime + timeToCall 21 | return id 22 | } 23 | } 24 | 25 | if (!global.cancelAnimationFrame) { 26 | global.cancelAnimationFrame = clearTimeout 27 | } 28 | 29 | for (let i = 0; i < 5; i++) 30 | setTimeout(timeoutCb, 1000 * i) 31 | 32 | function timeoutCb() { 33 | requestAnimationFrameCustomed(print) 34 | } 35 | 36 | function print(str) { 37 | console.log(str) 38 | } -------------------------------------------------------------------------------- /JS/EventEmit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 观察者模式 3 | */ 4 | function EventEmit() { 5 | this._queues = {} 6 | } 7 | 8 | EventEmit.prototype.on = function (name, fn, context) { 9 | if (fn) { 10 | let handlers = this._queues[name] || (this._queues[name] = []) 11 | handlers.push({fn, context}) 12 | } 13 | return this 14 | } 15 | 16 | EventEmit.prototype.off = function (name, fn, context) { 17 | if (!name && !fn && !context) 18 | this._queues = null 19 | 20 | if (name && !fn && !context) 21 | delete this._queues[name] 22 | else { 23 | let remain = [] 24 | let handlers = this._queues[name] 25 | let i 26 | let length = handlers.length 27 | let item 28 | for (i = 0; i < length; i++) { 29 | item = handlers[i] 30 | if ( 31 | (!context && item.fn !== fn) || 32 | (context && item.fn !== fn && item.context != context) 33 | ) 34 | remain.push(item) 35 | } 36 | this._queues[name] = remain 37 | } 38 | return this 39 | } 40 | 41 | EventEmit.prototype.emit = function (name, ...args) { 42 | let emitThing = this._queues[name] 43 | let i 44 | let length = emitThing.length 45 | for (i = 0; i < length; i++) 46 | emitThing[i].fn.apply(emitThing[i].context, args) 47 | return this 48 | } 49 | 50 | // example 51 | let evtEmit = new EventEmit() 52 | 53 | function doAny0() { 54 | console.log('The 0 sequence is running') 55 | } 56 | 57 | function doAny1() { 58 | console.log('The 1 sequence is running') 59 | } 60 | 61 | function doAny2() { 62 | console.log('The 2 sequence is running') 63 | } 64 | 65 | /* 66 | const KEY = 'test' 67 | evtEmit.on(KEY, doAny0) 68 | .on(KEY, doAny1) 69 | .on(KEY, doAny2) 70 | 71 | evtEmit.emit(KEY) 72 | 73 | evtEmit.off(KEY, doAny1) 74 | 75 | evtEmit.emit(KEY)*/ 76 | 77 | function clone(sources) { 78 | var tar 79 | if (sources instanceof Array) { 80 | tar = [] 81 | sources.forEach((item, idx) => { 82 | tar[idx] = clone(sources[idx]) 83 | }) 84 | return tar 85 | } else if (Object.prototype.toString.call(sources) == '[object Object]') { 86 | tar = {} 87 | for (var item in sources) 88 | tar[item] = clone(sources[item]) 89 | return tar 90 | } else 91 | return sources 92 | } 93 | var obj1 = {name: 'xuzhipeng', sex: 'boy', fn: function () { 94 | console.log(1) 95 | }} 96 | 97 | var after = clone(obj1) 98 | after.name = 'frehaiku' 99 | console.log(obj1) 100 | console.log(after) -------------------------------------------------------------------------------- /JS/JSONP/JSONP.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 64 | 65 | -------------------------------------------------------------------------------- /JS/MiddleWare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/2/27. 3 | */ 4 | function MiddleWare() { 5 | this.storge = [] 6 | // 缓存传入参数 7 | this.options = null 8 | } 9 | 10 | MiddleWare.prototype.use = function (fn) { 11 | if (typeof fn != 'function') 12 | throw 'use Function first argument must be function' 13 | this.storge.push(fn) 14 | return this 15 | } 16 | 17 | MiddleWare.prototype.next = function () { 18 | if (this.storge[0] != null) { 19 | let excute = this.storge.shift() 20 | excute.call(this, this.options, this.next.bind(this)) 21 | } 22 | } 23 | 24 | MiddleWare.prototype.handleRequest = function (opt) { 25 | this.options = opt 26 | this.next() 27 | } 28 | 29 | let middleware = new MiddleWare() 30 | 31 | function validate(opts, next) { 32 | if (true) 33 | console.log('通过验证', opts.data) 34 | next() 35 | } 36 | 37 | function send(opts, next) { 38 | setTimeout(() => { 39 | console.log('send', opts.data) 40 | opts.url = 'http://www.baidu.com' 41 | next() 42 | }, 100) 43 | } 44 | 45 | function goTo(opts) { 46 | console.log('goTo', opts.url) 47 | } 48 | 49 | middleware.use(validate).use(send).use(goTo) 50 | middleware.handleRequest({data: {name: 'xuzhipeng', age: 20}}) -------------------------------------------------------------------------------- /JS/Promise/compareWhichRequestIsQuick.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/19. 3 | */ 4 | // n个接口,计算出花费最小时间的接口 5 | 6 | let urls = ['./a', './b', './c', './d'] 7 | 8 | let promises = urls.map((e, idx) => { 9 | return new Promise((resolve, reject) => { 10 | // throw new Error('happening error') 11 | 12 | const ago = +new Date() 13 | setTimeout(() => { 14 | /*if (idx == 2) 15 | throw new Error('happening error') 16 | */console.log(e) 17 | resolve(+new Date - ago) 18 | }, idx * 1000) 19 | }).catch(e => { 20 | console.log(e) 21 | }) 22 | }) 23 | 24 | Promise.all(promises).then((res) => { 25 | console.log(res) 26 | }) -------------------------------------------------------------------------------- /JS/Promise/data/data1.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": 100, 3 | "b": 200 4 | } -------------------------------------------------------------------------------- /JS/Promise/data/data2.json: -------------------------------------------------------------------------------- 1 | { 2 | "c": 15 3 | } -------------------------------------------------------------------------------- /JS/Promise/produceChar.js: -------------------------------------------------------------------------------- 1 | // 用尽可能快的方式生成有一万个相同字符的字符串 2 | 3 | function productChar(char) { 4 | let promiseArr = [] 5 | , total = '' 6 | 7 | for (let i = 0; i < 10000; i++) { 8 | promiseArr.push(new Promise((resolve) => { 9 | total += 'a' 10 | resolve(char) 11 | })) 12 | } 13 | 14 | Promise.all(promiseArr) 15 | .then(datas => { 16 | console.log(datas.join('')) 17 | }) 18 | } 19 | 20 | productChar('a') -------------------------------------------------------------------------------- /JS/Promise/promise-ajaxLoadImg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 12 | 46 | 47 | -------------------------------------------------------------------------------- /JS/Promise/promise-all.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const readFilePromise = function (fileName) { 5 | return new Promise(function (resolve, reject) { 6 | fs.readFile(fileName, function (err, data) { 7 | if (err) { 8 | reject(err) 9 | } else { 10 | resolve(data) 11 | } 12 | }) 13 | }) 14 | } 15 | 16 | const filePath1 = path.resolve(__dirname, './data/data1.json') 17 | const filePath2 = path.resolve(__dirname, './data/data2.json') 18 | 19 | const filePromise1 = readFilePromise(filePath1) 20 | const filePromise2 = readFilePromise(filePath2) 21 | 22 | // 读取多个文件成功的回调 23 | Promise.all([filePromise1, filePromise2]) 24 | .then(values => { 25 | console.log(JSON.parse(values[0])) 26 | console.log(JSON.parse(values[1])) 27 | }) -------------------------------------------------------------------------------- /JS/Promise/promise-race.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const readFilePromise = function (fileName) { 5 | return new Promise(function (resolve, reject) { 6 | fs.readFile(fileName, function (err, data) { 7 | if (err) { 8 | reject(err) 9 | } else { 10 | resolve(data) 11 | } 12 | }) 13 | }) 14 | } 15 | 16 | const filePath1 = path.resolve(__dirname, './data/data1.json') 17 | const filePath2 = path.resolve(__dirname, './data/data2.json') 18 | 19 | const filePromise1 = readFilePromise(filePath1) 20 | const filePromise2 = readFilePromise(filePath2) 21 | 22 | // race的含义与all相反,只要其中一个满足条件则执行 23 | Promise.race([filePromise1, filePromise2]) 24 | .then(datas => { 25 | console.log(JSON.parse(datas)) 26 | }) 27 | 28 | // race的setTimeout示例 29 | var p1 = new Promise(function (resolve, reject) { 30 | setTimeout(resolve, 500, 'one') 31 | }) 32 | 33 | var p2 = new Promise(function (resolve, reject) { 34 | setTimeout(resolve, 100, 'two') 35 | }) 36 | 37 | // 输出two,因为两个都完成,但是p2更快 38 | Promise.race([p1, p2]) 39 | .then(function (value) { 40 | console.log(value) 41 | }) 42 | 43 | 44 | var p3 = new Promise(function (resolve, reject) { 45 | setTimeout(resolve, 100, 'three') 46 | }) 47 | 48 | var p4 = new Promise(function (resolve, reject) { 49 | setTimeout(reject, 500, 'four') 50 | }) 51 | // p3更快,所以它完成了 52 | Promise.race([p3, p4]) 53 | .then(function (value) { 54 | console.log(value) 55 | }, function (reason) { 56 | 57 | }) 58 | 59 | 60 | var p5 = new Promise(function (resolve, reject) { 61 | setTimeout(resolve, 500, 'five') 62 | }) 63 | 64 | var p6 = new Promise(function (resolve, reject) { 65 | setTimeout(reject, 100, 'six') 66 | }) 67 | // p6时间更短,所以它能被reject接收到 68 | Promise.race([p5, p6]) 69 | .then(function (value) { 70 | console.log(value) 71 | }, function (reason) { 72 | console.log(reason) 73 | }) -------------------------------------------------------------------------------- /JS/Promise/promise-resolve.js: -------------------------------------------------------------------------------- 1 | // Promise.resolve(value) 方法返回一个以给定值后的Promise对象。 2 | // 如果这个值是thenable(即一个对象带有then方法),返回的promise会跟随这个thenable对象 3 | 4 | Promise.resolve({ 5 | then (resolve, reject) { 6 | resolve(200) 7 | } 8 | }) 9 | .then(data => { 10 | console.log(data) 11 | }) -------------------------------------------------------------------------------- /JS/Promise/promiseErrCatch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/7/3. 3 | */ 4 | 5 | // 1.工厂函数里面的reslove发生错误时,会从then的error,向后延伸到catch函数。 6 | // 一般在then后面不做error处理 7 | var promiseFactoryErr = function () { 8 | return new Promise( 9 | () => { 10 | throw new Error('error') 11 | } 12 | ) 13 | } 14 | 15 | promiseFactoryErr().then( 16 | () => {}, 17 | () => console.log('then inner catch') 18 | ) 19 | .catch(() => console.log('outer catch')) 20 | 21 | // 2. then内部发生的错误,不会立即被then内部的error函数捕获。 22 | // 而是传递给下一个catch函数,故一般promise的错误会在catch中捕获 23 | var promiseThenErr = function () { 24 | Promise.resolve() 25 | .then( 26 | () => { 27 | throw new Error('error') 28 | }, 29 | () => console.log('then inner catch') 30 | ) 31 | .catch(() => console.log('outer catch')) 32 | }() -------------------------------------------------------------------------------- /JS/Promise/readFilePromise.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const readFilePromise = function (fileName) { 4 | return new Promise((resolve, reject) => { 5 | fs.readFile(fileName, (err, data) => { 6 | // 异常捕获 7 | if (err) { 8 | reject(err) 9 | } else { 10 | resolve(data.toString()) 11 | } 12 | }) 13 | }) 14 | } 15 | 16 | const fullFileName = path.resolve(__dirname, './data/data1.json') 17 | const fullNamedata2 = path.resolve(__dirname, './data/data2.json') 18 | 19 | const result = readFilePromise(fullFileName) 20 | const result2 = readFilePromise(fullNamedata2) 21 | 22 | // 串联多个异步操作 23 | // 如果前面的步骤返回值是一个Promise对象的话, 24 | // 后面的then将会被当做这个返回的Promise的第一个then来对待 25 | result2 26 | // 参数中接受的参数是resolve传递的内容 27 | .then(data => { 28 | console.log(data) 29 | return result 30 | }) 31 | .then(data => { 32 | console.log(data) 33 | return JSON.parse(data).a 34 | }) 35 | // 如果then有多层操作,那么前面步骤return的值会被当做参数传递到后面步骤的函数 36 | .then(data => { 37 | console.log(data) 38 | }) 39 | 40 | // then接受两个参数,第一个参数会在执行resolve之后触发(还能传递参数) 41 | // 第二个参数会在执行reject之后触发,但是不建议这样使用,因为会产生一新的“分支” 42 | // 一般要采用最后一个.catch捕获异常 43 | .catch(err => { 44 | console.log(err.stack) 45 | }) -------------------------------------------------------------------------------- /JS/Promise/thenReturnPromise01.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用Promise实现调用完数组的全部元素之后,打印信息 3 | * Created by 海枯 on 2017/7/3. 4 | */ 5 | var arr = [1, 2, 3, 4] 6 | var promises = arr.map( 7 | ele => new Promise( 8 | (resolve, reject) => 9 | setTimeout(() => { 10 | console.log(`${ele}s later.`) 11 | // 注意:如果这里reject不注释掉 12 | // 1. promise状态不会再改成resolve,因为promise的状态是不可逆的,只能从Pending变为resolved,或者从Pending变为Rejected 13 | // 2. reject之后会马上执行catch回调,但是!!!后面的promise依然会顺序执行 14 | 15 | // reject(ele) 16 | resolve(ele) 17 | }, ele * 1000) 18 | ) 19 | ) 20 | 21 | Promise.resolve(arr) 22 | .then(arr => Promise.all(promises)) 23 | .then(promiseArrs => console.log('all promise excute complete!')) 24 | .catch(e => console.log('a error happen!')) -------------------------------------------------------------------------------- /JS/Promise/thenReturnPromise02.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 使用Promise实现调用完数组的全部元素之后,打印信息 3 | * 与01不同的时,要等前一个数组的异步操作执行完才能执行下一个元素 4 | * Created by 海枯 on 2017/7/3. 5 | */ 6 | var arr = [1, 2, 3, 4, 5, 6] 7 | 8 | var oneStepInto = Promise.resolve() 9 | 10 | var timeAsync = function (item) { 11 | return new Promise(resolve => 12 | setTimeout(() => { 13 | console.log(`${item}s...`) 14 | resolve(item) 15 | }, 1000) 16 | ) 17 | } 18 | var execute = function (datas) { 19 | console.log('1s after will poll print with interval 1s.') 20 | return datas.forEach(item => { 21 | oneStepInto = oneStepInto.then( 22 | () => timeAsync(item) 23 | ) 24 | }) 25 | } 26 | 27 | execute(arr) -------------------------------------------------------------------------------- /JS/async/asyncGenertor.js: -------------------------------------------------------------------------------- 1 | function asyncToGenerator(g) { 2 | return function () { 3 | var gen = g.apply(null, arguments) 4 | return new Promise((resolve, reject) => { 5 | function step(ret) { 6 | var { value, done } = gen.next(ret) 7 | if (done) return Promise.resolve(value) 8 | 9 | return Promise 10 | .resolve(value) 11 | .then(step) 12 | .catch(err => { 13 | return gen.throw(err) 14 | }) 15 | } 16 | 17 | try { 18 | resolve(step()) 19 | } catch (e) { 20 | reject(e) 21 | } 22 | }) 23 | } 24 | } 25 | 26 | function getDate() { 27 | return new Promise(r => 28 | setTimeout(() => { 29 | r(Date.now()) 30 | }, 1000) 31 | ) 32 | } 33 | 34 | // example start 35 | function* testG() { 36 | var data1 = yield getDate() 37 | console.log(data1) 38 | //throw new Error('reject sth') 39 | var data2 = yield getDate() 40 | console.log(data2) 41 | 42 | return 'success' 43 | } 44 | 45 | var asyncFn = asyncToGenerator(testG) 46 | asyncFn().then(console.log).catch(console.warn) 47 | 48 | // async call exmpale 49 | // async function testAsync() { 50 | // var data1 = await getDate() 51 | // console.log(data1) 52 | 53 | // var data2 = await getDate() 54 | // console.log(data2) 55 | 56 | // return 'success' 57 | // } 58 | // testAsync().then(console.log) -------------------------------------------------------------------------------- /JS/autoExecuteMoreHandler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/7/12. 3 | * 实现一个函数,可以给一个对象绑定函数, 4 | * 当对象任意属性发生变化的时候,可以执行绑定的函数。 5 | * 可以对同一个对象绑定多个函数。 6 | * 函数中的this指向this指向的第一个参数即绑定的对象 7 | */ 8 | ;(function () { 9 | const structor = function(obj) { 10 | for (let item in obj) 11 | if (obj.hasOwnProperty(item)) 12 | convert.call(obj, item, obj[item]) 13 | } 14 | 15 | const convert = function(key, val) { 16 | Object.defineProperty(this, key, { 17 | configurable: true, 18 | enumerable: true, 19 | get () { 20 | return val 21 | }, 22 | set (newValue) { 23 | if (newValue === val) return 24 | val = newValue 25 | dumpGoal(this) 26 | } 27 | }) 28 | } 29 | 30 | const dumpGoal = obj => { 31 | for (let i = 0; i < queues[obj].length; i++) 32 | queues[obj][i].call(obj) 33 | } 34 | 35 | let person = { 36 | name: 'aa', 37 | age: 11, 38 | title: '碉堡' 39 | } 40 | let queues = {} 41 | 42 | const bind = (object, callback) => { 43 | structor(object) 44 | if (!(object in queues)) { 45 | queues[object] = [] 46 | } 47 | queues[object].push(callback) 48 | } 49 | 50 | bind(person, function () { 51 | console.log(`输出name: ${this.name}`) 52 | }) 53 | bind(person, function () { 54 | console.log(`输出age: ${this.age}`) 55 | }) 56 | 57 | person.name = '名字' 58 | 59 | person.age = 18; 60 | })(); -------------------------------------------------------------------------------- /JS/bind-polyfill.js: -------------------------------------------------------------------------------- 1 | Function.prototype.selfBind = function (oThis) { 2 | if (typeof this !== 'function') 3 | throw new TypeError( 4 | "Function.prototype.bind - what is trying " + 5 | "to be bound is not callable" 6 | ) 7 | var args = [].slice.call(arguments, 1), 8 | fnThs = this; 9 | 10 | var f = function () { 11 | } 12 | var fBound = function () { 13 | return fnThs.apply( 14 | this instanceof f 15 | ? this : oThis 16 | , args.concat(Array.prototype.slice.call(arguments)) 17 | ) 18 | } 19 | // 若是new运算符时,则继承构造函数的prototype 20 | // 也便于对new运算符情况的判断 `this instanceof f` 21 | f.prototype = fnThs.prototype 22 | fBound.prototype = new f() 23 | return fBound 24 | }; 25 | 26 | var a = { 27 | age: 18, getAge: function () { 28 | console.log([].slice.call(arguments).reduce(function (a, b) { 29 | return a + b; 30 | })) 31 | } 32 | } 33 | 34 | 35 | var b = {age: 20} 36 | 37 | a.getAge.selfBind(b, 18)(20); 38 | 39 | /**对new 运算符的特殊处理**/ 40 | function foo(n) { 41 | this.name = n 42 | } 43 | var obj = {age: 22} 44 | var bind = foo.selfBind(obj) 45 | 46 | var bar = new bind('xuzhipeng') 47 | // 'frehaiku' 48 | console.log(obj) 49 | // 'xuzhipeng' 50 | console.log(bar) -------------------------------------------------------------------------------- /JS/cookie-crossdomain/getCookie.php: -------------------------------------------------------------------------------- 1 | 5 | // +---------------------------------------------------------------------- 6 | // | Description: 设置cookie 7 | // +---------------------------------------------------------------------- 8 | setcookie('uid', 1, time() + 60*60); 9 | ?> 10 | 11 | 12 | 13 | 14 | 16 | 17 | cookie跨域 18 | 19 | 20 | 21 | 22 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /JS/curryContinuedInvoke.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/9/3. 3 | */ 4 | function curryContinuedInvoking(...arg) { 5 | let finalArg = [].concat(arg.slice(1)) 6 | return function f1(...inner) { 7 | if (inner.length === 0) { 8 | return finalArg.reduce((...red) => arg[0].apply(null, red)) 9 | } 10 | else { 11 | finalArg = finalArg.concat(inner) 12 | return f1 13 | } 14 | } 15 | } 16 | 17 | function add(a, b) { 18 | return a + b 19 | } 20 | 21 | console.log(curryContinuedInvoking(add, 2, 3)(5)(15)(25)()) -------------------------------------------------------------------------------- /JS/cvteDiffDemo.js: -------------------------------------------------------------------------------- 1 | function isArray(obj) { 2 | return Array.isArray ? Array.isArray(obj) : Object.prototype.toString.call(obj) === '[object Array]' 3 | } 4 | function isObject(obj) { 5 | return Object.prototype.toString.call(obj) === '[object Object]' 6 | } 7 | function diff (c1, c2) { 8 | let type1 = typeof c1 9 | let type2 = typeof c2 10 | if (type1 !== type2) 11 | return false; 12 | else if(isObject(c1) && isObject(c2)) { 13 | let k1Len = Object.keys(c1).length 14 | let k2Len = Object.keys(c2).length 15 | if (k1Len != k2Len) 16 | return false 17 | else { 18 | for (let item in c1) 19 | if (c1.hasOwnProperty(item)) 20 | if (!isObject(c1[item]) && !isObject(c2[item])) 21 | return c1[item] === c2[item] 22 | else if (!diff(c1[item], c2[item])) 23 | return false 24 | return true 25 | } 26 | } else if (isArray(c1) && isArray(c2)) { 27 | if (c1.length != c2.length) 28 | return false 29 | return c1.every((e, idx) => diff(c1[idx], c2[idx])) 30 | } else { 31 | return true 32 | } 33 | } 34 | 35 | console.log(diff(1,1)) // true 36 | console.log(diff(1,'1')) // false 37 | console.log(diff({name: 'cvte'},{name:'cvte'}))// true 38 | console.log(diff({name: 'cvte'},{name:'seewo'})) //false -------------------------------------------------------------------------------- /JS/dataSingleDirectionBind.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 数据的单向绑定 6 | 7 | 8 | 9 |

年龄

10 | 11 | 44 | 45 | -------------------------------------------------------------------------------- /JS/extends/combinationInheritance.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 原型链和构造函数的组合式继承 3 | * Super---> name 4 | * Sub ---> age 5 | **/ 6 | 7 | function Super(name) { 8 | this.name = name; 9 | } 10 | 11 | Super.prototype.getName = function () { 12 | return this.name; 13 | } 14 | 15 | function Sub(name, age) { 16 | Super.call(this, name); 17 | this.age = age; 18 | } 19 | 20 | Sub.prototype = new Super(); 21 | Sub.constructor = Sub; 22 | Sub.prototype.sayAge = function () { 23 | return this.age; 24 | } 25 | 26 | var instance1 = new Sub('haiku', 18); 27 | console.log(instance1.getName()); 28 | console.log(instance1.sayAge()); -------------------------------------------------------------------------------- /JS/extends/constructorStealing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 构造函数模式 3 | * 问题:方法都在构造函数定义,因此函数复用无法提起 4 | * 而且在超类型定义的方法,在子类型是不可见的 5 | * */ 6 | 7 | function Super(name) { 8 | this.name = name; 9 | this.colors = ['red', 'blue']; 10 | } 11 | 12 | function Sub(name) { 13 | Super.call(this, name); 14 | 15 | this.age = 18; 16 | } 17 | 18 | var instance1 = new Sub('haiku'); 19 | instance1.colors.push('green'); 20 | console.log(instance1.colors); 21 | 22 | var instance2 = new Sub('Nicholas'); 23 | console.log(instance2.colors); 24 | console.log(instance2.age); -------------------------------------------------------------------------------- /JS/extends/parasiticCombination.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 寄生组合式继承 3 | * 背景:在组件继承中,父级的构造函数被调用了两次,而且子对象中存在着两个实例属性(实例一个,原型链一个),造成了实例属性冗余 4 | * 该种继承方式,在组合继承的基础上,用寄生式继承,继承父级原型链中的方法 5 | * */ 6 | 7 | function parasiticInherit(obj) { 8 | var o = Object(obj.prototype); 9 | o.constructor = obj; 10 | return o; 11 | } 12 | 13 | function Super(name) { 14 | this.name = name; 15 | this.colors = ['red', 'blue']; 16 | } 17 | 18 | Super.prototype.sayName = function () { 19 | console.log(this.name); 20 | } 21 | 22 | function Sub() { 23 | Super.apply(this, arguments); 24 | 25 | this.age = arguments[1]; 26 | } 27 | 28 | Sub.prototype = parasiticInherit(Super); 29 | Sub.constructor = Sub; 30 | 31 | Sub.prototype.sayAge = function () { 32 | console.log(this.age); 33 | } 34 | 35 | var instance1 = new Sub('haiku', 18); 36 | instance1.colors.push('green'); 37 | 38 | console.log(instance1.sayName()); 39 | 40 | console.log(instance1.sayAge()); -------------------------------------------------------------------------------- /JS/extends/parasiticExtends.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 寄生式继承 3 | * 思路与寄生构造函数和工厂模式类似,创建一个仅用于封装继承过程的函数 4 | * 该函数以某种方式来增强对象,返回新对象的函数 5 | * 6 | * 缺点:达不到函数的复用 7 | * */ 8 | 9 | /** 10 | * 对象深复制函数 11 | * @param obj 12 | * @returns clone 13 | */ 14 | function cloneObj(obj) { 15 | var twin; 16 | var typeFn = function (val) { 17 | return Object.prototype.toString.call(val); 18 | } 19 | if (typeFn(obj) === "[object Array]") { 20 | twin = obj.slice(); 21 | } else if (obj instanceof Object) { 22 | twin = {}; 23 | for (var attr in obj) { 24 | if (obj.hasOwnProperty(attr)) { 25 | twin[attr] = cloneObj(obj[attr]); 26 | } 27 | } 28 | } else { 29 | twin = obj; 30 | } 31 | 32 | return twin; 33 | } 34 | function extend(original) { 35 | 36 | var clone = cloneObj(original); 37 | clone.sayHi = function () { 38 | console.log('Hi'); 39 | } 40 | return clone; 41 | } 42 | 43 | var person = { 44 | name: "Nicholas", 45 | friends: ["Shelby", "Court", "Van"] 46 | }; 47 | 48 | var instance1 = extend(person); 49 | instance1.name = 'Me'; 50 | instance1.friends.push('Haiku'); 51 | console.log(person.name); 52 | console.log(person.friends); 53 | 54 | var instance2 = extend(person); 55 | instance2.friends.push('You'); 56 | console.log(person.friends); 57 | -------------------------------------------------------------------------------- /JS/extends/prototypalInheritace.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 原型式继承 3 | * 缺陷:引用类型的值始终会共享相应的值,就像原型链模式一样 4 | * */ 5 | 6 | function object(o) { 7 | var F = function () {}; 8 | F.prototype = o; 9 | 10 | return new F(); 11 | } 12 | 13 | var person = { 14 | name: 'Nicholas', 15 | friends: ['Shelby', 'Court', 'Haiku'] 16 | }; 17 | 18 | var instance1 = object(person); 19 | instance1.name = 'Van'; 20 | instance1.friends.push('God'); 21 | console.log(instance1.name); 22 | console.log(person.name); 23 | console.log("person.friends: " + person.friends); 24 | 25 | var instance2 = object(person); 26 | instance2.friends.push('Git'); 27 | 28 | console.log(person.name); 29 | console.log(person.friends); 30 | 31 | /*ES6通过新增Object.create()方法规范了原型式的继承, 32 | * 一个新对象的原型对象, 33 | * 一个为新对象定义的额外属性的对象, 34 | * 传入一个参数时,跟Object.create()与object()方法行为相同 35 | * */ 36 | var instance3 = Object.create(person); 37 | instance3.name = 'haiku'; 38 | instance3.friends.push('Rob'); 39 | 40 | console.log(person.friends); 41 | -------------------------------------------------------------------------------- /JS/extends/prototypeExtends.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 原型链继承 3 | */ 4 | 5 | function Super() { 6 | this.property = true; 7 | this.bugArr = ['red', 'blue']; 8 | this.bugObject = {}; 9 | } 10 | 11 | Super.prototype.getSuperValue = function () { 12 | return this.property; 13 | } 14 | 15 | function Sub() { 16 | this.subProperty = false; 17 | } 18 | 19 | Sub.prototype = new Super(); 20 | 21 | Sub.prototype.getSubProperty = function () { 22 | return this.subProperty; 23 | } 24 | 25 | var subClass = new Sub(); 26 | subClass.constructor = Sub; 27 | 28 | // 改变 bugArr与bugObject 29 | subClass.bugArr.push('green'); 30 | subClass.bugObject.color = 'green'; 31 | 32 | console.log(subClass.getSuperValue()); 33 | 34 | /*判断是否属于某个实例*/ 35 | console.log("subClass is belong to Sub? " + (subClass instanceof Sub)); 36 | console.log("subClass is belong to Super? " + (subClass instanceof Super)); 37 | console.log("subClass is belong to Object? " + (subClass instanceof Object)); 38 | 39 | console.log("---------isPrototypeOf---------"); 40 | 41 | /*第二种方式是用isPrototypeOf方法*/ 42 | console.log("subClass is belong to Sub? " + (Sub.prototype.isPrototypeOf(subClass))); 43 | console.log("subClass is belong to Super? " + (Super.prototype.isPrototypeOf(subClass))); 44 | console.log("subClass is belong to Object? " + (Super.prototype.isPrototypeOf(subClass))); 45 | 46 | var subClass1 = new Sub(); 47 | // 原型继承的第一个问题 当是包含引用类型值的原型,与subClass共享了同一个成员, 48 | console.log("subClass1 bugArr " + subClass1.bugArr); 49 | console.log("subClass1 bugObject " + subClass1.bugObject); 50 | 51 | // 原型继承的第二个问题是 没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数 -------------------------------------------------------------------------------- /JS/fileReaderDemo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 17 | 18 | 19 |
20 | 25 | 26 |
27 | 拖拽文件提交 28 |
29 |
30 | 31 | 73 | 74 | -------------------------------------------------------------------------------- /JS/flatteningToArr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/8/31. 3 | */ 4 | let arr = [1,2,3,[1,2,3],[2,[3,4],3]] 5 | 6 | function flatteningToArr1(arr) { 7 | let str = JSON.stringify(arr) 8 | let matchReg = /[\[\]]/g 9 | function replaceHandle(p, offset) { 10 | if (offset != 0 && offset != str.length - 1) 11 | return '' 12 | else 13 | return p 14 | } 15 | return JSON.parse(str.replace(matchReg, replaceHandle)) 16 | } 17 | 18 | function flatteningToArr2(data) { 19 | let ans = [] 20 | return function f1(arr) { 21 | arr.forEach(ele => { 22 | if (ele instanceof Array) { 23 | f1(ele) 24 | } else { 25 | ans.push(ele) 26 | } 27 | }) 28 | return ans 29 | }(data) 30 | } 31 | 32 | console.log(flatteningToArr1(arr)) 33 | console.log(flatteningToArr2(arr)) -------------------------------------------------------------------------------- /JS/formValidator/es6Primary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 策略模式 6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /JS/formValidator/es6Proxy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6Proxy 6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /JS/formValidator/js/es6Proxy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/5/17. 3 | */ 4 | // 为false时表示验证不通过 5 | const validators = { 6 | minLength (value, length) { 7 | return value.length >= length 8 | }, 9 | isMobile (value) { 10 | return /^1(3|5|7|8|9)[0-9]{9}$/.test(value) 11 | }, 12 | isEmail (value) { 13 | return /^\w+([+-.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value) 14 | } 15 | } 16 | 17 | function validator(target, validator, errorMsg) { 18 | return new Proxy(target, { 19 | _validator: validator, 20 | set (target, key, value, proxy) { 21 | let errMsg = errorMsg 22 | if (value == '') { 23 | alert(`${errMsg[key]}不能为空`) 24 | return target[key] = false 25 | } 26 | 27 | let va = this._validator[key] 28 | if (!!va(value)) { 29 | return Reflect.set(target, key, value, proxy) 30 | } else { 31 | alert(`${errMsg[key]}格式不正确`) 32 | return target[key] = false 33 | } 34 | } 35 | }) 36 | } 37 | 38 | const errorMsg = {name: '用户名', passwd: '密码', mobile: '手机号码', email: '邮箱地址'} 39 | const vali = validator({}, validators, errorMsg) 40 | 41 | let registerForm = document.querySelector('#registerForm') 42 | registerForm.addEventListener('submit', function (e) { 43 | let validatorNext = function* () { 44 | yield vali.name = registerForm.userName.value 45 | yield vali.passwd = registerForm.passWord.value 46 | yield vali.mobile = registerForm.phoneNumber.value 47 | yield vali.email = registerForm.emailAddress.value 48 | } 49 | 50 | let validator = validatorNext() 51 | 52 | for (let correct of validator) { 53 | if (!correct) { 54 | e.preventDefault(); 55 | return {done: true} 56 | } 57 | } 58 | }, false) 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /JS/formValidator/js/primary.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/5/16. 3 | */ 4 | 5 | // 具体策略角色 6 | const strategies = { 7 | isNonEmpty (value, errorMsg) { 8 | return value === '' ? errorMsg : void 0 9 | }, 10 | minLength (value, length, errorMsg) { 11 | return value.length < length ? errorMsg : void 0 12 | }, 13 | isMobile (value, error) { 14 | return !/^1(3|5|7|8|9)[0-9]{9}$/.test(value) ? 15 | error : void 0 16 | }, 17 | isEmail (value, error) { 18 | return !/^\w+([+-.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value) ? 19 | error : void 0 20 | } 21 | } 22 | 23 | class Validator { 24 | constructor() { 25 | this.cache = [] // 保存校验规则 26 | } 27 | 28 | add(dom, rules) { 29 | for (let rule of rules) { 30 | // [minLength, 6] 31 | let strategyArg = rule.strategy.split(/\s*:\s*/) 32 | let errMsg = rule.errorMsg 33 | 34 | this.cache.push(() => { 35 | let attr = strategyArg.shift() // minLength 36 | strategyArg.unshift(dom.value) // [dom.value, 6] 37 | strategyArg.push(errMsg) 38 | 39 | return strategies[attr].apply(dom, strategyArg) 40 | }) 41 | } 42 | } 43 | 44 | start() { 45 | for (let fn of this.cache) { 46 | var errorMsg = fn(); 47 | if (errorMsg) { 48 | return errorMsg 49 | } 50 | } 51 | } 52 | } 53 | 54 | let regForm = document.querySelector('#registerForm') 55 | 56 | const validatorFunc = () => { 57 | var validator = new Validator() 58 | 59 | validator.add(regForm.userName, [ 60 | { 61 | strategy: 'isNonEmpty', 62 | errorMsg: '用户名不能为空' 63 | }, 64 | { 65 | strategy: 'minLength:6', 66 | errorMsg: '用户名的长度不能小于6位' 67 | } 68 | ]) 69 | 70 | validator.add(regForm.passWord, [ 71 | { 72 | strategy: 'minLength:6', 73 | errorMsg: '密码的长度不能小于6位' 74 | } 75 | ]) 76 | 77 | validator.add(regForm.phoneNumber, [ 78 | { 79 | strategy: 'isMobile', 80 | errorMsg: '手机号格式不匹配' 81 | } 82 | ]) 83 | 84 | validator.add(regForm.emailAddress, [ 85 | { 86 | strategy: 'isEmail', 87 | errorMsg: '邮箱格式不合法' 88 | } 89 | ]) 90 | 91 | return validator.start() 92 | } 93 | 94 | 95 | regForm.addEventListener('submit', function (e) { 96 | let errorMsg = validatorFunc() 97 | if (errorMsg) { 98 | alert(errorMsg) 99 | e.preventDefault() 100 | } 101 | 102 | }, false) -------------------------------------------------------------------------------- /JS/formValidator/proxyDemo/pipeExecute.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by frehaiku on 2017/5/17. 3 | */ 4 | var pipe = (function () { 5 | return value => { 6 | var funcStack = [] 7 | var oproxy = new Proxy({}, { 8 | get (pipeObject, fnName) { 9 | if (fnName == 'get') { 10 | return funcStack.reduce((val, fn) => { 11 | return fn(val) 12 | }, value) 13 | } 14 | funcStack.push(global[fnName]) 15 | return oproxy 16 | } 17 | }) 18 | 19 | return oproxy 20 | } 21 | })() 22 | 23 | var double = n => n * 2 24 | var pow = n => n * n 25 | var reverseInt = n => n.toString().split("").reverse().join("") | 0 26 | 27 | pipe(3).double.pow.reverseInt.get -------------------------------------------------------------------------------- /JS/new-polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/11/28. 3 | */ 4 | 5 | /** 6 | * new运算符内部实现 7 | */ 8 | function newPolyfill(constructor, ...args) { 9 | var obj = {} 10 | obj.__proto__ = constructor.prototype 11 | var ret = constructor.apply(obj, args) 12 | return typeof ret == 'object' ? ret : obj 13 | } 14 | 15 | function newPolyfillNoProto(constructor, ...args) { 16 | var obj 17 | var F = function () {} 18 | F.prototype = constructor.prototype 19 | obj = new F() 20 | 21 | var ret = constructor.apply(obj, args) 22 | return typeof ret == 'object' ? ret : obj 23 | } 24 | 25 | function Person(name, age) { 26 | this.name = name 27 | this.age = age 28 | } 29 | Person.prototype.sayName = function () { 30 | console.log(this.name) 31 | } 32 | 33 | var i1 = newPolyfill(Person, 'xuzhipeng', 22) 34 | console.log(i1.name) 35 | console.log(i1.age) 36 | i1.sayName() -------------------------------------------------------------------------------- /JS/quitAsyncAwait.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2017/10/14. 3 | */ 4 | function timeout(ms) { 5 | return new Promise((resolve) => { 6 | setTimeout(() => { 7 | resolve('111') 8 | }, ms); 9 | }) 10 | } 11 | 12 | async function asyncPrint(value, ms) { 13 | var param = await timeout(ms); 14 | console.log(param) 15 | console.log(value); 16 | // throw new Error('出错了') 17 | } 18 | 19 | /*asyncPrint('hello world', 1000) 20 | .then(v => console.log(v)) 21 | .catch(v => console.log(v))*/ 22 | 23 | async function f() { 24 | return await 123; 25 | } 26 | // f().then(v => console.log(v)) 27 | 28 | async function parallelFunc() { 29 | var fns = [ 30 | setTimeout(() => console.log('1000 ms after'), 1000), 31 | setTimeout(() => console.log('2000 ms after'), 2000), 32 | setTimeout(() => console.log('3000 ms after'), 3000), 33 | ] 34 | fns.forEach(async function (item, idx) { 35 | await item() 36 | }) 37 | } 38 | // parallelFunc() 39 | 40 | async function dependFunc0() { 41 | var fns = [ 42 | setTimeout(() => console.log('1000 ms after'), 1000), 43 | setTimeout(() => console.log('2000 ms after'), 2000), 44 | setTimeout(() => console.log('3000 ms after'), 3000), 45 | ] 46 | for (let fn of fns) { 47 | await fn 48 | } 49 | } 50 | // dependFunc0() 51 | 52 | async function dependFunc1() { 53 | var seconds = [1000, 2000, 3000] 54 | 55 | function afterRun(ms) { 56 | return new Promise(resolve => { 57 | setTimeout(() => { 58 | console.log(`after ${ms} seconds`) 59 | resolve(ms) 60 | }, ms) 61 | }) 62 | } 63 | 64 | for (let sec of seconds) 65 | await afterRun(sec) 66 | 67 | } 68 | // dependFunc1() 69 | 70 | /*Promise.resolve(1) 71 | .catch(reject => { 72 | console.log(reject) 73 | }) 74 | .then(resolve => { 75 | // throw new Error('发送错误') 76 | console.log(resolve) 77 | return 2 78 | }) 79 | .then(resolve => { 80 | console.log(resolve) 81 | return 3 82 | })*/ 83 | 84 | /*var bb = 1 85 | function aa(bb) { 86 | bb = 2 87 | console.log(bb) 88 | } 89 | aa(bb) 90 | console.log(bb)*/ 91 | 92 | /*var sangfor = NaN 93 | function sangfor() {} 94 | 95 | if (typeof sangfor === 'number') 96 | console.log(100) 97 | else if (typeof sangfor === 'function') 98 | console.log(200) 99 | else if (typeof sangfor === 'object') 100 | console.log(300) 101 | else 102 | console.log(400)*/ 103 | 104 | /*let x = { 105 | toString () { 106 | return 20 107 | }, 108 | valueOf () { 109 | return '30' 110 | } 111 | } 112 | 113 | console.log(x == '20') 114 | console.log(x == 30) 115 | */ 116 | 117 | /* 118 | function load() { 119 | return Promise.resolve('sangfor') 120 | .then(result => { 121 | throw result 122 | }) 123 | .catch(result => 'error') 124 | } 125 | async function fn() { 126 | console.log(await load()) 127 | } 128 | fn()*/ 129 | /*Promise.resolve('sangfor') 130 | .then(result => { 131 | throw result 132 | }) 133 | .catch(console.error) 134 | .then(console.log)*/ 135 | 136 | /* 137 | ;(function () { 138 | for (var i = 0; i < 5;i++) 139 | setTimeout(console.log, i, i) 140 | }())*/ 141 | 142 | function findReverse(num, once, arr) { 143 | arr = arr.map(e => +e) 144 | num = num - 1 145 | var min = Math.min.apply(null, arr) 146 | if (min == 0) { 147 | console.log(arr.join(' ')) 148 | } else { 149 | var idx = arr.indexOf(min) 150 | var i = num 151 | var ans = 0 152 | while (1) { 153 | if (i != idx) { 154 | ans++ 155 | arr[i]-- 156 | } else { 157 | if (arr[i] > 0) { 158 | ans++ 159 | arr[i]-- 160 | } else { 161 | break 162 | } 163 | } 164 | if (i - 1 < 0) 165 | i = once 166 | i--; 167 | } 168 | arr[idx] += ans 169 | console.log(arr.join(' ')) 170 | } 171 | } 172 | findReverse(2, 3, ['6', '1', '1']) -------------------------------------------------------------------------------- /JS/textboxSelect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | select选择文本 8 | 9 | 10 |
11 | 27 | 28 |
29 | 30 | 72 | 73 | -------------------------------------------------------------------------------- /JS/touches.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | touches内置对象 8 | 35 | 36 | 37 |
38 |
39 |
40 |
41 |
42 | 43 | 102 | 103 | -------------------------------------------------------------------------------- /JS/underscore/debounce.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/9. 3 | */ 4 | 5 | /** 6 | * 函数防抖 7 | */ 8 | function debounce(func, wait, immediate) { 9 | var timeout, result 10 | 11 | var _debounce = function (...args) { 12 | if (timeout) 13 | clearTimeout(timeout) 14 | // 立即执行 15 | if (immediate) { 16 | // 如果已经执行过,就不再执行 17 | var callNow = !timeout 18 | timeout = setTimeout(function () { 19 | timeout = null 20 | }, wait) 21 | 22 | if (callNow) 23 | result = func.apply(this, args) 24 | } else { 25 | timeout = setTimeout(() => { 26 | // 解决回调中this的指向,与参数传递的问题(如event) 27 | func.apply(this, args) 28 | }, wait) 29 | } 30 | return result 31 | } 32 | 33 | /** 34 | * 取消防抖的计时,这样再去触发就会立即执行 35 | */ 36 | _debounce.cancel = function () { 37 | clearTimeout(timeout) 38 | timeout = null 39 | } 40 | return _debounce 41 | } -------------------------------------------------------------------------------- /JS/underscore/debouncePage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | debounce 8 | 19 | 20 | 21 | 22 |
23 | 24 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /JS/underscore/throttle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/3/9. 3 | */ 4 | 5 | /** 6 | * 时间比较写法,特点:执行前马上会触发一次 7 | * @param func 8 | * @param wait 9 | * @returns {Function} 10 | */ 11 | function throttleDate(func, wait) { 12 | var last = 0, context, now 13 | return function (...args) { 14 | context = this 15 | now = +new Date() 16 | if (now - last >= wait) { 17 | func.apply(context, args) 18 | last = now 19 | } 20 | } 21 | } 22 | 23 | /** 24 | * 定时器写法,特点:执行结束前会触发一次 25 | * @param func 26 | * @param wait 27 | * @returns {Function} 28 | */ 29 | function throttleTimeout(func, wait) { 30 | var timeout, context 31 | return function (...args) { 32 | context = this 33 | if (!timeout) 34 | timeout = setTimeout(() => { 35 | timeout = null 36 | func.apply(context, args) 37 | }, wait) 38 | } 39 | } 40 | 41 | /** 42 | * 结合两种写法 43 | * @param func 44 | * @param wait 45 | * @param options = {leading, trailing} 46 | */ 47 | function throttle(func, wait, options = {leading: true, trailing: true}) { 48 | var previous = 0, timeout, context 49 | var later = function (args) { 50 | previous = +new Date() 51 | timeout = null 52 | func.apply(this, args) 53 | } 54 | 55 | var _throttle = function (...args) { 56 | context = this 57 | var now = +new Date() 58 | var remaining = wait - (options.leading ? now - previous : 0) 59 | 60 | // 超过了间隔时间未操作 61 | if (remaining <= 0) { 62 | if (timeout) { 63 | clearTimeout(timeout) 64 | timeout = null 65 | } 66 | 67 | previous = now 68 | func.apply(context, args) 69 | } else if (!timeout && options.trailing) { 70 | timeout = setTimeout(later.bind(context, args), remaining) 71 | } 72 | } 73 | 74 | _throttle.cancel = function () { 75 | clearTimeout(timeout) 76 | previous = 0 77 | timeout = null 78 | } 79 | 80 | return _throttle 81 | } -------------------------------------------------------------------------------- /JS/underscore/throttlePage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | throttle 8 | 19 | 20 | 21 | 22 |
23 | 24 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /JS/vue-mvvm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue MVVM双向绑定 6 | 7 | 8 | 9 |

10 | 11 | 161 | 162 | -------------------------------------------------------------------------------- /JS/window-name-cross-domain/data.php: -------------------------------------------------------------------------------- 1 | window.name = "{\"name\":\"xuzhipeng\", \"age\":21}"; ' 3 | ?> -------------------------------------------------------------------------------- /JS/window-name-cross-domain/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 49 | 50 | -------------------------------------------------------------------------------- /JS/window-name-cross-domain/proxy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | Document 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Network/index.md: -------------------------------------------------------------------------------- 1 | ## 在浏览器中输入www.baidu.com后执行的全部过程 2 | 3 | 1. 浏览器获取输入的域名www.baidu.com 4 | 2. 浏览器向DNS请求解析www.baidu.com的IP地址 5 | 3. 浏览器与服务器建立TCP连接(三次握手过程) 6 | 4. 浏览器发出HTTP请求,请求百度首页 7 | 5. 服务器通过HTTP响应把请求页数据发送给浏览器 8 | 6. TCP释放连接(四次挥手过程) 9 | 7. 浏览器将首页文件进行解析,并将WEB页显示给用户 10 | 11 | **涉及到的协议** 12 | 1. 应用层:HTTP(超文本传输协议),DNS(域名解析服务,将域名转换为IP) 13 | 2. 传输层:TCP(为HTTP提供可靠的数据传输),UDP(DNS使用UDP传输) 14 | 3. 网络层:IP(IP数据报传输和路由选择),ICMP(提供网络传输过程的差错检查),ARP(将本地的默认网关IP地址映射成物理MAC地址) 15 | 16 | ## 简述DNS域名系统的工作原理 17 | 18 | 1. 首先会调用解析程序,并成为一个DNS用户,把待解析的域名放在DNS请求报文中,以UDP数据报的形式发送给本地域名服务器 19 | 2. 本地域名服务器查找到相应域名的IP地址后,就将该域名的IP地址信息放入应答报文中返回给客户进程 20 | 3. 如果本地域名服务器没有直接查找到对应的IP地址,则向根域名服务器发出迭代查询,再将查询的IP地址信息回传给客户程序 21 | 22 | 简单答: 23 | 1. 浏览器缓存查找 24 | 2. 系统缓存中查找 25 | 3. 路由器缓存中查找 26 | 4. 第三方运营商中查找 27 | 28 | ## 简述ARP的工作原理 29 | 30 | 1. 每个主机都会在自己的ARP缓存区中建立一个表,以表示IP地址和MAC地址之间的对应关系 31 | 2. 当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机IP地址,源主机MAC地址,目的主机IP地址。 32 | 3. 当本网络的所有主机收到该ARP数据包时,首先检查数据包的地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入ARP列表中。如果存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址 33 | 4. 源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。如果源主机一直没有收到ARP响应包,表示ARP查询失败 34 | 35 | 广播发送ARP请求,单播发送ARP响应 36 | 37 | ## HTTP基本构成 38 | 39 | Request中,由Request line(请求行)、Header(请求头)、Body(可选)构成。三者中间用CLRF(换行符隔开) 40 | 41 | - Request line行中由 `Method SP Request-URL SP httpVersion CRLF`构成,method就是GET、POST等方法,SP对应ASCII码中的空格,如 `GET http://www.meitu.com HTTP/1.1` 42 | - Header部分由键值对构成,`key: 空格 value CRLF` 43 | - 常见的请求字段头 44 | - Host 客户机想访问的主机ip,在http1.0中必须包含此头 45 | - Accept 表示浏览器支持处理的数据类型 46 | - Accept-Encoding 表示支持的数据压缩格式 47 | - Accept-language 表示客户端的语言环境 48 | - Referer:从哪个url来 49 | - user-agent:客户端身份标识 50 | - cookie:客户端一种存储数据的方式 -------------------------------------------------------------------------------- /Node/memory-leak/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2019/7/21. 3 | */ 4 | const {EventEmitter} = require('events'); 5 | const heapdump = require('heapdump'); 6 | 7 | global.test = new EventEmitter(); 8 | heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot'); 9 | 10 | function run3() { 11 | const innerData = new Buffer(100); 12 | const outClosure3 = function () { 13 | void innerData; 14 | }; 15 | test.on('error', () => { 16 | console.log('error'); 17 | }); 18 | outClosure3(); 19 | } 20 | 21 | for(let i = 0; i < 10; i++) { 22 | run3(); 23 | } 24 | 25 | gc(); 26 | 27 | heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot'); -------------------------------------------------------------------------------- /Node/memory-leak/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "memory-leak", 3 | "version": "1.0.0", 4 | "description": "Reproduce memory-leak solution", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node --expose-gc index.js" 8 | }, 9 | "author": "frehkxu", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /webpack/treeShakingTheory/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["transform-runtime"] 4 | } -------------------------------------------------------------------------------- /webpack/treeShakingTheory/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /webpack/treeShakingTheory/bundle.js: -------------------------------------------------------------------------------- 1 | !function(t){var n={};function r(e){if(n[e])return n[e].exports;var o=n[e]={i:e,l:!1,exports:{}};return t[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=t,r.c=n,r.i=function(t){return t},r.d=function(t,n,e){r.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:e})},r.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(n,"a",n),n},r.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},r.p="",r(r.s=1)}([function(t,n,r){"use strict";n.a=class{toString(){return"V8"}}},function(t,n,r){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var e=r(0);console.log(new class{constructor(t){this.engine=t}toString(){return this.engine.toString()+"Sports Car"}}(new e.a).toString())}]); -------------------------------------------------------------------------------- /webpack/treeShakingTheory/car.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/2/25. 3 | */ 4 | import {V8Engine} from './engine' 5 | 6 | class SportsCar { 7 | constructor (engine) { 8 | this.engine = engine 9 | } 10 | 11 | toString() { 12 | return this.engine.toString() + 'Sports Car' 13 | } 14 | } 15 | 16 | console.log(new SportsCar(new V8Engine()).toString()) -------------------------------------------------------------------------------- /webpack/treeShakingTheory/engine.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/2/25. 3 | */ 4 | export class V5Engine { 5 | toString () { 6 | return 'V5' 7 | } 8 | } 9 | 10 | export class V8Engine { 11 | toString () { 12 | return 'V8' 13 | } 14 | } 15 | 16 | export function getVersion() { 17 | return '1.0' 18 | } -------------------------------------------------------------------------------- /webpack/treeShakingTheory/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "treeshaking", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "bundle.js", 6 | "dependencies": { 7 | "babel-loader": "^7.1.3", 8 | "babel-plugin-transform-runtime": "^6.23.0", 9 | "babel-preset-es2015": "^6.24.1", 10 | "uglifyjs-webpack-plugin": "^1.2.2", 11 | "webpack": "^2.7.0" 12 | }, 13 | "devDependencies": { 14 | "babel-core": "^6.26.0", 15 | "babel-loader": "^7.1.3", 16 | "babel-plugin-transform-runtime": "^6.23.0", 17 | "babel-preset-es2015": "^6.24.1" 18 | }, 19 | "scripts": { 20 | "test": "echo \"Error: no test specified\" && exit 1" 21 | }, 22 | "author": "", 23 | "license": "ISC" 24 | } 25 | -------------------------------------------------------------------------------- /webpack/treeShakingTheory/treeShakingTheory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /webpack/treeShakingTheory/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 海枯 on 2018/2/25. 3 | */ 4 | var UglifyJSPlugin = require('uglifyjs-webpack-plugin') 5 | 6 | module.exports = { 7 | entry: './car.js', 8 | output: { 9 | filename: 'bundle.js' 10 | }, 11 | /*module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | exclude: /node_modules/, 16 | use: { 17 | loader: 'babel-loader'/!*, 18 | options: { 19 | cacheDirectory: true 20 | }*!/ 21 | } 22 | } 23 | ] 24 | },*/ 25 | resolve: { 26 | extensions: ['.js'] 27 | }, 28 | plugins: [ 29 | new UglifyJSPlugin() 30 | ] 31 | } --------------------------------------------------------------------------------