{"id":13672332,"url":"https://github.com/wuxianqiang/libraries","last_synced_at":"2025-04-15T15:39:15.471Z","repository":{"id":126583067,"uuid":"107532446","full_name":"wuxianqiang/libraries","owner":"wuxianqiang","description":"方法库","archived":false,"fork":false,"pushed_at":"2020-01-09T02:30:47.000Z","size":269,"stargazers_count":51,"open_issues_count":0,"forks_count":21,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-28T22:01:58.386Z","etag":null,"topics":["javascript","jquery"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wuxianqiang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-10-19T10:31:24.000Z","updated_at":"2022-06-10T02:42:47.000Z","dependencies_parsed_at":"2023-03-13T11:36:50.082Z","dependency_job_id":null,"html_url":"https://github.com/wuxianqiang/libraries","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wuxianqiang%2Flibraries","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wuxianqiang%2Flibraries/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wuxianqiang%2Flibraries/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wuxianqiang%2Flibraries/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wuxianqiang","download_url":"https://codeload.github.com/wuxianqiang/libraries/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249100030,"owners_count":21212767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","jquery"],"created_at":"2024-08-02T09:01:32.514Z","updated_at":"2025-04-15T15:39:15.453Z","avatar_url":"https://github.com/wuxianqiang.png","language":null,"funding_links":[],"categories":["Others"],"sub_categories":[],"readme":"# libraries\n\n# 目录\n- [插入排序算法](#插入排序算法)\n- [函数防抖](#函数防抖)\n- [函数节流](#函数节流)\n- [数组展平](#数组展平)\n- [寻找最大值](#寻找最大值)\n- [冒泡排序](#冒泡排序)\n- [实现sleep函数](#实现sleep函数)\n- [实现node的events模块](#实现node的events模块)\n- [JS继承实现的6种方式](https://github.com/wuxianqiang/blog/issues/31)\n- [实现所有对象的深度克隆](#实现所有对象的深度克隆)\n- [二分查找法模板](#二分查找法模板)\n- [将对象转换为树结构](#将对象转换为树结构)\n- [foo(1)(2)(3)(4)实现1+2+3+4](#foo1234实现1234)\n- [仿函数原型上的call()方法](#仿函数原型上的call方法)\n- [仿数组原型上的push()方法](#仿数组原型上的push方法)\n- [仿ES6中的Array.of()方法](#仿es6中的arrayof方法)\n- [仿ECMAScript5中Object.create()函数](#仿ecmascript5中objectcreate函数)\n- [仿ECMAScript5中String.trim()函数](#仿ecmascript5中stringtrim函数)\n- [仿ECMAScript5中String.padstart()函数](#仿ecmascript5中stringpadstart函数)\n- [仿ECMAScript5中String.padend()函数](#仿ecmascript5中stringpadend函数)\n- [仿ECMAScript5中Array.reduce()函数](#仿ecmascript5中arrayreduce函数)\n- [仿ECMAScript5中Object.keys()函数](#仿ecmascript5中objectkeys函数)\n- [仿ECMAScript5中Function.bind()函数](#仿ecmascript5中functionbind函数)\n- [仿ECMAScript5中Array.map()函数](#仿ecmascript5中arraymap函数)\n- [仿ECMAScript5中Array.forEach()函数](#仿ecmascript5中arrayforeach函数)\n- [仿ECMAScript5中Array.filter()函数](#仿ecmascript5中arrayfilter函数)\n- [仿ECMAScript5中Array.every()函数](#仿ecmascript5中arrayevery函数)\n- [仿ECMAScript5中Array.some()函数](#仿ecmascript5中arraysome函数)\n- [仿ECMAScript5中Array.find()函数](#仿ecmascript5中arrayfind函数)\n- [仿ECMAScript5中Array.findIndex()函数](#仿ecmascript5中arrayfindindex函数)\n- [仿Array.indexOf()函数](#仿arrayindexof函数)\n- [仿Math.max()方法实现](#仿mathmax方法不定实参函数)\n- [仿String.match()方法实现](#仿stringmatch方法实现)\n- [仿HTML5的classList属性实现](#仿html5的classlist属性)\n- [仿Function.name属性实现](#返回函数的名字)\n- [返回元素的第n层祖先元素](#返回元素的第n层祖先元素)\n- [返回元素的第n个兄弟元素](#返回元素的第n个兄弟元素)\n- [返回元素的第n个子代元素](#返回元素的第n个子代元素)\n- [原生JS实现CSS动画之震动](#原生js实现css动画1)\n- [原生JS实现CSS动画之隐藏](#原生js实现css动画2)\n- [在数组中查找所有出现的元素方法](#在数组中查找所有出现的元素方法)\n- [数据类型检测之特殊情况特殊处理](#数据类型检测特殊情况特殊处理)\n- [使用innerHTML实现outerHTML属性](#使用innerhtml实现outerhtml属性)\n- [插入节点](#插入节点)\n- [倒序排列子节点](#倒序排列子节点)\n- [查询窗口滚动条的位置](#查询窗口滚动条的位置)\n- [查询窗口的视口尺寸](#查询窗口的视口尺寸)\n- [表格的行排序](#表格的行排序)\n- [生成目录表](#生成目录表)\n- [数组去重](#数组去重)\n- [冒泡排序](#冒泡排序)\n- [从URL解析参数](#从url解析参数)\n- [获取纯文本的元素内容](#获取纯文本的元素内容)\n- [手写一个JSONP实现](#手写一个jsonp实现)\n- [查询纯文本形式的内容](#查询纯文本形式的内容)\n- [查找元素的后代中节点中的所有Text节点](#查找元素的后代中节点中的所有text节点)\n- [使用innerHTML实现insertAdjacentHTML](#使用innerhtml实现insertadjacenthtml)\n- [拖拽](#拖拽)\n- [在谷歌地图上显示地理位置信息](#在谷歌地图上显示地理位置信息)\n- [使用所有地理位置特性](#使用所有地理位置特性)\n- [优雅的图片翻转实现](#优雅的图片翻转实现)\n- [使用canvas绘制多边形](#使用canvas绘制多边形)\n- [使用canvas绘制雪花](#使用canvas绘制雪花)\n- [在Web Worker中发起同步XMLHtttpRequest](#在web-worker中发起同步xmlhtttprequest)\n- [统计字符串中每个字母的出现次数](#统计字符串中每个字母的出现次数)\n- [给HTML元素增加样式类名](#给html元素增加样式类名)\n- [写一个范围函数](#写一个范围函数)\n- [写一个eval函数](#写一个eval函数)\n- [判断空对象的函数](#判断空对象的函数)\n- [随机抽样调查](#随机抽样调查)\n- [求数组中的最大数](#求数组中的最大数)\n- [字符串的repeat的方法模仿](#字符串的repeat的方法模仿)\n- [求两数之和](#求两数之和)\n- [二叉树翻转](#二叉树翻转)\n\n## 插入排序算法\n```js\nfunction insert_sort (A) {\n  for (let j = 1, len = A.length; j \u003c len; j++) {\n    const key = A[j]\n    let i = j - 1\n    while (i \u003e= 0 \u0026\u0026 A[i] \u003e key) {\n      A[i + 1] = A[i]\n      i--\n    }\n    A[i + 1] = key\n  }\n}\n```\n\n## 函数防抖\n```js\nfunction debounce (func, delay = 300, I = null) {\n  return (...args) =\u003e {\n    clearTimeout(I)\n    I = setTimeout(func.bind(null, ...args), delay)\n  }\n}\n```\n\n## 函数节流\n```js\nfunction throttle (func, delay = 60) {\n  let lock = false\n  return (...args) =\u003e {\n    if (lock) {\n      return\n    }\n    func(...args)\n    lock = true\n    setTimeout(() =\u003e {\n      lock = false\n    }, delay)\n  }\n}\n```\n\n## 数组展平\n```js\nfunction flatten (arr) {\n  return [].concat(\n    ...arr.map(x =\u003e \n      Array.isArray(x) ? flatten(x) : x\n    )\n  )\n}\n```\n\n## 寻找最大值\n```js\n// O(n)的算法\nfunction find_max (arr) {\n  let max = Number.NEGATIVE_INFINITY\n  for (let i = 0, len = arr.length; i \u003c len; i++) {\n    max = (arr[i] \u003e max ? arr[i] : max)\n  }\n  return max\n}\n```\n\n## 冒泡排序\n```js\n// O^2算法\nfunction bubble_sort (A) {\n  for (let i = A.length; i \u003e 0; i--) {\n    for (let j = 1; j \u003c i; j++) {\n      if (A[j] \u003c A[j - 1]) {\n        swap(A, j, j - 1)\n      }\n    }\n  }\n  return A\n}\n\nfunction swap (A, i, j) {\n  const t = A[i]\n  A[i] = A[j]\n  A[j] = t\n}\n```\n\n## foo(1)(2)(3)(4)实现1+2+3+4\n```js\nconst curry = func =\u003e {\n  const g = (...allArgs) =\u003e allArgs.length \u003e= func.length ? func(...allArgs) : (...args) =\u003e g(...allArgs, ...args)\n  return g\n}\nconst foo = curry ((a, b, c, d) =\u003e {\n  return a + b + c + d\n})\nfoo(1)(2)(3)(4)\n```\n\n## 仿ECMAScript5中String.padEnd()函数\n```js\nString.prototype.mypadEnd = function (num, replacer) {\n  var len = ('' + this).length;\n  return this + (Array(\n    num \u003e len ? num - len + 1 || 0 : 0\n  ).join(replacer));\n}\n```\n\n## 仿ECMAScript5中String.padStart()函数\n```js\nString.prototype.mypadStart = function (num, replacer) {\n  var len = ('' + this).length;\n  return (Array(\n    num \u003e len ? num - len + 1 || 0 : 0\n  ).join(replacer) + this);\n}\n```\n\n## 仿函数原型上的call()方法\n```js\nFunction.prototype.mycall = function mycall() {\n    var ary = [...arguments].slice(1);\n    if (arguments[0] == undefined) {\n        this(...ary);\n    } else {\n        var obj = Object(arguments[0]);\n        obj.__proto__.fn = this;\n        obj.fn(...ary);\n        delete obj.__proto__.fn;\n    }\n    return this;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿数组原型上的push()方法\n```js\nArray.prototype.myPush = function () {\n    let argLen = arguments.length;\n    if (argLen === 0) return this.length;\n    for (let i = 0; i \u003c argLen; i++) {\n        const element = arguments[i];\n        this[this.length] = element;\n    }\n    return this.length;\n}\n```\n**[⬆ back to top](#readme)**\n**[⬆ back to top](#readme)**\n## 仿ES6中的Array.of()方法\n```js\nlet myArray = { of: function of () {\n        const len = arguments.length;\n        if (len === 0) return [];\n        let ary = [];\n        for (let i = 0; i \u003c len; i++) {\n            const element = arguments[i];\n            ary.push(element);\n        }\n        return ary;\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Object.create()函数\n```js\n        function inherit(obj) {\n            if (obj === null) throw TypeError();\n            if (Object.create) return Object.create(obj);\n            var t = typeof obj;\n            if (t !== \"object\" \u0026\u0026 t !== \"function\") throw TypeError();\n            function Fn() {};\n            Fn.prototype = obj;\n            return new Fn();\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中String.trim()函数\n```js\n        String.prototype.mytrim = function () {\n            String.prototype.trim || function () {\n                if (!this) return this; //空字符串不做处理\n                return this.replace(/^\\s+|\\s+$/g, \"\") //使用正则表达式经行空格替换\n            }\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.reduce()函数\n\n```js\n        var reduce = Array.prototype.reduce ? function (ary, fn, initial) {\n            if (arguments.length \u003e 2) { //如果reduce()方法存在的话\n                return ary.reduce(fn, initial); //如果传入了一个初始值\n            } else {\n                return ary.reduce(fn); //否则初始值\n            }\n        } : function (ary, fn, initial) { //以特定的初始值开始，否则第一个值取自ary\n            var i = 0,\n                len = ary.length,\n                accumulator;\n            if (arguments.length \u003e 2) {\n                accumulator = initial;\n            } else { //找到数组中第一个已经定义的索引\n                if (len == 0) throw TypeError();\n                while (i \u003c len) {\n                    if (i in ary) {\n                        accumulator = ary[i++];\n                        break;\n                    } else {\n                        i++;\n                    }\n                }\n                if (i == len) throw TypeError();\n            }\n            while (i \u003c len) { //对于数组中剩下的元素依次调用fn\n                if (i in ary) {\n                    accumulator = fn.call(undefined, accumulator, ary[i], i, ary)\n                }\n                i++;\n            }\n            return accumulator;\n        }\n```\n**[⬆ back to top](#readme)**\n## 在数组中查找所有出现的元素方法\n\n```js\n        function findAll(ary, ele) {\n            var results = [],\n                len = ary.length,\n                pos = 0;\n            while (pos \u003c len) {\n                pos = ary.indexOf(ele, pos);\n                if (pos === -1) break;\n                results.push(pos);\n                pos++;\n            }\n            return results;\n        }\n```\n**[⬆ back to top](#readme)**\n## 数据类型检测，特殊情况特殊处理\n\n```js\n        function classOf(obj) {\n            if (obj === null) return \"Null\";\n            if (obj === undefined) return 'Undefined';\n            return Object.prototype.toString.call(obj).slice(8, -1);\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Object.keys()函数\n\n```js\n        function keys(obj) {\n            if (typeof obj !== \"object\") {\n                throw TypeError();\n            }\n            var result = [];\n            for (var prop in obj) {\n                if (obj.hasOwnProperty(prop)) {\n                    result.push(prop);\n                }\n            }\n            return result;\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿Math.max方法（不定实参函数）\n\n```js\n        function max() {\n            var max = Number.NEGATIVE_INFINITY;\n            for (var i = 0; i \u003c arguments.length; i++) {\n                if (arguments[i] \u003e max) max = arguments[i];\n            }\n            return max;\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Function.bind()函数\n\n```js\n        if (!Function.prototype.bind) {\n            Function.prototype.bind = function (obj) {\n                var self = this,\n                    boundArgs = arguments;\n                return function () {\n                    var args = [],\n                        i;\n                    for (i = 1; i \u003c boundArgs.length; i++) args.push(boundArgs[i]);\n                    for (i = 1; i \u003c arguments.length; i++) args.push(arguments[i]);\n                    return self.apply(obj, args);\n                }\n            }\n        }\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.map()函数\n\n```js\nArray.prototype.mymap = function (fn, obj) {\n    let res = [];\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            res[i] = fn(element, i, this)\n        } else {\n            res[i] = fn.call(obj, element, i, this);\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.forEach()函数\n```js\nArray.prototype.myforEach = function (fn, obj) {\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            fn(element, i, this)\n        } else {\n            fn.call(obj, element, i, this);\n        }\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.filter()函数\n```js\nArray.prototype.myfilter = function (fn, obj) {\n    let res = [],\n        index = 0;\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            let cur = fn(element, i, this);\n            if (cur) res[index++] = element;\n        } else {\n            let cur = fn.call(obj, element, i, this);\n            if (cur) res[index++] = element;\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.every()函数\n```js\nArray.prototype.myevery = function (fn, obj) {\n    let res = true;\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            let cur = fn(element, i, this);\n            if (!cur) {\n                res = false;\n                break;\n            }\n        } else {\n            let cur = fn.call(obj, element, i, this);\n            if (!cur) {\n                res = false;\n                break;\n            }\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.some()函数\n```js\nArray.prototype.mysome = function (fn, obj) {\n    let res = false;\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            let cur = fn(element, i, this);\n            if (cur) {\n                res = true;\n                break;\n            }\n        } else {\n            let cur = fn.call(obj, element, i, this);\n            if (cur) {\n                res = true;\n                break;\n            }\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.find()函数\n```js\nArray.prototype.myfind = function (fn, obj) {\n    let res = undefined;\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            let cur = fn(element, i, this);\n            if (cur) {\n                res = element;\n                break;\n            }\n        } else {\n            let cur = fn.call(obj, element, i, this);\n            if (cur) {\n                res = element;\n                break;\n            }\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿ECMAScript5中Array.findIndex()函数\n```js\nArray.prototype.myfindIndex = function (fn, obj) {\n    let res = undefined;\n    for (let i = 0; i \u003c this.length; i++) {\n        const element = this[i];\n        if (obj == undefined) {\n            let cur = fn(element, i, this);\n            if (cur) {\n                res = i;\n                break;\n            }\n        } else {\n            let cur = fn.call(obj, element, i, this);\n            if (cur) {\n                res = i;\n                break;\n            }\n        }\n    }\n    return res;\n}\n```\n**[⬆ back to top](#readme)**\n## 仿Array.indexOf()函数\n```js\nString.prototype.myindexOf = function () {\n    let index = -1;\n    let arg = arguments.length;\n    if (!arg) return index;\n    let s1 = arguments[0][0];\n    if (arg \u003e 1) {\n        let param = arguments[1];\n        if (typeof param !== \"number\" || isNaN(param)) return index;\n        let len = this.length;\n        if (param \u003c 0 \u0026\u0026 param \u003e= -len) {\n            param += len;\n        } else if (param \u003c -len) {\n            param = 0\n        } else if (param \u003e len) {\n            return index;\n        }\n        for (let i = param; i \u003c len; i++) {\n            const s2 = this[i];\n            if (s1 === s2) {\n                index = i;\n                break;\n            }\n        }\n    }\n    if (!arguments[1]) {\n        for (let i = 0; i \u003c this.length; i++) {\n            const s2 = this[i];\n            if (s1 === s2) {\n                index = i;\n                break;\n            }\n        }\n    }\n    return index;\n}\n```\n**[⬆ back to top](#readme)**\n## 数组去重\n\n```js\n        Array.prototype.unique = function unique() {\n            var obj = {};\n            for (var i = 0; i \u003c this.length; i++) {\n                var current = this[i];\n                if (obj[current] === current) {\n                    current = this[this.length - 1];\n                    this.length--;\n                    i--;\n                    continue;\n                }\n                obj[current] = current\n            }\n            obj = null;\n            return this;\n        }\n```\n**[⬆ back to top](#readme)**\n## 冒泡排序\n\n```js\n        Array.prototype.bubbleSort = function bubbleSort() {\n            var temp = null;\n            for (var i = 0; i \u003c this.length - 1; i++) {\n                for (var k = 0; k \u003c this.length - 1 - i; k++) {\n                    if (this[k] \u003e this[k + 1]) {\n                        temp = this[k];\n                        this[k] = this[k + 1];\n                        this[k + 1] = temp;\n                    }\n                }\n            }\n            return this;\n        }\n\n```\n**[⬆ back to top](#readme)**\n## 仿String.match()方法实现\n\n```js\n        String.prototype.mymatch = function (reg) {\n         var ary = [];\n         var res = reg.exec(this);\n         while (res) {\n            ary.push(res[0]);\n            res = reg.exec(this);\n         }\n         return ary;\n        }\n```\n**[⬆ back to top](#readme)**\n## 返回元素的第n层祖先元素\n\n```js\n        /**\n        *返回元素ele的第n层祖先元素，如果不存在此类祖先或祖先不是Element，\n        *（例如Document或者DocumentFragment）则返回null\n        *如果n为0，则返回e本身。如果n为1（或省略），则返回其父元素\n        *如果n为2，则返回其祖父元素，依次类推\n        */\n        function parent(ele, n) {\n            if (n === nudefined) n = 1;\n            while (n-- \u0026\u0026 ele) {\n                ele = ele.parentNode;\n            }\n            if (!ele || ele.nodeTope !== 1) return null;\n            return ele;\n        }\n```\n**[⬆ back to top](#readme)**\n## 返回元素的第n个兄弟元素\n\n```js\n/**\n *返回元素ele的第n个兄弟元素\n *如果n为正，返回后续的第n个兄弟元素\n *如果n为负，返回前面的第n个兄弟元素\n *如果n为零，返回ele本身\n */\nfunction sibling(ele, n) {\n    while (ele \u0026\u0026 n !== 0) { //如果ele未定义，即刻返回它\n        if (n \u003e 0) { //查找后续的兄弟元素\n            if (ele.nextElementSibling) {\n                ele = ele.nextElementSibling;\n            } else {\n                for (ele = ele.nextSibling; ele \u0026\u0026 ele.nodeType !== 1; ele = ele.nextSibling) /*空循环*/;\n            }\n            n--;\n        } else { //查找前面的兄弟元素\n            if (ele.previousElementSibing) {\n                ele = ele.previousElementSibling;\n            } else {\n                for (ele = ele.previousSibling; ele \u0026\u0026 ele.nodeType !== 1; ele = ele.previousSibling) /*空循环*/;\n            }\n            n++;\n        }\n    }\n    return ele;\n}\n```\n**[⬆ back to top](#readme)**\n## 返回元素的第n个子代元素\n\n```js\n/**\n *返回元素ele的第n代子元素，如果不存在则为null\n *负值n代表从后往前计数。0表示第一个子元素，而-1代表最后一个，-2代表倒数第二个，依次类推\n */\nfunction child(ele, n) {\n    if (ele.children) { //如果children数组存在\n        if (n \u003c 0) n += ele.children.length; //转换负的n为数组索引\n        if (n \u003c 0) return null; //如果它仍然为负，说明没有子元素\n        return ele.children[n]; //返回指定的子元素\n    }\n    //如果e没有children数组，找到第一个子元素并向前数，或找到最后一个子元素并往回数\n    if (n \u003e= 0) { //n非负：从第一个子元素向前数\n        //找到元素e的第一个子元素\n        if (ele.firstElementChild) {\n            ele = ele.firstElementChild;\n        } else {\n            for (ele = ele.firstChild; ele \u0026\u0026 ele.nodeType !== 1; ele = ele.nextSibling) /*空循环*/;\n        }\n        return sibling(ele, n); //返回第一个子元素的第n个兄弟元素\n    } else { //n为负：从最后一个子元素往回数\n        if (ele.lastElementChild) {\n            ele = ele.lastElementChild;\n        } else {\n            for (ele = ele.lastChild; ele \u0026\u0026 ele.nodeType !== 1; ele = ele.previousSibling) /*空循环*/;\n        }\n        return sibling(ele, n + 1); //+1来转化最后1个子元素为最后1个兄弟元素\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 表格的行排序\n\n```js\n//根据指定表格每行第n个单元格的值，对第一个＜tbody＞中的行进行排序\n//如果存在comparator函数则使用它，否则按字母表顺序比较\nfunction sortrows(table, n, comparator) {\n    var tbody = table.tBodies[0]; //第一个＜tbody＞，可能是隐式创建的\n    var rows = tbody.getElementsByTagName(\"tr\"); //tbody中的所有行\n    rows = Array.prototype.slice.call(rows, 0); //真实数组中的快照\n    //基于第n个＜td＞元素的值对行排序\n    rows.sort(function (row1, row2) {\n        var cell1 = row1.getElementsByTagName(\"td\")[n]; //获得第n个单元格\n        var cell2 = row2.getElementsByTagName(\"td\")[n]; //两行都是\n        var val1 = cell1.textContent || cell1.innerText; //获得文本内容\n        var val2 = cell2.textContent || cell2.innerText; //两单元格都是\n        if (comparator) return comparator(val1, val2); //进行比较\n        if (val1 \u003c val2) {\n            return -1;\n        } else if (val1 \u003e val2) {\n            return 1;\n        } else {\n            return 0;\n        }\n    }); //在tbody中按它们的顺序把行添加到最后\n    //这将自动把它们从当前位置移走，故没必要预先删除它们\n    //如果＜tbody＞还包含了除了＜tr＞的任何其他元素，这些节点将会悬浮到顶部位置\n    for (var i = 0; i \u003c rows.length; i++) tbody.appendChild(rows[i]);\n}\n//查找表格的＜th＞元素（假设只有一行），让它们可单击，\n//以便单击列标题，按该列对行排序\nfunction makeSortable(table) {\n    var headers = table.getElementsByTagName(\"th\");\n    for (var i = 0; i \u003c headers.length; i++) {\n        (function (n) { //嵌套函数来创建本地作用域\n            headers[i].onclick = function () {\n                sortrows(table, n);\n            };\n        }(i)); //将i的值赋给局部变量n\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 生成目录表\n```js\n/**\n *\n *这个模块注册一个可在页面加载完成后自动运行的匿名函数。当执行这个函数时会去文档中查找\n *id为\"TOC\"的元素。如果这个元素不存在，就创建一个元素\n *\n *生成的TOC目录应当具有自己的CSS样式。整个目录区域的样式className设置为\"TOCEntry\"\n *同样我们为不同层级的目录标题定义不同的样式。＜h1＞标签生成的标题\n *className为\"TOCLevel1\"，＜h2＞标签生成的标题className为\"TOCLevel2\"，以此类推\n *段编号的样式为\"TOCSectNum\"\n *\n *完整的CSS样式代码如下:\n *\n *#TOC{border:solid black 1px;margin:10px;padding:10px;}\n *.TOCEntry{font-family:sans-serif;}\n *.TOCEntry a{text-decoration:none;}\n *.TOCLevel1{font-size:16pt;font-weight:bold;}\n *.TOCLevel2{font-size:12pt;margin-left:.5in;}\n *.TOCSectNum:after{content:\":\";}\n *\n *这段代码的最后一行表示每个段编号之后都有一个冒号和空格符。要想隐藏段编号，\n *请使用这行代码：\n *.TOCSectNum{display:none}\n *\n **/\n(function () { //匿名函数定义了一个局部作用域\n    //查找TOC容器元素\n    //如果不存在，则在文档开头处创建一个\n    var toc = document.getElementById(\"TOC\");\n    if (!toc) {\n        toc = document.createElement(\"div\");\n        toc.id = \"TOC\";\n        document.body.insertBefore(toc, document.body.firstChild);\n    }\n    //查找所有的标题元素\n    var headings;\n    if (document.querySelectorAll) //我们是否能用这个简单的方法？\n        headings = document.querySelectorAll(\"h1,h2,h3,h4,h5,h6\");\n    else //否则，查找方法稍微麻烦一些\n        headings = findHeadings(document.body, []); //递归遍历document的body，查找标题元素\n    function findHeadings(root, sects) {\n        for (var c = root.firstChild; c != null; c = c.nextSibling) {\n            if (c.nodeType !== 1) continue;\n            if (c.tagName.length == 2 \u0026\u0026 c.tagName.charAt(0) == \"H\")\n                sects.push(c);\n            else\n                findHeadings(c, sects);\n        }\n        return sects;\n    }\n    //初始化一个数组来保持跟踪章节号\n    var sectionNumbers = [0, 0, 0, 0, 0, 0]; //现在，循环已找到的标题元素\n    for (var h = 0; h \u003c headings.length; h++) {\n        var heading = headings[h]; //跳过在TOC容器中的标题元素\n        if (heading.parentNode == toc) continue; //判定标题的级别\n        var level = parseInt(heading.tagName.charAt(1));\n        if (isNaN(level) || level \u003c 1 || level \u003e 6) continue; //对于该标题级别增加sectionNumbers对应的数字\n        //重置所有标题比它级别低的数字为零\n        sectionNumbers[level - 1]++;\n        for (var i = level; i \u003c 6; i++) sectionNumbers[i] = 0; //现在，将所有标题级别的章节号组合产生一个章节号， 如2 .3 .1\n        var sectionNumber = sectionNumbers.slice(0, level).join(\".\") //为标题级别增加章节号\n        //把数字放在＜span＞中，使得其可以用样式修饰\n        var span = document.createElement(\"span\");\n        span.className = \"TOCSectNum\";\n        span.innerHTML = sectionNumber;\n        heading.insertBefore(span, heading.firstChild); //用命名的锚点将标题包起来，以便为它增加链接\n        var anchor = document.createElement(\"a\");\n        anchor.name = \"TOC\" + sectionNumber;\n        heading.parentNode.insertBefore(anchor, heading);\n        anchor.appendChild(heading); //现在为该节创建一个链接\n        var link = document.createElement(\"a\");\n        link.href = \"#TOC\" + sectionNumber; //链接的目标地址\n        link.innerHTML = heading.innerHTML; //链接文本与实际标题一致\n        //将链接放在一个div中，div用基于级别名字的样式修饰\n        var entry = document.createElement(\"div\");\n        entry.className = \"TOCEntry TOCLevel\" + level;\n        entry.appendChild(link); //该div添加到TOC容器中\n        toc.appendChild(entry);\n    }\n}());\n```\n**[⬆ back to top](#readme)**\n## 从URL解析参数\n\n```js\n/*\n *这个函数用来解析来自URL的查询串中的name=value参数对\n *它将name=value对存储在一个对象的属性中，并返回该对象\n *这样来使用它\n *\n *var args=urlArgs();//从URL中解析参数\n *var q=args.q||\"\";//如果参数定义了的话就使用参数；否则使用一个默认值\n *var n=args.n?parseInt(args.n):10;\n */\nfunction urlArgs() {\n    var args = {}; //定义一个空对象\n    var query = location.search.substring(1); //查找到查询串，并去掉'?'\n    var pairs = query.split(\"\u0026\"); //根据\"\u0026\"符号将查询字符串分隔开\n    for (var i = 0; i \u003c pairs.length; i++) { //对于每个片段\n        var pos = pairs[i].indexOf('='); //查找\"name=value\"\n        if (pos == -1) continue; //如果没有找到的话，就跳过\n        var name = pairs[i].substring(0, pos); //提取name\n        var value = pairs[i].substring(pos + 1); //提取value\n        value = decodeURIComponent(value); //对value进行解码\n        args[name] = value; //存储为属性\n    }\n    return args; //返回解析后的参数\n}\n```\n**[⬆ back to top](#readme)**\n\n## 获取纯文本的元素内容\n\n```js\n/**\n *一个参数，返回元素的textContent或innerText\n *两个参数，用value参数的值设置元素的textContent或innerText\n */\nfunction textContent(element, value) {\n    var content = element.textContent; //检测textContent是否有定义\n    if (value === undefined) { //没传递value，因此返回当前文本\n        if (content !== undefined) {\n            return content;\n        } else {\n            return element.innerText;\n        }\n    } else { //传递了value，因此设置文本\n        if (content !== undefined) {\n            element.textContent = value;\n        } else {\n            element.innerText = value;\n        }\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 手写一个JSONP实现\n\n```js\n//根据指定的URL发送一个JSONP请求\n//然后把解析得到的响应数据传递给回调函数\n//在URL中添加一个名为jsonp的查询参数，用于指定该请求的回调函数的名称\nfunction getJSONP(url, callback) { //为本次请求创建一个唯一的回调函数名称\n    var cbnum = \"cb\" + getJSONP.counter++; //每次自增计数器\n    var cbname = \"getJSONP.\" + cbnum; //作为JSONP函数的属性\n    //将回调函数名称以表单编码的形式添加到URL的查询部分中\n    //使用jsonp作为参数名，一些支持JSONP的服务\n    //可能使用其他的参数名，比如callback\n    if (url.indexOf(\"?\") === -1) //URL没有查询部分\n        url += \"?jsonp=\" + cbname; //作为查询部分添加参数\n    else //否则\n        url += \"＆jsonp=\" + cbname; //作为新的参数添加它\n    //创建script元素用于发送请求\n    var script = document.createElement(\"script\"); //定义将被脚本执行的回调函数\n    getJSONP[cbnum] = function (response) {\n        try {\n            callback(response); //处理响应数据\n        } finally { //即使回调函数或响应抛出错误\n            delete getJSONP[cbnum]; //删除该函数\n            script.parentNode.removeChild(script); //移除script元素\n        }\n    }; //立即触发HTTP请求\n    script.src = url; //设置脚本的URL\n    document.body.appendChild(script); //把它添加到文档中\n}\ngetJSONP.counter = 0; //用于创建唯一回调函数名称的计数器\n```\n**[⬆ back to top](#readme)**\n## 插入节点\n\n```js\n//将child节点插入到parent中，使其成为第n个子节点\nfunction insertAt(parent, child, n) {\n    if (n \u003c 0 || n \u003e parent.childNodes.length) {\n        throw new Error(\"invalid index\");\n    } else if (n == parent.childNodes.length) {\n        parent.appendChild(child);\n    } else {\n        parent.insertBefore(child, parent.childNodes[n]);\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 使用innerHTML实现outerHTML属性\n```js\n//为那些不支持它的浏览器实现outerHTML属性\n//假设浏览器确实支持innerHTML，并有个可扩展的Element.prototype，\n//并且可以定义getter和setter\n(function () { //如果outerHTML存在，则直接返回\n    if (document.createElement(\"div\").outerHTML) return; //返回this所引用元素的外部HTML\n    function outerHTMLGetter() {\n        var container = document.createElement(\"div\"); //虚拟元素\n        container.appendChild(this.cloneNode(true)); //复制到该虚拟节点\n        return container.innerHTML; //返回虚拟节点的innerHTML\n    }\n    //用指定的值设置元素的外部HTML\n    function outerHTMLSetter(value) { //创建一个虚拟元素，设置其内容为指定的值\n        var container = document.createElement(\"div\");\n        container.innerHTML = value; //将虚拟元素中的节点全部移动到文档中\n        while (container.firstChild) //循环，直到container没有子节点为止\n            this.parentNode.insertBefore(container.firstChild, this); //删除所被取代的节点\n        this.parentNode.removeChild(this);\n    }\n    //现在使用这两个函数作为所有Element对象的outerHTML属性的getter和setter\n    //如果它存在则使用ES5的Object.defineProperty()方法，\n    //否则，退而求其次，使用__defineGetter__()和__defineSetter__()\n    if (Object.defineProperty) {\n        Object.defineProperty(Element.prototype, \"outerHTML\", {\n            get: outerHTMLGetter,\n            set: outerHTMLSetter,\n            enumerable: false,\n            configurable: true\n        });\n    } else {\n        Element.prototype.__defineGetter__(\"outerHTML\", outerHTMLGetter);\n        Element.prototype.__defineSetter__(\"outerHTML\", outerHTMLSetter);\n    }\n}());\n```\n**[⬆ back to top](#readme)**\n## 倒序排列子节点\n```js\n//倒序排列节点n的子节点\nfunction reverse(n) { //创建一个DocumentFragment作为临时容器\n    var f = document.createDocumentFragment(); //从后至前循环子节点，将每一个子节点移动到文档片段中\n    //n的最后一个节点变成f的第一个节点，反之亦然\n    //注意，给f添加一个节点，该节点自动地会从n中删除\n    while (n.lastChild) f.appendChild(n.lastChild); //最后，把f的所有子节点一次性全部移回n中\n    n.appendChild(f);\n}\n```\n**[⬆ back to top](#readme)**\n## 查询窗口滚动条的位置\n```js\n//以一个对象的x和y属性的方式返回滚动条的偏移量\nfunction getScrollOffsets(w) { //使用指定的窗口，如果不带参数则使用当前窗口\n    w = w || window; //除了IE 8及更早的版本以外，其他浏览器都能用\n    if (w.pageXOffset != null) return {\n        x: w.pageXOffset,\n        y: w.pageYOffset\n    }; //对标准模式下的IE（或任何浏览器）\n    var d = w.document;\n    if (document.compatMode == \"CSS1Compat\")\n        return {\n            x: d.documentElement.scrollLeft,\n            y: d.documentElement.scrollTop\n        }; //对怪异模式下的浏览器\n    return {\n        x: d.body.scrollLeft,\n        y: d.body.scrollTop\n    };\n}\n```\n**[⬆ back to top](#readme)**\n## 查询窗口的视口尺寸\n```js\n//作为一个对象的w和h属性返回视口的尺寸\nfunction getViewportSize(w) { //使用指定的窗口，如果不带参数则使用当前窗口\n    w = w || window; //除了IE 8及更早的版本以外，其他浏览器都能用\n    if (w.innerWidth != null) return {\n        w: w.innerWidth,\n        h: w.innerHeight\n    }; //对标准模式下的IE（或任何浏览器）\n    var d = w.document;\n    if (document.compatMode == \"CSS1Compat\")\n        return {\n            w: d.documentElement.clientWidth,\n            h: d.documentElement.clientHeight\n        }; //对怪异模式下的浏览器\n    return {\n        w: d.body.clientWidth,\n        h: d.body.clientWidth\n    };\n}\n```\n**[⬆ back to top](#readme)**\n## 返回函数的名字\n```js\nFunction.prototype.getName = function () {\n    return this.name || this.toString().match(/function\\s*(\\w*)\\s*\\(/)[1];\n}\n```\n**[⬆ back to top](#readme)**\n## 原生JS实现CSS动画1\n```js\n//将e转化为相对定位的元素，使之左右\"震动\"\n//第一个参数可以是元素对象或者元素的id\n//如果第二个参数是函数，以e为参数，它将在动画结束时调用\n//第三个参数指定e震动的距离，默认是5像素\n//第四个参数指定震动多久，默认是500毫秒\nfunction shake(e, oncomplete, distance, time) { //句柄参数\n    if (typeof e === \"string\") e = document.getElementById(e);\n    if (!time) time = 500;\n    if (!distance) distance = 5;\n    var originalStyle = e.style.cssText; //保存e的原始style\n    e.style.position = \"relative\"; //使e相对定位\n    var start = (new Date()).getTime(); //注意，动画的开始时间\n    animate(); //动画开始\n    //函数检查消耗的时间，并更新e的位置\n    //如果动画完成，它将e还原为原始状态\n    //否则，它更新e的位置，安排它自身重新运行\n    function animate() {\n        var now = (new Date()).getTime(); //得到当前时间\n        var elapsed = now - start; //从开始以来消耗了多长时间？\n        var fraction = elapsed / time; //是总时间的几分之几？\n        if (fraction \u003c 1) { //如果动画未完成\n            //作为动画完成比例的函数，计算e的x位置\n            //使用正弦函数将完成比例乘以4pi\n            //所以，它来回往复两次\n            var x = distance * Math.sin(fraction * 4 * Math.PI);\n            e.style.left = x + \"px\"; //在25毫秒后或在总时间的最后尝试再次运行函数\n            //目的是为了产生每秒40帧的动画\n            setTimeout(animate, Math.min(25, time - elapsed));\n        } else { //否则，动画完成\n            e.style.cssText = originalStyle //恢复原始样式\n            if (oncomplete) oncomplete(e); //调用完成后的回调函数\n        }\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 原生JS实现CSS动画2\n```js\nfunction fadeOut(e, oncomplete, time) {\n    if (typeof e === \"string\") e = document.getElementById(e);\n    if (!time) time = 500; //使用Math.sqrt作为一个简单的“缓动函数”来创建动画\n    //精巧的非线性：一开始淡出得比较快，然后缓慢了一些\n    var ease = Math.sqrt;\n    var start = (new Date()).getTime(); //注意：动画开始的时间\n    animate(); //动画开始\n    function animate() {\n        var elapsed = (new Date()).getTime() - start; //消耗的时间\n        var fraction = elapsed / time; //总时间的几分之几？\n        if (fraction \u003c 1) { //如果动画未完成\n            var opacity = 1 - ease(fraction); //计算元素的不透明度\n            e.style.opacity = String(opacity); //设置在e上\n            setTimeout(animate, //调度下一帧\n                Math.min(25, time - elapsed));\n        } else { //否则，动画完成\n            e.style.opacity = \"0\"; //使e完全透明\n            if (oncomplete) oncomplete(e); //调用完成后的回调函数\n        }\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 仿HTML5的classList属性\n```js\n/*\n *如果e有classList属性则返回它。否则，返回一个为e模拟DOMTokenList API的对象\n *返回的对象有contains()、add()、remove()、toggle()和toString()等方法\n *来检测和修改元素e的类集合。如果classList属性是原生支持的，\n *返回的类数组对象有length和数组索引属性。模拟DOMTokenList不是类数组对象，\n *但是它有一个toArray()方法来返回一个含元素类名的纯数组快照\n */\nfunction classList(e) {\n    if (e.classList) return e.classList; //如果e.classList存在，则返回它\n    else return new CSSClassList(e); //否则，就伪造一个\n}\n//CSSClassList是一个模拟DOMTokenList的JavaScript类\nfunction CSSClassList(e) {\n    this.e = e;\n} //如果e.className包含类名c则返回true否则返回false\nCSSClassList.prototype.contains = function (c) { //检查c是否是合法的类名\n    if (c.length === 0 || c.indexOf(\" \") != -1)\n        throw new Error(\"Invalid class name:'\" + c + \"'\"); //首先是常规检查\n    var classes = this.e.className;\n    if (!classes) return false; //e不含类名\n    if (classes === c) return true; //e有一个完全匹配的类名\n    //否则，把c自身看做一个单词，利用正则表达式搜索c\n    //\\b在正则表达式里代表单词的边界\n    return classes.search(\"\\\\b\" + c + \"\\\\b\") != -1;\n}; //如果c不存在，将c添加到e.className中\nCSSClassList.prototype.add = function (c) {\n    if (this.contains(c)) return; //如果存在，什么都不做\n    var classes = this.e.className;\n    if (classes \u0026\u0026 classes[classes.length - 1] != \"\")\n        c = \"\" + c; //如果需要加一个空格\n    this.e.className += c; //将c添加到className中\n}; //将在e.className中出现的所有c都删除\nCSSClassList.prototype.remove = function (c) { //检查c是否是合法的类名\n    if (c.length === 0 || c.indexOf(\" \") != -1)\n        throw new Error(\"Invalid class name:'\" + c + \"'\"); //将所有作为单词的c和多余的尾随空格全部删除\n    var pattern = new RegExp(\"\\\\b\" + c + \"\\\\b\\\\s*\", \"g\");\n    this.e.className = this.e.className.replace(pattern, \"\");\n}; //如果c不存在，将c添加到e.className中，并返回true\n//否则，将在e.className中出现的所有c都删除，并返回false\nCSSClassList.prototype.toggle = function (c) {\n    if (this.contains(c)) { //如果e.className包含c\n        this.remove(c); //删除它\n        return false;\n    } else { //否则\n        this.add(c); //添加它\n        return true;\n    }\n}; //返回e.className本身\nCSSClassList.prototype.toString = function () {\n    return this.e.className;\n}; //返回在e.className中的类名\nCSSClassList.prototype.toArray = function () {\n    return this.e.className.match(/\\b\\w+\\b/g) || [];\n};\n```\n**[⬆ back to top](#readme)**\n## 查询纯文本形式的内容\n```js\n/**\n *一个参数，返回元素的textContent或innerText\n *两个参数，用value参数的值设置元素的textContent或innerText\n */\nfunction textContent(element, value) {\n    var content = element.textContent; //检测textContent是否有定义\n    if (value === undefined) { //没传递value，因此返回当前文本\n        if (content !== undefined) return content;\n        else return element.innerText;\n    } else { //传递了value，因此设置文本\n        if (content !== undefined) element.textContent = value;\n        else element.innerText = value;\n    }\n}\n```\ntextContent属性在除了IE的所有当前的浏览器中都支持。在IE中，可以用Element的innerText属性来代替。\n**[⬆ back to top](#readme)**\n## 查找元素的后代中节点中的所有Text节点\n```js\n//返回元素e的纯文本内容，递归进入其子元素\n//该方法的效果类似于textContent属性\nfunction textContent(e) {\n    var child, type, s = \"\"; //s保存所有子节点的文本\n    for (child = e.firstChild; child != null; child = child.nextSibling) {\n        type = child.nodeType;\n        if (type === 3 || type === 4) //Text和CDATASection节点\n            s += child.nodeValue;\n        else if (type === 1) //递归Element节点\n            s += textContent(child);\n    }\n    return s;\n}\n```\n**[⬆ back to top](#readme)**\n## 使用innerHTML实现insertAdjacentHTML()\n```js\n//本模块为不支持它的浏览器定义了Element.insertAdjacentHTML\n//还定义了一些可移植的HTML插入函数，它们的名字比insertAdjacentHTML更符合逻辑：\n//Insert.before()、Insert.after()、Insert.atStart()和Insert.atEnd()\nvar Insert = (function () { //如果元素有原生的insertAdjacentHTML，\n    //在4个函数名更明了的HTML插入函数中使用它\n    if (document.createElement(\"div\").insertAdjacentHTML) {\n        return {\n            before: function (e, h) {\n                e.insertAdjacentHTML(\"beforebegin\", h);\n            },\n            after: function (e, h) {\n                e.insertAdjacentHTML(\"afterend\", h);\n            },\n            atStart: function (e, h) {\n                e.insertAdjacentHTML(\"afterbegin\", h);\n            },\n            atEnd: function (e, h) {\n                e.insertAdjacentHTML(\"beforeend\", h);\n            }\n        };\n    }\n    //否则，无原生的insertAdjacentHTML\n    //实现同样的4个插入函数，并使用它们来定义insertAdjacentHTML\n    //首先，定义一个工具函数，传入HTML字符串，返回一个DocumentFragment，\n    //它包含了解析后的HTML的表示\n    function fragment(html) {\n        var elt = document.createElement(\"div\"); //创建空元素\n        var frag = document.createDocumentFragment(); //创建空文档片段\n        elt.innerHTML = html; //设置元素内容\n        while (elt.firstChild) //移动所有的节点\n            frag.appendChild(elt.firstChild); //从elt到frag\n        return frag; //然后返回frag\n    }\n    var Insert = {\n        before: function (elt, html) {\n            elt.parentNode.insertBefore(fragment(html), elt);\n        },\n        after: function (elt, html) {\n            elt.parentNode.insertBefore(fragment(html), elt.nextSibling);\n        },\n        atStart: function (elt, html) {\n            elt.insertBefore(fragment(html), elt.firstChild);\n        },\n        atEnd: function (elt, html) {\n            elt.appendChild(fragment(html));\n        }\n    }; //基于以上函数实现insertAdjacentHTML\n    Element.prototype.insertAdjacentHTML = function (pos, html) {\n        switch (pos.toLowerCase()) {\n            case \"beforebegin\":\n                return Insert.before(this, html);\n            case \"afterend\":\n                return Insert.after(this, html);\n            case \"afterbegin\":\n                return Insert.atStart(this, html);\n            case \"beforeend\":\n                return Insert.atEnd(this, html);\n        }\n    };\n    return Insert; //最后返回4个插入函数\n}());\n```\n\n**[⬆ back to top](#readme)**\n## 拖拽\n```js\n/**\n *Drag.js：拖动绝对定位的HTML元素\n *\n *这个模块定义了一个drag()函数，它用于mousedown事件处理程序的调用\n *随后的mousemove事件将移动指定元素，mouseup事件将终止拖动\n *这些实现能同标准和IE两种事件模型一起工作\n *\n *参数：\n *\n *elementToDrag：接收mousedown事件的元素或某些包含元素\n *它必须是定位的元素,元素的样式必须是行内样式\n *它的style.left和style.top值将随着用户的拖动而改变\n *\n *event：mousedown事件对象\n **/\nfunction drag(elementToDrag, event) { //初始鼠标位置，转换为文档坐标\n    var startX = event.clientX;\n    var startY = event.clientY; //在文档坐标下，待拖动元素的初始位置\n    //因为elementToDrag是绝对定位的，\n    //所以我们可以假设它的offsetParent就是文档的body元素\n    var origX = parseFloat(elementToDrag.style.left);\n    var origY = parseFloat(elementToDrag.style.top); //计算mousedown事件和元素左上角之间的距离\n    //我们将它另存为鼠标移动的距离\n    if (document.addEventListener) { //标准事件模型\n        //在document对象上注册捕获事件处理程序\n        document.addEventListener(\"mousemove\", moveHandler, true);\n        document.addEventListener(\"mouseup\", upHandler, true);\n    } else if (document.attachEvent) { //用于IE5～8的IE事件模型\n        //在IE事件模型中，\n        //捕获事件是通过调用元素上的setCapture()捕获它们\n        elementToDrag.setCapture();\n        elementToDrag.attachEvent(\"onmousemove\", moveHandler);\n        elementToDrag.attachEvent(\"onmouseup\", upHandler); //作为mouseup事件看待鼠标捕获的丢失\n        elementToDrag.attachEvent(\"onlosecapture\", upHandler);\n    }\n    //我们处理了这个事件，不让任何其他元素看到它\n    if (event.stopPropagation) event.stopPropagation(); //标准模型\n    else event.cancelBubble = true; //IE\n    //现在阻止任何默认操作\n    if (event.preventDefault) event.preventDefault(); //标准模型\n    else event.returnValue = false; //IE\n    /**\n     * 当元素正在被拖动时， 这就是捕获mousemove事件的处理程序\n     *它用于移动这个元素 \n     **/\n    function moveHandler(e) {\n        if (!e) e = window.event; //IE事件模型\n        //移动这个元素到当前鼠标位置，\n        //通过滚动条的位置和初始单击的偏移量来调整\n        var targetLeft = e.clientX - startX + origX;\n        var targetTop = e.clientY - startY + origY;\n        var minLeft = 0;\n        var minTop = 0;\n        var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - elementToDrag.offsetWidth;\n        var maxTop = (document.documentElement.clientHeight || document.body.clientHeight) - elementToDrag.offsetHeight;\n        targetLeft = targetLeft \u003e maxLeft ? maxLeft : (targetLeft \u003c minLeft ? minLeft : targetLeft);\n        targetTop = targetTop \u003e maxTop ? maxTop : (targetTop \u003c minTop ? minTop : targetTop);\n        elementToDrag.style.left = targetLeft + \"px\";\n        elementToDrag.style.top = targetTop + \"px\";\n        if (e.stopPropagation) e.stopPropagation(); //标准\n        else e.cancelBubble = true; //IE\n    }\n    /**\n     *这是捕获在拖动结束时发生的最终mouseup事件的处理程序\n     **/\n    function upHandler(e) {\n        if (!e) e = window.event; //IE事件模型\n        //注销捕获事件处理程序\n        if (document.removeEventListener) { //DOM事件模型\n            document.removeEventListener(\"mouseup\", upHandler, true);\n            document.removeEventListener(\"mousemove\", moveHandler, true);\n        } else if (document.detachEvent) { //IE 5+事件模型\n            elementToDrag.detachEvent(\"onlosecapture\", upHandler);\n            elementToDrag.detachEvent(\"onmouseup\", upHandler);\n            elementToDrag.detachEvent(\"onmousemove\", moveHandler);\n            elementToDrag.releaseCapture();\n        }\n        //并且不让事件进一步传播\n        if (e.stopPropagation) e.stopPropagation(); //标准模型\n        else e.cancelBubble = true; //IE\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 在谷歌地图上显示地理位置信息\n```js\n//获取当前位置然后通过Google地图显示\n//如果当前浏览器不支持地理位置API，则抛出一个错误\nfunction getmap() { //检查是否支持地理位置API\n    if (!navigator.geolocation) throw \"Geolocation not supported\"; //开始请求地理位置信息，\n    navigator.geolocation.getCurrentPosition(setMapURL);\n    function setMapURL(pos) { //从参数对象（pos）中获取位置信息\n        var latitude = pos.coords.latitude; //经度\n        var longitude = pos.coords.longitude; //纬度\n        var accuracy = pos.coords.accuracy; //米\n        var scale = 10; //比例\n        //构造一个URL，用于跳转到Google地图\n        var url = \"https://www.google.com/maps/@\" + latitude + \",\" + longitude + \",\" + scale + \"z\"; //设置一个大致的缩放级别\n        location = url;\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 使用所有地理位置特性\n```js\n//异步的获取我的位置，并在指定的元素中展示出来\nfunction whereami(elt) { //将此对象作为第三个参数传递给getCurrentPosition()方法\n    var options = { //设置为true，表示如果可以的话\n        //获取高精度的位置信息（例如，通过GPS获取）\n        //但是，要注意的是，这会影响电池寿命\n        enableHighAccuracy: false, //可以近似：这是默认值\n        //如果获取缓存过的位置信息就足够的话，可以设置此属性\n        //默认值为0,表示强制检查新的位置信息\n        maximumAge: 300000, //5分钟左后\n        //愿意等待多长时间来获取位置信息？\n        //默认值为无限长 [2] ，getCurrentPosition()方法永不超时\n        timeout: 15000 //不要超过15秒\n    };\n    if (navigator.geolocation) //如果支持的话，就获取位置信息\n        navigator.geolocation.getCurrentPosition(success, error, options);\n    else\n        elt.innerHTMl = \"Geolocation not supported in this browser\"; //当获取位置信息失败的时候，会调用此函数\n\n    function error(e) { //error对象包含一些数字编码和文本消息，如下所示：\n        //1:用户不允许分享他/她的位置信息\n        //2:浏览器无法确定位置\n        //3:发生超时\n        elt.innerHTML = \"Geolocation error\" + e.code + \":\" + e.message;\n    }\n    //当获取位置信息成功的时候，会调用此函数\n    function success(pos) { //总是可以获取如下这些字段\n        //但是要注意的是时间戳信息在outer对象中，而不在inner、coords对象中\n        var msg = \"时间是\" +\n            new Date(pos.timestamp).toLocaleString() + \"地理位置是\" +\n            pos.coords.accuracy + \"米范围内经度是\" +\n            pos.coords.latitude + \"纬度是\" +\n            pos.coords.longitude + \".\"; //如果设备还返回了海拔信息，则将其添加进去\n        if (pos.coords.altitude) {\n            msg += \"海拔是\" + pos.coords.altitude + \"±\" +\n                pos.coords.altitudeAccuracy + \"千米.\";\n        }\n        //如果设备还返回了速度和航向信息，也将它们添加进去\n        if (pos.coords.speed) {\n            msg += \"速度是\" +\n                pos.coords.speed + \"m/s方向是\" +\n                pos.coords.heading + \".\";\n        }\n        elt.innerHTML = msg; //显示所有的位置信息\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 优雅的图片翻转实现\n```js\n/**\n *优雅的图片翻转实现方式\n *\n *要创建图片翻转效果，将此模块引入到HTML文件中\n *然后在任意＜img＞元素上使用data-rollover属性来指定翻转图片的URL即可\n *如下所示:\n *\n *\u003cimg src=\"normal_image.png \"data-rollover=\"rollover_image.png\"\u003e\n *\n */\nfunction changeImage() { //所有处理逻辑都在一个匿名函数中:不定义任何符号\n    //遍历所有的图片，查找data-rollover属性\n    for (var i = 0; i \u003c document.images.length; i++) {\n        var img = document.images[i];\n        var rollover = img.getAttribute(\"data-rollover\");\n        if (!rollover) continue; //跳过没有data-rollover属性的图片\n        //确保将翻转的图片缓存起来\n        (new Image()).src = rollover; //定义一个属性来标识默认的图片URL\n        img.setAttribute(\"data-rollout\", img.src); //注册事件处理函数来创建翻转效果\n        img.onmouseover = function () {\n            this.src = this.getAttribute(\"data-rollover\");\n        };\n        img.onmouseout = function () {\n            this.src = this.getAttribute(\"data-rollout\");\n        };\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 使用canvas绘制多边形\n```js\n//定义一个以(x,y)为中心，半径为r的规则n边形,c可以通过调用画布getContext()方法得到\n//每个顶点都是均匀分布在圆周上\n//将第一个顶点放置在最上面，或者指定一定角度\n//除非最后一个参数是true，否则顺时针旋转\nfunction polygon(c, n, x, y, r, angle, counterclockwise) {\n    angle = angle || 0;\n    counterclockwise = counterclockwise || false;\n    c.moveTo(x + r * Math.sin(angle), //从第一个顶点开始一条新的子路径\n        y - r * Math.cos(angle)); //使用三角法计算位置\n    var delta = 2 * Math.PI / n; //两个顶点之间的夹角\n    for (var i = 1; i \u003c n; i++) { //循环剩余的每个顶点\n        angle += counterclockwise ? -delta : delta; //调整角度\n        c.lineTo(x + r * Math.sin(angle), //以下个顶点为端点添加线段\n            y - r * Math.cos(angle));\n    }\n    c.closePath(); //将最后一个顶点和起点连接起来\n}\n```\n**[⬆ back to top](#readme)**\n## 使用canvas绘制雪花\n```js\nvar deg = Math.PI / 180; //用于角度制到弧度制的转换\n//在画布的上下文c中，以左下角的点(x,y)和边长len，绘制一个n级别的科赫雪花分形\nfunction snowflake(c, n, x, y, len) {\n    c.save(); //保存当前变换\n    c.translate(x, y); //变换原点为起始点\n    c.moveTo(0, 0); //从新的原点开始一条新的子路径\n    leg(n); //绘制雪花的第一条边\n    c.rotate(-120 * deg); //现在沿着逆时针方向旋转120 o\n    leg(n); //绘制第二条边\n    c.rotate(-120 * deg); //再次旋转\n    leg(n); //画最后一条边\n    c.closePath(); //闭合子路径\n    c.restore(); //恢复初始的变换\n    //绘制n级别的科赫雪花的一条边\n    //此函数在画完一条边的时候就离开当前点，\n    //然后通过坐标系变换将当前点又转换成(0,0,)\n    //这意味着画完一条边之后可以很简单地调用rotate()进行旋转\n    function leg(n) {\n        c.save(); //保存当前坐标系变换\n        if (n == 0) { //不需要递归的情况下:\n            c.lineTo(len, 0); //就绘制一条水平线段\n        } else { //递归情况下：绘制4条子边，类似这个样子： - \\/ -\n            c.scale(1 / 3, 1 / 3); //子边长度为原边长的1/3\n            leg(n - 1); //递归第一条子边\n            c.rotate(60 * deg); //顺时针旋转60 o\n            leg(n - 1); //第二条子边\n            c.rotate(-120 * deg); //逆时针旋转120 o\n            leg(n - 1); //第三条子边\n            c.rotate(60 * deg); //通过旋转回到初始状态\n            leg(n - 1); //最后一条边\n        }\n        c.restore(); //恢复坐标系变换\n        c.translate(len, 0); //但是通过转换使得边的结束点为(0,0)\n    }\n}\n```\n**[⬆ back to top](#readme)**\n## 在Web Worker中发起同步XMLHtttpRequest\n```js\n//此文件会通过一个新的Worker()来载入，因此，它是运行在独立的线程中的，\n//可以放心地使用同步XMLHttpRequest API\n//消息是URL数组的形式。以字符串形式同步获取每个URL指定的内容，\n//并将这些字符串数组传递回去。\nonmessage = function (e) {\n    var urls = e.data; //输入：要获取的URL\n    var contents = []; //输出：URL指定的内容\n    for (var i = 0; i \u003c urls.length; i++) {\n        var url = urls[i]; //每个URL\n        var xhr = new XMLHttpRequest(); //开始一个HTTP请求\n        xhr.open(\"GET\", url, false); //false则表示进行同步请求\n        xhr.send(); //阻塞住，一直到响应完成\n        if (xhr.status !== 200) //如果请求失败则抛出错误\n            throw Error(xhr.status + \" \" + xhr.statusText + \": \" + url);\n        contents.push(xhr.responseText); //否则，存储通过URL获取得到的内容\n    }\n    //最后，将这些URL内容以数组的形式传递回主线程\n    postMessage(contents);\n}\n```\n**[⬆ back to top](#readme)**\n## 统计字符串中每个字母的出现次数\n```js\nfunction statistics(str) {\n        str = str || \"\"; //处理在不传递参数的情况下不报错\n        var obj = {};\n        for (var i = 0; i \u003c str.length; i++) {\n                var element = str[i];\n                obj[element] = !obj[element] ? 1 : obj[element] + 1;\n        }\n        return obj;\n}\n```\n**[⬆ back to top](#readme)**\n## 拷贝数组\n```js\nvar toConsumableArray = function (arr) {\n    if (Array.isArray(arr)) {\n      for (var i = 0, arr2 = Array(arr.length); i \u003c arr.length; i++) arr2[i] = arr[i];\n      return arr2;\n    } else {\n      return Array.from(arr);\n    }\n  }\n```\n**[⬆ back to top](#readme)**\n## 给HTML元素增加样式类名\n```js\n        function hasClass(ele, cls) {\n            let reg = new RegExp(\"(^|\\\\s)\" + cls + \"(\\\\s|$)\");\n            return reg.test(ele.className);\n        }\n\n        function addClass(ele, cls) {\n            if (!hasClass(ele, cls)) {\n                console.log(2)\n                let newCls = ele.className.split(\" \");\n                newCls.push(cls);\n                ele.className = newCls.join(\" \");\n            }\n        }\n```\n**[⬆ back to top](#readme)**\n## 写一个范围函数\n```js\nfunction* range(start, end) {\n    yield start;\n    if (start === end) return;\n    yield* range(start + 1, end);\n}\n\nconsole.log([...range(2,6)]) //[ 2, 3, 4, 5, 6 ]\n```\n**[⬆ back to top](#readme)**\n## 写一个eval函数\n```js\nfunction DOMEval(code, doc) {\n\tdoc = doc || document;\n\tvar script = doc.createElement(\"script\");\n\tscript.text = code;\n\tdoc.head.appendChild(script).parentNode.removeChild(script);\n}\n```\n**[⬆ back to top](#readme)**\n## 判断空对象的函数\n```js\nfunction isEmptyObject(obj) {\n    var name;\n    for (name in obj) {\n        return false;\n    }\n    return true;\n}\n```\n**[⬆ back to top](#readme)**\n## 随机抽样调查\n```js\nlet ary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\nlet newAry = [];\n\nfor (let i = 0; i \u003c 5; i++) {\n    let num = Math.round(Math.random() * 9);\n    let value = ary[num];\n    newAry.push(value)\n\n    ary[num] = ary[ary.length - 1];\n    ary.length--;\n}\n\nconsole.log(newAry);\n```\n**[⬆ back to top](#readme)**\n## 求数组中的最大数\n```js\nlet ary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\nMath.max.apply(null, ary);\nMath.max(...ary);\n\nfunction max(ary) {\n    let max = ary[0];\n    for (const item of ary) {\n        max = max \u003e item ? max : item;\n    }\n    return max;\n}\n```\n**[⬆ back to top](#readme)**\n## 字符串的repeat的方法模仿\n```js\nvar repeat = function (str, n) {\n    var res = '';\n    while (n) {\n        if (n % 2 === 1) {\n            res += str;\n        }\n        if (n \u003e 1) {\n            str += str;\n        }\n        n \u003e\u003e= 1;\n    }\n    return res\n};\n\nconsole.log(repeat(\"*\", 6));\n```\n### 数组中concat模仿\n```js\nfunction concat( first, second ) {\n  var len = +second.length,\n    j = 0,\n    i = first.length;\n\n  for ( ; j \u003c len; j++ ) {\n    first[ i++ ] = second[ j ];\n  }\n\n  first.length = i;\n\n  return first;\n}\n\nlet res = concat([1,2,3], [1,2,3])\n```\n\n### 实现sleep函数\n```js\nfunction sleep (ms) {\n  let start = Date.now();\n  let expire = start + ms;\n  while (Date.now() \u003c expire) {}\n  console.log(1)\n}\n\nsleep(500)\n```\n### 实现所有对象的深度克隆\n```js\nfunction deepClone (obj, hash = new WeakMap()) {\n  if (obj == null) return obj;\n  if (obj instanceof Date) return new Date(obj);\n  if (obj instanceof RegExp) return new RegExp(obj);\n  if (typeof obj !== 'object') return obj;\n  if (hash.has(obj)) return hash.get(obj);\n  let cloneObj = new obj.constructor;\n  hash.set(obj, cloneObj);\n  for (const key in obj) {\n    if (obj.hasOwnProperty(key)) {\n      cloneObj[key] = obj[key];\n    }\n  }\n  return cloneObj;\n}\n```\n### 实现node的events模块\n```js\nfunction EventEmitter() {\n  EventEmitter.init.call(this);\n}\n\nEventEmitter.init = function () {\n  if (this._events === undefined) {\n    this._events = Object.create(null);\n    this._eventsCount = 0;\n  }\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n  return _addListener(this, type, listener)\n}\n\nfunction _addListener(target, type, listener) {\n  var events;\n  var existing;\n  events = target._events;\n  if (events === undefined) {\n    events = target._events = Object.create(null);\n    target._eventsCount = 0;\n  } else {\n    existing = events[type]\n  }\n  if (existing === undefined) {\n    events[type] = listener;\n    ++target._eventsCount;\n  } else {\n    if (typeof existing === 'function') {\n      existing = events[type] = [existing, listener]\n    } else {\n      existing.push(listener)\n    }\n  }\n  return target\n}\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener\n\nEventEmitter.prototype.emit = function emit(type, ...args) {\n  const events = this._events;\n  const handler = events[type];\n  if (handler === undefined) {\n    return false\n  }\n  if (typeof handler === 'function') {\n    Reflect.apply(handler, this, args)\n  } else {\n    let len = handler.length;\n    const listeners = arrayClone(handler, len);\n    for (var i = 0; i \u003c len; ++i) {\n      Reflect.apply(listeners[i], this, args)\n    }\n  }\n}\n\nfunction arrayClone(arr, n) {\n  var copy = new Array(n);\n  for (var i = 0; i \u003c n; ++i) {\n    copy[i] = arr[i];\n  }\n  return copy;\n}\n```\n### 求两数之和\n```js\n// 问题描述：给定一个数组，数组里面有两个数，他们的和已知是target，求这两个数在数组中的位置\nfunction solution(nums, target) {\n  for (let i = 0; i \u003c nums.length; i++) {\n    let a = nums[i]\n    for (let j = i + 1; j \u003c nums.length; j++) {\n      let b = nums[j]\n      if (b === target - a) {\n        console.log(i, j)\n      }\n    }\n  }\n}\n```\n### 二叉树翻转\n```js\n// 问题描述：根据二叉树的数据结构，需要将二叉树各节点左右翻转\nfunction reverse(node) {\n  if (node != null) {\n    let temp = node.left;\n    node.left = node.right;\n    node.right = temp;\n    reverse(node.left);\n    reverse(node.right);\n  }\n}\n```\n### 二分查找法模板\n```js\nfunction binary_search(left, right) {\n  while (left \u003c right) {\n    // 选择左中位数\n    let mid = (left + right) \u003e\u003e 1\n    if (check(mid)) {\n      // 先写可以排除中位数的逻辑\n      left = mid + 1\n    } else {\n      // 右边不能排除\n      right = mid\n    }\n  }\n  // 退出循环的时候，视情况，是否需要单独判断left（或者right）\n  return left\n}\n```\n### 将对象转换为树结构\n```js\nconst data = [\n  { id: 56, parentId: 62 },\n  { id: 81, parentId: 80 },\n  { id: 74, parentId: null },\n  { id: 76, parentId: 80 },\n  { id: 63, parentId: 62 },\n  { id: 80, parentId: 86 },\n  { id: 87, parentId: 86 },\n  { id: 62, parentId: 74 },\n  { id: 86, parentId: 74 },\n];\nlet tree = {\n  id: 74,\n  parentId: null,\n  children: [\n    {\n      id: 62,\n      parentId: 74,\n      children: [{ id: 56, parentId: 62 }, { id: 63, parentId: 62 }],\n    },\n    {\n      id: 86,\n      parentId: 74,\n      children: [\n        {\n          id: 80,\n          parentId: 86,\n          children: [{ id: 81, parentId: 80 }, { id: 76, parentId: 80 }],\n        },\n        { id: 87, parentId: 86 },\n      ],\n    },\n  ],\n};\n// 无需递归即可在O（n）时间内完成\nfunction createTree (data) {\n  let idMap = data.reduce((prev, cur, index) =\u003e {\n    prev[cur.id] = index\n    return prev\n  }, {})\n  let root;\n  data.forEach(item =\u003e {\n    if (item.parentId === null) {\n      return root = item\n    }\n    let parentEl = data[idMap[item.parentId]]\n    parentEl.children = [...(parentEl.children || []), item]\n  })\n  return root\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwuxianqiang%2Flibraries","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwuxianqiang%2Flibraries","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwuxianqiang%2Flibraries/lists"}