Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/wuxianqiang/libraries

方法库
https://github.com/wuxianqiang/libraries

javascript jquery

Last synced: 27 days ago
JSON representation

方法库

Awesome Lists containing this project

README

        

# libraries

# 目录
- [插入排序算法](#插入排序算法)
- [函数防抖](#函数防抖)
- [函数节流](#函数节流)
- [数组展平](#数组展平)
- [寻找最大值](#寻找最大值)
- [冒泡排序](#冒泡排序)
- [实现sleep函数](#实现sleep函数)
- [实现node的events模块](#实现node的events模块)
- [JS继承实现的6种方式](https://github.com/wuxianqiang/blog/issues/31)
- [实现所有对象的深度克隆](#实现所有对象的深度克隆)
- [二分查找法模板](#二分查找法模板)
- [将对象转换为树结构](#将对象转换为树结构)
- [foo(1)(2)(3)(4)实现1+2+3+4](#foo1234实现1234)
- [仿函数原型上的call()方法](#仿函数原型上的call方法)
- [仿数组原型上的push()方法](#仿数组原型上的push方法)
- [仿ES6中的Array.of()方法](#仿es6中的arrayof方法)
- [仿ECMAScript5中Object.create()函数](#仿ecmascript5中objectcreate函数)
- [仿ECMAScript5中String.trim()函数](#仿ecmascript5中stringtrim函数)
- [仿ECMAScript5中String.padstart()函数](#仿ecmascript5中stringpadstart函数)
- [仿ECMAScript5中String.padend()函数](#仿ecmascript5中stringpadend函数)
- [仿ECMAScript5中Array.reduce()函数](#仿ecmascript5中arrayreduce函数)
- [仿ECMAScript5中Object.keys()函数](#仿ecmascript5中objectkeys函数)
- [仿ECMAScript5中Function.bind()函数](#仿ecmascript5中functionbind函数)
- [仿ECMAScript5中Array.map()函数](#仿ecmascript5中arraymap函数)
- [仿ECMAScript5中Array.forEach()函数](#仿ecmascript5中arrayforeach函数)
- [仿ECMAScript5中Array.filter()函数](#仿ecmascript5中arrayfilter函数)
- [仿ECMAScript5中Array.every()函数](#仿ecmascript5中arrayevery函数)
- [仿ECMAScript5中Array.some()函数](#仿ecmascript5中arraysome函数)
- [仿ECMAScript5中Array.find()函数](#仿ecmascript5中arrayfind函数)
- [仿ECMAScript5中Array.findIndex()函数](#仿ecmascript5中arrayfindindex函数)
- [仿Array.indexOf()函数](#仿arrayindexof函数)
- [仿Math.max()方法实现](#仿mathmax方法不定实参函数)
- [仿String.match()方法实现](#仿stringmatch方法实现)
- [仿HTML5的classList属性实现](#仿html5的classlist属性)
- [仿Function.name属性实现](#返回函数的名字)
- [返回元素的第n层祖先元素](#返回元素的第n层祖先元素)
- [返回元素的第n个兄弟元素](#返回元素的第n个兄弟元素)
- [返回元素的第n个子代元素](#返回元素的第n个子代元素)
- [原生JS实现CSS动画之震动](#原生js实现css动画1)
- [原生JS实现CSS动画之隐藏](#原生js实现css动画2)
- [在数组中查找所有出现的元素方法](#在数组中查找所有出现的元素方法)
- [数据类型检测之特殊情况特殊处理](#数据类型检测特殊情况特殊处理)
- [使用innerHTML实现outerHTML属性](#使用innerhtml实现outerhtml属性)
- [插入节点](#插入节点)
- [倒序排列子节点](#倒序排列子节点)
- [查询窗口滚动条的位置](#查询窗口滚动条的位置)
- [查询窗口的视口尺寸](#查询窗口的视口尺寸)
- [表格的行排序](#表格的行排序)
- [生成目录表](#生成目录表)
- [数组去重](#数组去重)
- [冒泡排序](#冒泡排序)
- [从URL解析参数](#从url解析参数)
- [获取纯文本的元素内容](#获取纯文本的元素内容)
- [手写一个JSONP实现](#手写一个jsonp实现)
- [查询纯文本形式的内容](#查询纯文本形式的内容)
- [查找元素的后代中节点中的所有Text节点](#查找元素的后代中节点中的所有text节点)
- [使用innerHTML实现insertAdjacentHTML](#使用innerhtml实现insertadjacenthtml)
- [拖拽](#拖拽)
- [在谷歌地图上显示地理位置信息](#在谷歌地图上显示地理位置信息)
- [使用所有地理位置特性](#使用所有地理位置特性)
- [优雅的图片翻转实现](#优雅的图片翻转实现)
- [使用canvas绘制多边形](#使用canvas绘制多边形)
- [使用canvas绘制雪花](#使用canvas绘制雪花)
- [在Web Worker中发起同步XMLHtttpRequest](#在web-worker中发起同步xmlhtttprequest)
- [统计字符串中每个字母的出现次数](#统计字符串中每个字母的出现次数)
- [给HTML元素增加样式类名](#给html元素增加样式类名)
- [写一个范围函数](#写一个范围函数)
- [写一个eval函数](#写一个eval函数)
- [判断空对象的函数](#判断空对象的函数)
- [随机抽样调查](#随机抽样调查)
- [求数组中的最大数](#求数组中的最大数)
- [字符串的repeat的方法模仿](#字符串的repeat的方法模仿)
- [求两数之和](#求两数之和)
- [二叉树翻转](#二叉树翻转)

## 插入排序算法
```js
function insert_sort (A) {
for (let j = 1, len = A.length; j < len; j++) {
const key = A[j]
let i = j - 1
while (i >= 0 && A[i] > key) {
A[i + 1] = A[i]
i--
}
A[i + 1] = key
}
}
```

## 函数防抖
```js
function debounce (func, delay = 300, I = null) {
return (...args) => {
clearTimeout(I)
I = setTimeout(func.bind(null, ...args), delay)
}
}
```

## 函数节流
```js
function throttle (func, delay = 60) {
let lock = false
return (...args) => {
if (lock) {
return
}
func(...args)
lock = true
setTimeout(() => {
lock = false
}, delay)
}
}
```

## 数组展平
```js
function flatten (arr) {
return [].concat(
...arr.map(x =>
Array.isArray(x) ? flatten(x) : x
)
)
}
```

## 寻找最大值
```js
// O(n)的算法
function find_max (arr) {
let max = Number.NEGATIVE_INFINITY
for (let i = 0, len = arr.length; i < len; i++) {
max = (arr[i] > max ? arr[i] : max)
}
return max
}
```

## 冒泡排序
```js
// O^2算法
function bubble_sort (A) {
for (let i = A.length; i > 0; i--) {
for (let j = 1; j < i; j++) {
if (A[j] < A[j - 1]) {
swap(A, j, j - 1)
}
}
}
return A
}

function swap (A, i, j) {
const t = A[i]
A[i] = A[j]
A[j] = t
}
```

## foo(1)(2)(3)(4)实现1+2+3+4
```js
const curry = func => {
const g = (...allArgs) => allArgs.length >= func.length ? func(...allArgs) : (...args) => g(...allArgs, ...args)
return g
}
const foo = curry ((a, b, c, d) => {
return a + b + c + d
})
foo(1)(2)(3)(4)
```

## 仿ECMAScript5中String.padEnd()函数
```js
String.prototype.mypadEnd = function (num, replacer) {
var len = ('' + this).length;
return this + (Array(
num > len ? num - len + 1 || 0 : 0
).join(replacer));
}
```

## 仿ECMAScript5中String.padStart()函数
```js
String.prototype.mypadStart = function (num, replacer) {
var len = ('' + this).length;
return (Array(
num > len ? num - len + 1 || 0 : 0
).join(replacer) + this);
}
```

## 仿函数原型上的call()方法
```js
Function.prototype.mycall = function mycall() {
var ary = [...arguments].slice(1);
if (arguments[0] == undefined) {
this(...ary);
} else {
var obj = Object(arguments[0]);
obj.__proto__.fn = this;
obj.fn(...ary);
delete obj.__proto__.fn;
}
return this;
}
```
**[⬆ back to top](#readme)**
## 仿数组原型上的push()方法
```js
Array.prototype.myPush = function () {
let argLen = arguments.length;
if (argLen === 0) return this.length;
for (let i = 0; i < argLen; i++) {
const element = arguments[i];
this[this.length] = element;
}
return this.length;
}
```
**[⬆ back to top](#readme)**
**[⬆ back to top](#readme)**
## 仿ES6中的Array.of()方法
```js
let myArray = { of: function of () {
const len = arguments.length;
if (len === 0) return [];
let ary = [];
for (let i = 0; i < len; i++) {
const element = arguments[i];
ary.push(element);
}
return ary;
}
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Object.create()函数
```js
function inherit(obj) {
if (obj === null) throw TypeError();
if (Object.create) return Object.create(obj);
var t = typeof obj;
if (t !== "object" && t !== "function") throw TypeError();
function Fn() {};
Fn.prototype = obj;
return new Fn();
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中String.trim()函数
```js
String.prototype.mytrim = function () {
String.prototype.trim || function () {
if (!this) return this; //空字符串不做处理
return this.replace(/^\s+|\s+$/g, "") //使用正则表达式经行空格替换
}
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.reduce()函数

```js
var reduce = Array.prototype.reduce ? function (ary, fn, initial) {
if (arguments.length > 2) { //如果reduce()方法存在的话
return ary.reduce(fn, initial); //如果传入了一个初始值
} else {
return ary.reduce(fn); //否则初始值
}
} : function (ary, fn, initial) { //以特定的初始值开始,否则第一个值取自ary
var i = 0,
len = ary.length,
accumulator;
if (arguments.length > 2) {
accumulator = initial;
} else { //找到数组中第一个已经定义的索引
if (len == 0) throw TypeError();
while (i < len) {
if (i in ary) {
accumulator = ary[i++];
break;
} else {
i++;
}
}
if (i == len) throw TypeError();
}
while (i < len) { //对于数组中剩下的元素依次调用fn
if (i in ary) {
accumulator = fn.call(undefined, accumulator, ary[i], i, ary)
}
i++;
}
return accumulator;
}
```
**[⬆ back to top](#readme)**
## 在数组中查找所有出现的元素方法

```js
function findAll(ary, ele) {
var results = [],
len = ary.length,
pos = 0;
while (pos < len) {
pos = ary.indexOf(ele, pos);
if (pos === -1) break;
results.push(pos);
pos++;
}
return results;
}
```
**[⬆ back to top](#readme)**
## 数据类型检测,特殊情况特殊处理

```js
function classOf(obj) {
if (obj === null) return "Null";
if (obj === undefined) return 'Undefined';
return Object.prototype.toString.call(obj).slice(8, -1);
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Object.keys()函数

```js
function keys(obj) {
if (typeof obj !== "object") {
throw TypeError();
}
var result = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
result.push(prop);
}
}
return result;
}
```
**[⬆ back to top](#readme)**
## 仿Math.max方法(不定实参函数)

```js
function max() {
var max = Number.NEGATIVE_INFINITY;
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] > max) max = arguments[i];
}
return max;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Function.bind()函数

```js
if (!Function.prototype.bind) {
Function.prototype.bind = function (obj) {
var self = this,
boundArgs = arguments;
return function () {
var args = [],
i;
for (i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
for (i = 1; i < arguments.length; i++) args.push(arguments[i]);
return self.apply(obj, args);
}
}
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.map()函数

```js
Array.prototype.mymap = function (fn, obj) {
let res = [];
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
res[i] = fn(element, i, this)
} else {
res[i] = fn.call(obj, element, i, this);
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.forEach()函数
```js
Array.prototype.myforEach = function (fn, obj) {
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
fn(element, i, this)
} else {
fn.call(obj, element, i, this);
}
}
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.filter()函数
```js
Array.prototype.myfilter = function (fn, obj) {
let res = [],
index = 0;
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
let cur = fn(element, i, this);
if (cur) res[index++] = element;
} else {
let cur = fn.call(obj, element, i, this);
if (cur) res[index++] = element;
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.every()函数
```js
Array.prototype.myevery = function (fn, obj) {
let res = true;
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
let cur = fn(element, i, this);
if (!cur) {
res = false;
break;
}
} else {
let cur = fn.call(obj, element, i, this);
if (!cur) {
res = false;
break;
}
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.some()函数
```js
Array.prototype.mysome = function (fn, obj) {
let res = false;
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
let cur = fn(element, i, this);
if (cur) {
res = true;
break;
}
} else {
let cur = fn.call(obj, element, i, this);
if (cur) {
res = true;
break;
}
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.find()函数
```js
Array.prototype.myfind = function (fn, obj) {
   let res = undefined;
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
let cur = fn(element, i, this);
if (cur) {
res = element;
break;
}
} else {
let cur = fn.call(obj, element, i, this);
if (cur) {
res = element;
break;
}
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿ECMAScript5中Array.findIndex()函数
```js
Array.prototype.myfindIndex = function (fn, obj) {
   let res = undefined;
for (let i = 0; i < this.length; i++) {
const element = this[i];
if (obj == undefined) {
let cur = fn(element, i, this);
if (cur) {
res = i;
break;
}
} else {
let cur = fn.call(obj, element, i, this);
if (cur) {
res = i;
break;
}
}
}
return res;
}
```
**[⬆ back to top](#readme)**
## 仿Array.indexOf()函数
```js
String.prototype.myindexOf = function () {
let index = -1;
let arg = arguments.length;
if (!arg) return index;
let s1 = arguments[0][0];
if (arg > 1) {
let param = arguments[1];
if (typeof param !== "number" || isNaN(param)) return index;
let len = this.length;
if (param < 0 && param >= -len) {
param += len;
} else if (param < -len) {
param = 0
} else if (param > len) {
return index;
}
for (let i = param; i < len; i++) {
const s2 = this[i];
if (s1 === s2) {
index = i;
break;
}
}
}
if (!arguments[1]) {
for (let i = 0; i < this.length; i++) {
const s2 = this[i];
if (s1 === s2) {
index = i;
break;
}
}
}
return index;
}
```
**[⬆ back to top](#readme)**
## 数组去重

```js
Array.prototype.unique = function unique() {
var obj = {};
for (var i = 0; i < this.length; i++) {
var current = this[i];
if (obj[current] === current) {
current = this[this.length - 1];
this.length--;
i--;
continue;
}
obj[current] = current
}
obj = null;
return this;
}
```
**[⬆ back to top](#readme)**
## 冒泡排序

```js
Array.prototype.bubbleSort = function bubbleSort() {
var temp = null;
for (var i = 0; i < this.length - 1; i++) {
for (var k = 0; k < this.length - 1 - i; k++) {
if (this[k] > this[k + 1]) {
temp = this[k];
this[k] = this[k + 1];
this[k + 1] = temp;
}
}
}
return this;
}

```
**[⬆ back to top](#readme)**
## 仿String.match()方法实现

```js
String.prototype.mymatch = function (reg) {
var ary = [];
var res = reg.exec(this);
while (res) {
ary.push(res[0]);
res = reg.exec(this);
}
return ary;
}
```
**[⬆ back to top](#readme)**
## 返回元素的第n层祖先元素

```js
/**
*返回元素ele的第n层祖先元素,如果不存在此类祖先或祖先不是Element,
*(例如Document或者DocumentFragment)则返回null
*如果n为0,则返回e本身。如果n为1(或省略),则返回其父元素
*如果n为2,则返回其祖父元素,依次类推
*/
function parent(ele, n) {
if (n === nudefined) n = 1;
while (n-- && ele) {
ele = ele.parentNode;
}
if (!ele || ele.nodeTope !== 1) return null;
return ele;
}
```
**[⬆ back to top](#readme)**
## 返回元素的第n个兄弟元素

```js
/**
*返回元素ele的第n个兄弟元素
*如果n为正,返回后续的第n个兄弟元素
*如果n为负,返回前面的第n个兄弟元素
*如果n为零,返回ele本身
*/
function sibling(ele, n) {
while (ele && n !== 0) { //如果ele未定义,即刻返回它
if (n > 0) { //查找后续的兄弟元素
if (ele.nextElementSibling) {
ele = ele.nextElementSibling;
} else {
for (ele = ele.nextSibling; ele && ele.nodeType !== 1; ele = ele.nextSibling) /*空循环*/;
}
n--;
} else { //查找前面的兄弟元素
if (ele.previousElementSibing) {
ele = ele.previousElementSibling;
} else {
for (ele = ele.previousSibling; ele && ele.nodeType !== 1; ele = ele.previousSibling) /*空循环*/;
}
n++;
}
}
return ele;
}
```
**[⬆ back to top](#readme)**
## 返回元素的第n个子代元素

```js
/**
*返回元素ele的第n代子元素,如果不存在则为null
*负值n代表从后往前计数。0表示第一个子元素,而-1代表最后一个,-2代表倒数第二个,依次类推
*/
function child(ele, n) {
if (ele.children) { //如果children数组存在
if (n < 0) n += ele.children.length; //转换负的n为数组索引
if (n < 0) return null; //如果它仍然为负,说明没有子元素
return ele.children[n]; //返回指定的子元素
}
//如果e没有children数组,找到第一个子元素并向前数,或找到最后一个子元素并往回数
if (n >= 0) { //n非负:从第一个子元素向前数
//找到元素e的第一个子元素
if (ele.firstElementChild) {
ele = ele.firstElementChild;
} else {
for (ele = ele.firstChild; ele && ele.nodeType !== 1; ele = ele.nextSibling) /*空循环*/;
}
return sibling(ele, n); //返回第一个子元素的第n个兄弟元素
} else { //n为负:从最后一个子元素往回数
if (ele.lastElementChild) {
ele = ele.lastElementChild;
} else {
for (ele = ele.lastChild; ele && ele.nodeType !== 1; ele = ele.previousSibling) /*空循环*/;
}
return sibling(ele, n + 1); //+1来转化最后1个子元素为最后1个兄弟元素
}
}
```
**[⬆ back to top](#readme)**
## 表格的行排序

```js
//根据指定表格每行第n个单元格的值,对第一个<tbody>中的行进行排序
//如果存在comparator函数则使用它,否则按字母表顺序比较
function sortrows(table, n, comparator) {
var tbody = table.tBodies[0]; //第一个<tbody>,可能是隐式创建的
var rows = tbody.getElementsByTagName("tr"); //tbody中的所有行
rows = Array.prototype.slice.call(rows, 0); //真实数组中的快照
//基于第n个<td>元素的值对行排序
rows.sort(function (row1, row2) {
var cell1 = row1.getElementsByTagName("td")[n]; //获得第n个单元格
var cell2 = row2.getElementsByTagName("td")[n]; //两行都是
var val1 = cell1.textContent || cell1.innerText; //获得文本内容
var val2 = cell2.textContent || cell2.innerText; //两单元格都是
if (comparator) return comparator(val1, val2); //进行比较
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}); //在tbody中按它们的顺序把行添加到最后
//这将自动把它们从当前位置移走,故没必要预先删除它们
//如果<tbody>还包含了除了<tr>的任何其他元素,这些节点将会悬浮到顶部位置
for (var i = 0; i < rows.length; i++) tbody.appendChild(rows[i]);
}
//查找表格的<th>元素(假设只有一行),让它们可单击,
//以便单击列标题,按该列对行排序
function makeSortable(table) {
var headers = table.getElementsByTagName("th");
for (var i = 0; i < headers.length; i++) {
(function (n) { //嵌套函数来创建本地作用域
headers[i].onclick = function () {
sortrows(table, n);
};
}(i)); //将i的值赋给局部变量n
}
}
```
**[⬆ back to top](#readme)**
## 生成目录表
```js
/**
*
*这个模块注册一个可在页面加载完成后自动运行的匿名函数。当执行这个函数时会去文档中查找
*id为"TOC"的元素。如果这个元素不存在,就创建一个元素
*
*生成的TOC目录应当具有自己的CSS样式。整个目录区域的样式className设置为"TOCEntry"
*同样我们为不同层级的目录标题定义不同的样式。<h1>标签生成的标题
*className为"TOCLevel1",<h2>标签生成的标题className为"TOCLevel2",以此类推
*段编号的样式为"TOCSectNum"
*
*完整的CSS样式代码如下:
*
*#TOC{border:solid black 1px;margin:10px;padding:10px;}
*.TOCEntry{font-family:sans-serif;}
*.TOCEntry a{text-decoration:none;}
*.TOCLevel1{font-size:16pt;font-weight:bold;}
*.TOCLevel2{font-size:12pt;margin-left:.5in;}
*.TOCSectNum:after{content:":";}
*
*这段代码的最后一行表示每个段编号之后都有一个冒号和空格符。要想隐藏段编号,
*请使用这行代码:
*.TOCSectNum{display:none}
*
**/
(function () { //匿名函数定义了一个局部作用域
//查找TOC容器元素
//如果不存在,则在文档开头处创建一个
var toc = document.getElementById("TOC");
if (!toc) {
toc = document.createElement("div");
toc.id = "TOC";
document.body.insertBefore(toc, document.body.firstChild);
}
//查找所有的标题元素
var headings;
if (document.querySelectorAll) //我们是否能用这个简单的方法?
headings = document.querySelectorAll("h1,h2,h3,h4,h5,h6");
else //否则,查找方法稍微麻烦一些
headings = findHeadings(document.body, []); //递归遍历document的body,查找标题元素
function findHeadings(root, sects) {
for (var c = root.firstChild; c != null; c = c.nextSibling) {
if (c.nodeType !== 1) continue;
if (c.tagName.length == 2 && c.tagName.charAt(0) == "H")
sects.push(c);
else
findHeadings(c, sects);
}
return sects;
}
//初始化一个数组来保持跟踪章节号
var sectionNumbers = [0, 0, 0, 0, 0, 0]; //现在,循环已找到的标题元素
for (var h = 0; h < headings.length; h++) {
var heading = headings[h]; //跳过在TOC容器中的标题元素
if (heading.parentNode == toc) continue; //判定标题的级别
var level = parseInt(heading.tagName.charAt(1));
if (isNaN(level) || level < 1 || level > 6) continue; //对于该标题级别增加sectionNumbers对应的数字
//重置所有标题比它级别低的数字为零
sectionNumbers[level - 1]++;
for (var i = level; i < 6; i++) sectionNumbers[i] = 0; //现在,将所有标题级别的章节号组合产生一个章节号, 如2 .3 .1
var sectionNumber = sectionNumbers.slice(0, level).join(".") //为标题级别增加章节号
//把数字放在<span>中,使得其可以用样式修饰
var span = document.createElement("span");
span.className = "TOCSectNum";
span.innerHTML = sectionNumber;
heading.insertBefore(span, heading.firstChild); //用命名的锚点将标题包起来,以便为它增加链接
var anchor = document.createElement("a");
anchor.name = "TOC" + sectionNumber;
heading.parentNode.insertBefore(anchor, heading);
anchor.appendChild(heading); //现在为该节创建一个链接
var link = document.createElement("a");
link.href = "#TOC" + sectionNumber; //链接的目标地址
link.innerHTML = heading.innerHTML; //链接文本与实际标题一致
//将链接放在一个div中,div用基于级别名字的样式修饰
var entry = document.createElement("div");
entry.className = "TOCEntry TOCLevel" + level;
entry.appendChild(link); //该div添加到TOC容器中
toc.appendChild(entry);
}
}());
```
**[⬆ back to top](#readme)**
## 从URL解析参数

```js
/*
*这个函数用来解析来自URL的查询串中的name=value参数对
*它将name=value对存储在一个对象的属性中,并返回该对象
*这样来使用它
*
*var args=urlArgs();//从URL中解析参数
*var q=args.q||"";//如果参数定义了的话就使用参数;否则使用一个默认值
*var n=args.n?parseInt(args.n):10;
*/
function urlArgs() {
var args = {}; //定义一个空对象
var query = location.search.substring(1); //查找到查询串,并去掉'?'
var pairs = query.split("&"); //根据"&"符号将查询字符串分隔开
for (var i = 0; i < pairs.length; i++) { //对于每个片段
var pos = pairs[i].indexOf('='); //查找"name=value"
if (pos == -1) continue; //如果没有找到的话,就跳过
var name = pairs[i].substring(0, pos); //提取name
var value = pairs[i].substring(pos + 1); //提取value
value = decodeURIComponent(value); //对value进行解码
args[name] = value; //存储为属性
}
return args; //返回解析后的参数
}
```
**[⬆ back to top](#readme)**

## 获取纯文本的元素内容

```js
/**
*一个参数,返回元素的textContent或innerText
*两个参数,用value参数的值设置元素的textContent或innerText
*/
function textContent(element, value) {
var content = element.textContent; //检测textContent是否有定义
if (value === undefined) { //没传递value,因此返回当前文本
if (content !== undefined) {
return content;
} else {
return element.innerText;
}
} else { //传递了value,因此设置文本
if (content !== undefined) {
element.textContent = value;
} else {
element.innerText = value;
}
}
}
```
**[⬆ back to top](#readme)**
## 手写一个JSONP实现

```js
//根据指定的URL发送一个JSONP请求
//然后把解析得到的响应数据传递给回调函数
//在URL中添加一个名为jsonp的查询参数,用于指定该请求的回调函数的名称
function getJSONP(url, callback) { //为本次请求创建一个唯一的回调函数名称
var cbnum = "cb" + getJSONP.counter++; //每次自增计数器
var cbname = "getJSONP." + cbnum; //作为JSONP函数的属性
//将回调函数名称以表单编码的形式添加到URL的查询部分中
//使用jsonp作为参数名,一些支持JSONP的服务
//可能使用其他的参数名,比如callback
if (url.indexOf("?") === -1) //URL没有查询部分
url += "?jsonp=" + cbname; //作为查询部分添加参数
else //否则
url += "&jsonp=" + cbname; //作为新的参数添加它
//创建script元素用于发送请求
var script = document.createElement("script"); //定义将被脚本执行的回调函数
getJSONP[cbnum] = function (response) {
try {
callback(response); //处理响应数据
} finally { //即使回调函数或响应抛出错误
delete getJSONP[cbnum]; //删除该函数
script.parentNode.removeChild(script); //移除script元素
}
}; //立即触发HTTP请求
script.src = url; //设置脚本的URL
document.body.appendChild(script); //把它添加到文档中
}
getJSONP.counter = 0; //用于创建唯一回调函数名称的计数器
```
**[⬆ back to top](#readme)**
## 插入节点

```js
//将child节点插入到parent中,使其成为第n个子节点
function insertAt(parent, child, n) {
if (n < 0 || n > parent.childNodes.length) {
throw new Error("invalid index");
} else if (n == parent.childNodes.length) {
parent.appendChild(child);
} else {
parent.insertBefore(child, parent.childNodes[n]);
}
}
```
**[⬆ back to top](#readme)**
## 使用innerHTML实现outerHTML属性
```js
//为那些不支持它的浏览器实现outerHTML属性
//假设浏览器确实支持innerHTML,并有个可扩展的Element.prototype,
//并且可以定义getter和setter
(function () { //如果outerHTML存在,则直接返回
if (document.createElement("div").outerHTML) return; //返回this所引用元素的外部HTML
function outerHTMLGetter() {
var container = document.createElement("div"); //虚拟元素
container.appendChild(this.cloneNode(true)); //复制到该虚拟节点
return container.innerHTML; //返回虚拟节点的innerHTML
}
//用指定的值设置元素的外部HTML
function outerHTMLSetter(value) { //创建一个虚拟元素,设置其内容为指定的值
var container = document.createElement("div");
container.innerHTML = value; //将虚拟元素中的节点全部移动到文档中
while (container.firstChild) //循环,直到container没有子节点为止
this.parentNode.insertBefore(container.firstChild, this); //删除所被取代的节点
this.parentNode.removeChild(this);
}
//现在使用这两个函数作为所有Element对象的outerHTML属性的getter和setter
//如果它存在则使用ES5的Object.defineProperty()方法,
//否则,退而求其次,使用__defineGetter__()和__defineSetter__()
if (Object.defineProperty) {
Object.defineProperty(Element.prototype, "outerHTML", {
get: outerHTMLGetter,
set: outerHTMLSetter,
enumerable: false,
configurable: true
});
} else {
Element.prototype.__defineGetter__("outerHTML", outerHTMLGetter);
Element.prototype.__defineSetter__("outerHTML", outerHTMLSetter);
}
}());
```
**[⬆ back to top](#readme)**
## 倒序排列子节点
```js
//倒序排列节点n的子节点
function reverse(n) { //创建一个DocumentFragment作为临时容器
var f = document.createDocumentFragment(); //从后至前循环子节点,将每一个子节点移动到文档片段中
//n的最后一个节点变成f的第一个节点,反之亦然
//注意,给f添加一个节点,该节点自动地会从n中删除
while (n.lastChild) f.appendChild(n.lastChild); //最后,把f的所有子节点一次性全部移回n中
n.appendChild(f);
}
```
**[⬆ back to top](#readme)**
## 查询窗口滚动条的位置
```js
//以一个对象的x和y属性的方式返回滚动条的偏移量
function getScrollOffsets(w) { //使用指定的窗口,如果不带参数则使用当前窗口
w = w || window; //除了IE 8及更早的版本以外,其他浏览器都能用
if (w.pageXOffset != null) return {
x: w.pageXOffset,
y: w.pageYOffset
}; //对标准模式下的IE(或任何浏览器)
var d = w.document;
if (document.compatMode == "CSS1Compat")
return {
x: d.documentElement.scrollLeft,
y: d.documentElement.scrollTop
}; //对怪异模式下的浏览器
return {
x: d.body.scrollLeft,
y: d.body.scrollTop
};
}
```
**[⬆ back to top](#readme)**
## 查询窗口的视口尺寸
```js
//作为一个对象的w和h属性返回视口的尺寸
function getViewportSize(w) { //使用指定的窗口,如果不带参数则使用当前窗口
w = w || window; //除了IE 8及更早的版本以外,其他浏览器都能用
if (w.innerWidth != null) return {
w: w.innerWidth,
h: w.innerHeight
}; //对标准模式下的IE(或任何浏览器)
var d = w.document;
if (document.compatMode == "CSS1Compat")
return {
w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight
}; //对怪异模式下的浏览器
return {
w: d.body.clientWidth,
h: d.body.clientWidth
};
}
```
**[⬆ back to top](#readme)**
## 返回函数的名字
```js
Function.prototype.getName = function () {
return this.name || this.toString().match(/function\s*(\w*)\s*\(/)[1];
}
```
**[⬆ back to top](#readme)**
## 原生JS实现CSS动画1
```js
//将e转化为相对定位的元素,使之左右"震动"
//第一个参数可以是元素对象或者元素的id
//如果第二个参数是函数,以e为参数,它将在动画结束时调用
//第三个参数指定e震动的距离,默认是5像素
//第四个参数指定震动多久,默认是500毫秒
function shake(e, oncomplete, distance, time) { //句柄参数
if (typeof e === "string") e = document.getElementById(e);
if (!time) time = 500;
if (!distance) distance = 5;
var originalStyle = e.style.cssText; //保存e的原始style
e.style.position = "relative"; //使e相对定位
var start = (new Date()).getTime(); //注意,动画的开始时间
animate(); //动画开始
//函数检查消耗的时间,并更新e的位置
//如果动画完成,它将e还原为原始状态
//否则,它更新e的位置,安排它自身重新运行
function animate() {
var now = (new Date()).getTime(); //得到当前时间
var elapsed = now - start; //从开始以来消耗了多长时间?
var fraction = elapsed / time; //是总时间的几分之几?
if (fraction < 1) { //如果动画未完成
//作为动画完成比例的函数,计算e的x位置
//使用正弦函数将完成比例乘以4pi
//所以,它来回往复两次
var x = distance * Math.sin(fraction * 4 * Math.PI);
e.style.left = x + "px"; //在25毫秒后或在总时间的最后尝试再次运行函数
//目的是为了产生每秒40帧的动画
setTimeout(animate, Math.min(25, time - elapsed));
} else { //否则,动画完成
e.style.cssText = originalStyle //恢复原始样式
if (oncomplete) oncomplete(e); //调用完成后的回调函数
}
}
}
```
**[⬆ back to top](#readme)**
## 原生JS实现CSS动画2
```js
function fadeOut(e, oncomplete, time) {
if (typeof e === "string") e = document.getElementById(e);
if (!time) time = 500; //使用Math.sqrt作为一个简单的“缓动函数”来创建动画
//精巧的非线性:一开始淡出得比较快,然后缓慢了一些
var ease = Math.sqrt;
var start = (new Date()).getTime(); //注意:动画开始的时间
animate(); //动画开始
function animate() {
var elapsed = (new Date()).getTime() - start; //消耗的时间
var fraction = elapsed / time; //总时间的几分之几?
if (fraction < 1) { //如果动画未完成
var opacity = 1 - ease(fraction); //计算元素的不透明度
e.style.opacity = String(opacity); //设置在e上
setTimeout(animate, //调度下一帧
Math.min(25, time - elapsed));
} else { //否则,动画完成
e.style.opacity = "0"; //使e完全透明
if (oncomplete) oncomplete(e); //调用完成后的回调函数
}
}
}
```
**[⬆ back to top](#readme)**
## 仿HTML5的classList属性
```js
/*
*如果e有classList属性则返回它。否则,返回一个为e模拟DOMTokenList API的对象
*返回的对象有contains()、add()、remove()、toggle()和toString()等方法
*来检测和修改元素e的类集合。如果classList属性是原生支持的,
*返回的类数组对象有length和数组索引属性。模拟DOMTokenList不是类数组对象,
*但是它有一个toArray()方法来返回一个含元素类名的纯数组快照
*/
function classList(e) {
if (e.classList) return e.classList; //如果e.classList存在,则返回它
else return new CSSClassList(e); //否则,就伪造一个
}
//CSSClassList是一个模拟DOMTokenList的JavaScript类
function CSSClassList(e) {
this.e = e;
} //如果e.className包含类名c则返回true否则返回false
CSSClassList.prototype.contains = function (c) { //检查c是否是合法的类名
if (c.length === 0 || c.indexOf(" ") != -1)
throw new Error("Invalid class name:'" + c + "'"); //首先是常规检查
var classes = this.e.className;
if (!classes) return false; //e不含类名
if (classes === c) return true; //e有一个完全匹配的类名
//否则,把c自身看做一个单词,利用正则表达式搜索c
//\b在正则表达式里代表单词的边界
return classes.search("\\b" + c + "\\b") != -1;
}; //如果c不存在,将c添加到e.className中
CSSClassList.prototype.add = function (c) {
if (this.contains(c)) return; //如果存在,什么都不做
var classes = this.e.className;
if (classes && classes[classes.length - 1] != "")
c = "" + c; //如果需要加一个空格
this.e.className += c; //将c添加到className中
}; //将在e.className中出现的所有c都删除
CSSClassList.prototype.remove = function (c) { //检查c是否是合法的类名
if (c.length === 0 || c.indexOf(" ") != -1)
throw new Error("Invalid class name:'" + c + "'"); //将所有作为单词的c和多余的尾随空格全部删除
var pattern = new RegExp("\\b" + c + "\\b\\s*", "g");
this.e.className = this.e.className.replace(pattern, "");
}; //如果c不存在,将c添加到e.className中,并返回true
//否则,将在e.className中出现的所有c都删除,并返回false
CSSClassList.prototype.toggle = function (c) {
if (this.contains(c)) { //如果e.className包含c
this.remove(c); //删除它
return false;
} else { //否则
this.add(c); //添加它
return true;
}
}; //返回e.className本身
CSSClassList.prototype.toString = function () {
return this.e.className;
}; //返回在e.className中的类名
CSSClassList.prototype.toArray = function () {
return this.e.className.match(/\b\w+\b/g) || [];
};
```
**[⬆ back to top](#readme)**
## 查询纯文本形式的内容
```js
/**
*一个参数,返回元素的textContent或innerText
*两个参数,用value参数的值设置元素的textContent或innerText
*/
function textContent(element, value) {
var content = element.textContent; //检测textContent是否有定义
if (value === undefined) { //没传递value,因此返回当前文本
if (content !== undefined) return content;
else return element.innerText;
} else { //传递了value,因此设置文本
if (content !== undefined) element.textContent = value;
else element.innerText = value;
}
}
```
textContent属性在除了IE的所有当前的浏览器中都支持。在IE中,可以用Element的innerText属性来代替。
**[⬆ back to top](#readme)**
## 查找元素的后代中节点中的所有Text节点
```js
//返回元素e的纯文本内容,递归进入其子元素
//该方法的效果类似于textContent属性
function textContent(e) {
var child, type, s = ""; //s保存所有子节点的文本
for (child = e.firstChild; child != null; child = child.nextSibling) {
type = child.nodeType;
if (type === 3 || type === 4) //Text和CDATASection节点
s += child.nodeValue;
else if (type === 1) //递归Element节点
s += textContent(child);
}
return s;
}
```
**[⬆ back to top](#readme)**
## 使用innerHTML实现insertAdjacentHTML()
```js
//本模块为不支持它的浏览器定义了Element.insertAdjacentHTML
//还定义了一些可移植的HTML插入函数,它们的名字比insertAdjacentHTML更符合逻辑:
//Insert.before()、Insert.after()、Insert.atStart()和Insert.atEnd()
var Insert = (function () { //如果元素有原生的insertAdjacentHTML,
//在4个函数名更明了的HTML插入函数中使用它
if (document.createElement("div").insertAdjacentHTML) {
return {
before: function (e, h) {
e.insertAdjacentHTML("beforebegin", h);
},
after: function (e, h) {
e.insertAdjacentHTML("afterend", h);
},
atStart: function (e, h) {
e.insertAdjacentHTML("afterbegin", h);
},
atEnd: function (e, h) {
e.insertAdjacentHTML("beforeend", h);
}
};
}
//否则,无原生的insertAdjacentHTML
//实现同样的4个插入函数,并使用它们来定义insertAdjacentHTML
//首先,定义一个工具函数,传入HTML字符串,返回一个DocumentFragment,
//它包含了解析后的HTML的表示
function fragment(html) {
var elt = document.createElement("div"); //创建空元素
var frag = document.createDocumentFragment(); //创建空文档片段
elt.innerHTML = html; //设置元素内容
while (elt.firstChild) //移动所有的节点
frag.appendChild(elt.firstChild); //从elt到frag
return frag; //然后返回frag
}
var Insert = {
before: function (elt, html) {
elt.parentNode.insertBefore(fragment(html), elt);
},
after: function (elt, html) {
elt.parentNode.insertBefore(fragment(html), elt.nextSibling);
},
atStart: function (elt, html) {
elt.insertBefore(fragment(html), elt.firstChild);
},
atEnd: function (elt, html) {
elt.appendChild(fragment(html));
}
}; //基于以上函数实现insertAdjacentHTML
Element.prototype.insertAdjacentHTML = function (pos, html) {
switch (pos.toLowerCase()) {
case "beforebegin":
return Insert.before(this, html);
case "afterend":
return Insert.after(this, html);
case "afterbegin":
return Insert.atStart(this, html);
case "beforeend":
return Insert.atEnd(this, html);
}
};
return Insert; //最后返回4个插入函数
}());
```

**[⬆ back to top](#readme)**
## 拖拽
```js
/**
*Drag.js:拖动绝对定位的HTML元素
*
*这个模块定义了一个drag()函数,它用于mousedown事件处理程序的调用
*随后的mousemove事件将移动指定元素,mouseup事件将终止拖动
*这些实现能同标准和IE两种事件模型一起工作
*
*参数:
*
*elementToDrag:接收mousedown事件的元素或某些包含元素
*它必须是定位的元素,元素的样式必须是行内样式
*它的style.left和style.top值将随着用户的拖动而改变
*
*event:mousedown事件对象
**/
function drag(elementToDrag, event) { //初始鼠标位置,转换为文档坐标
var startX = event.clientX;
var startY = event.clientY; //在文档坐标下,待拖动元素的初始位置
//因为elementToDrag是绝对定位的,
//所以我们可以假设它的offsetParent就是文档的body元素
var origX = parseFloat(elementToDrag.style.left);
var origY = parseFloat(elementToDrag.style.top); //计算mousedown事件和元素左上角之间的距离
//我们将它另存为鼠标移动的距离
if (document.addEventListener) { //标准事件模型
//在document对象上注册捕获事件处理程序
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
} else if (document.attachEvent) { //用于IE5~8的IE事件模型
//在IE事件模型中,
//捕获事件是通过调用元素上的setCapture()捕获它们
elementToDrag.setCapture();
elementToDrag.attachEvent("onmousemove", moveHandler);
elementToDrag.attachEvent("onmouseup", upHandler); //作为mouseup事件看待鼠标捕获的丢失
elementToDrag.attachEvent("onlosecapture", upHandler);
}
//我们处理了这个事件,不让任何其他元素看到它
if (event.stopPropagation) event.stopPropagation(); //标准模型
else event.cancelBubble = true; //IE
//现在阻止任何默认操作
if (event.preventDefault) event.preventDefault(); //标准模型
else event.returnValue = false; //IE
/**
* 当元素正在被拖动时, 这就是捕获mousemove事件的处理程序
*它用于移动这个元素
**/
function moveHandler(e) {
if (!e) e = window.event; //IE事件模型
//移动这个元素到当前鼠标位置,
//通过滚动条的位置和初始单击的偏移量来调整
var targetLeft = e.clientX - startX + origX;
var targetTop = e.clientY - startY + origY;
var minLeft = 0;
var minTop = 0;
var maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - elementToDrag.offsetWidth;
var maxTop = (document.documentElement.clientHeight || document.body.clientHeight) - elementToDrag.offsetHeight;
targetLeft = targetLeft > maxLeft ? maxLeft : (targetLeft < minLeft ? minLeft : targetLeft);
targetTop = targetTop > maxTop ? maxTop : (targetTop < minTop ? minTop : targetTop);
elementToDrag.style.left = targetLeft + "px";
elementToDrag.style.top = targetTop + "px";
if (e.stopPropagation) e.stopPropagation(); //标准
else e.cancelBubble = true; //IE
}
/**
*这是捕获在拖动结束时发生的最终mouseup事件的处理程序
**/
function upHandler(e) {
if (!e) e = window.event; //IE事件模型
//注销捕获事件处理程序
if (document.removeEventListener) { //DOM事件模型
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
} else if (document.detachEvent) { //IE 5+事件模型
elementToDrag.detachEvent("onlosecapture", upHandler);
elementToDrag.detachEvent("onmouseup", upHandler);
elementToDrag.detachEvent("onmousemove", moveHandler);
elementToDrag.releaseCapture();
}
//并且不让事件进一步传播
if (e.stopPropagation) e.stopPropagation(); //标准模型
else e.cancelBubble = true; //IE
}
}
```
**[⬆ back to top](#readme)**
## 在谷歌地图上显示地理位置信息
```js
//获取当前位置然后通过Google地图显示
//如果当前浏览器不支持地理位置API,则抛出一个错误
function getmap() { //检查是否支持地理位置API
if (!navigator.geolocation) throw "Geolocation not supported"; //开始请求地理位置信息,
navigator.geolocation.getCurrentPosition(setMapURL);
function setMapURL(pos) { //从参数对象(pos)中获取位置信息
var latitude = pos.coords.latitude; //经度
var longitude = pos.coords.longitude; //纬度
var accuracy = pos.coords.accuracy; //米
var scale = 10; //比例
//构造一个URL,用于跳转到Google地图
var url = "https://www.google.com/maps/@" + latitude + "," + longitude + "," + scale + "z"; //设置一个大致的缩放级别
location = url;
}
}
```
**[⬆ back to top](#readme)**
## 使用所有地理位置特性
```js
//异步的获取我的位置,并在指定的元素中展示出来
function whereami(elt) { //将此对象作为第三个参数传递给getCurrentPosition()方法
var options = { //设置为true,表示如果可以的话
//获取高精度的位置信息(例如,通过GPS获取)
//但是,要注意的是,这会影响电池寿命
enableHighAccuracy: false, //可以近似:这是默认值
//如果获取缓存过的位置信息就足够的话,可以设置此属性
//默认值为0,表示强制检查新的位置信息
maximumAge: 300000, //5分钟左后
//愿意等待多长时间来获取位置信息?
//默认值为无限长 [2] ,getCurrentPosition()方法永不超时
timeout: 15000 //不要超过15秒
};
if (navigator.geolocation) //如果支持的话,就获取位置信息
navigator.geolocation.getCurrentPosition(success, error, options);
else
elt.innerHTMl = "Geolocation not supported in this browser"; //当获取位置信息失败的时候,会调用此函数

function error(e) { //error对象包含一些数字编码和文本消息,如下所示:
//1:用户不允许分享他/她的位置信息
//2:浏览器无法确定位置
//3:发生超时
elt.innerHTML = "Geolocation error" + e.code + ":" + e.message;
}
//当获取位置信息成功的时候,会调用此函数
function success(pos) { //总是可以获取如下这些字段
//但是要注意的是时间戳信息在outer对象中,而不在inner、coords对象中
var msg = "时间是" +
new Date(pos.timestamp).toLocaleString() + "地理位置是" +
pos.coords.accuracy + "米范围内经度是" +
pos.coords.latitude + "纬度是" +
pos.coords.longitude + "."; //如果设备还返回了海拔信息,则将其添加进去
if (pos.coords.altitude) {
msg += "海拔是" + pos.coords.altitude + "±" +
pos.coords.altitudeAccuracy + "千米.";
}
//如果设备还返回了速度和航向信息,也将它们添加进去
if (pos.coords.speed) {
msg += "速度是" +
pos.coords.speed + "m/s方向是" +
pos.coords.heading + ".";
}
elt.innerHTML = msg; //显示所有的位置信息
}
}
```
**[⬆ back to top](#readme)**
## 优雅的图片翻转实现
```js
/**
*优雅的图片翻转实现方式
*
*要创建图片翻转效果,将此模块引入到HTML文件中
*然后在任意<img>元素上使用data-rollover属性来指定翻转图片的URL即可
*如下所示:
*
*
*
*/
function changeImage() { //所有处理逻辑都在一个匿名函数中:不定义任何符号
//遍历所有的图片,查找data-rollover属性
for (var i = 0; i < document.images.length; i++) {
var img = document.images[i];
var rollover = img.getAttribute("data-rollover");
if (!rollover) continue; //跳过没有data-rollover属性的图片
//确保将翻转的图片缓存起来
(new Image()).src = rollover; //定义一个属性来标识默认的图片URL
img.setAttribute("data-rollout", img.src); //注册事件处理函数来创建翻转效果
img.onmouseover = function () {
this.src = this.getAttribute("data-rollover");
};
img.onmouseout = function () {
this.src = this.getAttribute("data-rollout");
};
}
}
```
**[⬆ back to top](#readme)**
## 使用canvas绘制多边形
```js
//定义一个以(x,y)为中心,半径为r的规则n边形,c可以通过调用画布getContext()方法得到
//每个顶点都是均匀分布在圆周上
//将第一个顶点放置在最上面,或者指定一定角度
//除非最后一个参数是true,否则顺时针旋转
function polygon(c, n, x, y, r, angle, counterclockwise) {
angle = angle || 0;
counterclockwise = counterclockwise || false;
c.moveTo(x + r * Math.sin(angle), //从第一个顶点开始一条新的子路径
y - r * Math.cos(angle)); //使用三角法计算位置
var delta = 2 * Math.PI / n; //两个顶点之间的夹角
for (var i = 1; i < n; i++) { //循环剩余的每个顶点
angle += counterclockwise ? -delta : delta; //调整角度
c.lineTo(x + r * Math.sin(angle), //以下个顶点为端点添加线段
y - r * Math.cos(angle));
}
c.closePath(); //将最后一个顶点和起点连接起来
}
```
**[⬆ back to top](#readme)**
## 使用canvas绘制雪花
```js
var deg = Math.PI / 180; //用于角度制到弧度制的转换
//在画布的上下文c中,以左下角的点(x,y)和边长len,绘制一个n级别的科赫雪花分形
function snowflake(c, n, x, y, len) {
c.save(); //保存当前变换
c.translate(x, y); //变换原点为起始点
c.moveTo(0, 0); //从新的原点开始一条新的子路径
leg(n); //绘制雪花的第一条边
c.rotate(-120 * deg); //现在沿着逆时针方向旋转120 o
leg(n); //绘制第二条边
c.rotate(-120 * deg); //再次旋转
leg(n); //画最后一条边
c.closePath(); //闭合子路径
c.restore(); //恢复初始的变换
//绘制n级别的科赫雪花的一条边
//此函数在画完一条边的时候就离开当前点,
//然后通过坐标系变换将当前点又转换成(0,0,)
//这意味着画完一条边之后可以很简单地调用rotate()进行旋转
function leg(n) {
c.save(); //保存当前坐标系变换
if (n == 0) { //不需要递归的情况下:
c.lineTo(len, 0); //就绘制一条水平线段
} else { //递归情况下:绘制4条子边,类似这个样子: - \/ -
c.scale(1 / 3, 1 / 3); //子边长度为原边长的1/3
leg(n - 1); //递归第一条子边
c.rotate(60 * deg); //顺时针旋转60 o
leg(n - 1); //第二条子边
c.rotate(-120 * deg); //逆时针旋转120 o
leg(n - 1); //第三条子边
c.rotate(60 * deg); //通过旋转回到初始状态
leg(n - 1); //最后一条边
}
c.restore(); //恢复坐标系变换
c.translate(len, 0); //但是通过转换使得边的结束点为(0,0)
}
}
```
**[⬆ back to top](#readme)**
## 在Web Worker中发起同步XMLHtttpRequest
```js
//此文件会通过一个新的Worker()来载入,因此,它是运行在独立的线程中的,
//可以放心地使用同步XMLHttpRequest API
//消息是URL数组的形式。以字符串形式同步获取每个URL指定的内容,
//并将这些字符串数组传递回去。
onmessage = function (e) {
var urls = e.data; //输入:要获取的URL
var contents = []; //输出:URL指定的内容
for (var i = 0; i < urls.length; i++) {
var url = urls[i]; //每个URL
var xhr = new XMLHttpRequest(); //开始一个HTTP请求
xhr.open("GET", url, false); //false则表示进行同步请求
xhr.send(); //阻塞住,一直到响应完成
if (xhr.status !== 200) //如果请求失败则抛出错误
throw Error(xhr.status + " " + xhr.statusText + ": " + url);
contents.push(xhr.responseText); //否则,存储通过URL获取得到的内容
}
//最后,将这些URL内容以数组的形式传递回主线程
postMessage(contents);
}
```
**[⬆ back to top](#readme)**
## 统计字符串中每个字母的出现次数
```js
function statistics(str) {
str = str || ""; //处理在不传递参数的情况下不报错
var obj = {};
for (var i = 0; i < str.length; i++) {
var element = str[i];
obj[element] = !obj[element] ? 1 : obj[element] + 1;
}
return obj;
}
```
**[⬆ back to top](#readme)**
## 拷贝数组
```js
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
}
```
**[⬆ back to top](#readme)**
## 给HTML元素增加样式类名
```js
function hasClass(ele, cls) {
let reg = new RegExp("(^|\\s)" + cls + "(\\s|$)");
return reg.test(ele.className);
}

function addClass(ele, cls) {
if (!hasClass(ele, cls)) {
console.log(2)
let newCls = ele.className.split(" ");
newCls.push(cls);
ele.className = newCls.join(" ");
}
}
```
**[⬆ back to top](#readme)**
## 写一个范围函数
```js
function* range(start, end) {
yield start;
if (start === end) return;
yield* range(start + 1, end);
}

console.log([...range(2,6)]) //[ 2, 3, 4, 5, 6 ]
```
**[⬆ back to top](#readme)**
## 写一个eval函数
```js
function DOMEval(code, doc) {
doc = doc || document;
var script = doc.createElement("script");
script.text = code;
doc.head.appendChild(script).parentNode.removeChild(script);
}
```
**[⬆ back to top](#readme)**
## 判断空对象的函数
```js
function isEmptyObject(obj) {
var name;
for (name in obj) {
return false;
}
return true;
}
```
**[⬆ back to top](#readme)**
## 随机抽样调查
```js
let ary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

let newAry = [];

for (let i = 0; i < 5; i++) {
let num = Math.round(Math.random() * 9);
let value = ary[num];
newAry.push(value)

ary[num] = ary[ary.length - 1];
ary.length--;
}

console.log(newAry);
```
**[⬆ back to top](#readme)**
## 求数组中的最大数
```js
let ary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

Math.max.apply(null, ary);
Math.max(...ary);

function max(ary) {
let max = ary[0];
for (const item of ary) {
max = max > item ? max : item;
}
return max;
}
```
**[⬆ back to top](#readme)**
## 字符串的repeat的方法模仿
```js
var repeat = function (str, n) {
var res = '';
while (n) {
if (n % 2 === 1) {
res += str;
}
if (n > 1) {
str += str;
}
n >>= 1;
}
return res
};

console.log(repeat("*", 6));
```
### 数组中concat模仿
```js
function concat( first, second ) {
var len = +second.length,
j = 0,
i = first.length;

for ( ; j < len; j++ ) {
first[ i++ ] = second[ j ];
}

first.length = i;

return first;
}

let res = concat([1,2,3], [1,2,3])
```

### 实现sleep函数
```js
function sleep (ms) {
let start = Date.now();
let expire = start + ms;
while (Date.now() < expire) {}
console.log(1)
}

sleep(500)
```
### 实现所有对象的深度克隆
```js
function deepClone (obj, hash = new WeakMap()) {
if (obj == null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj);
let cloneObj = new obj.constructor;
hash.set(obj, cloneObj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = obj[key];
}
}
return cloneObj;
}
```
### 实现node的events模块
```js
function EventEmitter() {
EventEmitter.init.call(this);
}

EventEmitter.init = function () {
if (this._events === undefined) {
this._events = Object.create(null);
this._eventsCount = 0;
}
}

EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener)
}

function _addListener(target, type, listener) {
var events;
var existing;
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
existing = events[type]
}
if (existing === undefined) {
events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
existing = events[type] = [existing, listener]
} else {
existing.push(listener)
}
}
return target
}

EventEmitter.prototype.on = EventEmitter.prototype.addListener

EventEmitter.prototype.emit = function emit(type, ...args) {
const events = this._events;
const handler = events[type];
if (handler === undefined) {
return false
}
if (typeof handler === 'function') {
Reflect.apply(handler, this, args)
} else {
let len = handler.length;
const listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i) {
Reflect.apply(listeners[i], this, args)
}
}
}

function arrayClone(arr, n) {
var copy = new Array(n);
for (var i = 0; i < n; ++i) {
copy[i] = arr[i];
}
return copy;
}
```
### 求两数之和
```js
// 问题描述:给定一个数组,数组里面有两个数,他们的和已知是target,求这两个数在数组中的位置
function solution(nums, target) {
for (let i = 0; i < nums.length; i++) {
let a = nums[i]
for (let j = i + 1; j < nums.length; j++) {
let b = nums[j]
if (b === target - a) {
console.log(i, j)
}
}
}
}
```
### 二叉树翻转
```js
// 问题描述:根据二叉树的数据结构,需要将二叉树各节点左右翻转
function reverse(node) {
if (node != null) {
let temp = node.left;
node.left = node.right;
node.right = temp;
reverse(node.left);
reverse(node.right);
}
}
```
### 二分查找法模板
```js
function binary_search(left, right) {
while (left < right) {
// 选择左中位数
let mid = (left + right) >> 1
if (check(mid)) {
// 先写可以排除中位数的逻辑
left = mid + 1
} else {
// 右边不能排除
right = mid
}
}
// 退出循环的时候,视情况,是否需要单独判断left(或者right)
return left
}
```
### 将对象转换为树结构
```js
const data = [
{ id: 56, parentId: 62 },
{ id: 81, parentId: 80 },
{ id: 74, parentId: null },
{ id: 76, parentId: 80 },
{ id: 63, parentId: 62 },
{ id: 80, parentId: 86 },
{ id: 87, parentId: 86 },
{ id: 62, parentId: 74 },
{ id: 86, parentId: 74 },
];
let tree = {
id: 74,
parentId: null,
children: [
{
id: 62,
parentId: 74,
children: [{ id: 56, parentId: 62 }, { id: 63, parentId: 62 }],
},
{
id: 86,
parentId: 74,
children: [
{
id: 80,
parentId: 86,
children: [{ id: 81, parentId: 80 }, { id: 76, parentId: 80 }],
},
{ id: 87, parentId: 86 },
],
},
],
};
// 无需递归即可在O(n)时间内完成
function createTree (data) {
let idMap = data.reduce((prev, cur, index) => {
prev[cur.id] = index
return prev
}, {})
let root;
data.forEach(item => {
if (item.parentId === null) {
return root = item
}
let parentEl = data[idMap[item.parentId]]
parentEl.children = [...(parentEl.children || []), item]
})
return root
}
```