去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//第一种方法  
Array.prototype.unique = function(){ //在原型上加方法
var res = [];
var json = {};
for(var i = 0; i < this.length; i++){
if(!json[this[i]]){ //是否存在
res.push(this[i]);
json[this[i]] = 1; //保存了
}
}
return res;
}
var arr = [112,112,34,'你好',112,112,34,'你好','str','str1'];

console.log(arr.unique()) //[112, 34, "你好", "str", "str1"]

//2.
//判断是否第一个index,返回第一出现的值
let uniqueArr=arr.filter((item,index,arr)=>arr.indexOf(item)==index)
console.log(uniqueArr) //[112, 34, "你好", "str", "str1"]


//3.es6 Set方法
let a =[...new Set(arr)]
console.log(a) //[112, 34, "你好", "str", "str1"]

防抖与节流

JS的防抖与节流

防抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null) {
clearTimeout(timeout)
}
timeout = setTimeout(fn, wait)
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));

节流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//节流
var throttle = function(func, delay) {
var timer = null;
var startTime = Date.now();
return function() {
var curTime = Date.now();
var remaining = delay - (curTime - startTime);
var context = this;
var args = arguments;
clearTimeout(timer);
if (remaining <= 0) {
func.apply(context, args);
startTime = Date.now();
} else { // 超1s多出时间执行
timer = setTimeout(func, remaining);
}
}
}
function handle() {
console.log(Math.random());
}
//当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数
window.addEventListener('scroll', throttle(handle, 3000));

多级数组变一级(扁平)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    var arr=[1,2,3,4,['a',55,[111,{"name":'bbb'}]]]
var empty=[]
function flat(arr){
arr.forEach(item=>{
if (typeof item==='string' || typeof item==='number'){
empty.push(item)
}else if(Array.isArray(item)){
//判断数组 1.typeof item ==='object' &&item instanceof Array
// 2. Object.prototype.toString.call(item)==='[object Array]'
flat(item)
}else{
empty.push(item)
}
})

return empty
}

console.log(flat(arr)) // [1, 2, 3, 4, "a", 55, 111, {"name":'bbb'}]

千分符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
var str="3562123761";//[3,562,123,761]

function test(str){
var iNum=str.length%3;

var prev="";
var arr=[];
var iNow=0;
var tmp='';

if(iNum !=0){ //不是三的整除,先放在数组
prev =str.substring(0,iNum);
arr.push(prev)
}
str =str.substring(iNum);

for (var i=0;i<str.length;i++){
iNow++;
tmp+=str[i];

if(iNow==3&&tmp){
arr.push(tmp) //三个数字一组
tmp='';
iNow=0;
}
}
//console.log(arr)
return arr.join(',');
}

console.log(test(str));

//正则
//(?=)前项声明
//(?!)反前向声明
//例子
var str1='abacad';
var re=/a(?=b)/g
str1=str1.replace(re,"*");
console.log(str1);//*bacad

var re2=/a(?!b)/g
var str2=str1.replace(re2,"*")
console.log(str2);//*b*c*d

function test2(str){
var re=/(?=(?!\b)(\d{3})+$)/g; //边界不能替换
return str.replace(re,',')
}

console.log(test2(str));//3,562,123,761

驼峰命名法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var str="border-bottom-color";
function test(str){
var arr=str.split("-");//[border,bottom,color]
for(var i=1;i<arr.length;i++){
arr[i]=arr[i].charAt(0).toUpperCase()+arr[i].substring(1);
}
return arr.join('')
}
console.log(test(str));//borderBottomColor

//2.正则
function test2(str){
var re=/-(\w)/g;
return str.replace(re,function($0,$1){ //-b b
return $1.toUpperCase()
})
}

console.log(test2(str));//borderBottomColor

排序

Javascript常见排序算法的笔记

从小到大排序

冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var arr = [15, 55, 99, 77, 8, 0, 2]
let time = 0;

function bubbleSort(arr) {
var len = arr.length
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - 1 - i; j++) {
time++
if (arr[j] > arr[j + 1]) {
var temp
temp = arr[j];
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
}

console.log(time) //21
console.log(bubbleSort(arr)) //[0, 2, 8, 15, 55, 77, 99]

二分法排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const Arr = [85, 24, 63, 45, 17, 31, 96, 50];

function quickSort(arr) {
if (arr.length <= 1) {
return arr;
}
let pivotIndex = Math.floor(arr.length / 2);
let pivot = arr.splice(pivotIndex, 1)[0];
let left = [];
let right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
// 递归
return quickSort(left).concat([pivot], quickSort(right));
}
console.log(quickSort(Arr));//[17, 24, 31, 45, 50, 63, 85, 96]

添加class

1
2
3
4
5
6
7
8
9
10
function addClass(el, className) { //加class
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)') //"className" 或者 “ className ”
if (reg.test(el.className)) { //判断是否有class
return
}
//加上class名
let newClass = el.className.split(' ') //拆分
newClass.push(className) //添加
el.className = newClass.join(' ') //字符串
}

设置data节点属性

1
2
3
4
5
6
7
function getData(el, name, val) {
const prefix = 'data-'
if (val) {
return el.setAttribute(prefix + name, val) //设置
}
return el.getAttribute(prefix + name) //获取
}

浏览器css前缀的兼容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//设置浏览器的兼容
function prefixStyle(style) {
let elementStyle = document.createElement('div').style
//供应商
let vendor = (() => {
let transformNames = {
webkit: 'webkitTransform',
Moz: 'MozTransform',
O: 'OTransform',
ms: 'msTransform',
standard: 'transform'
}
for (let key in transformNames) {
if (elementStyle[transformNames[key]] !== undefined) {
return key //返回前缀
}
}
return false
})()

if (vendor === false) {
return false
}

if (vendor === 'standard') { //标准,没有前缀
return style
}

return vendor + style.charAt(0).toUpperCase() + style.substr(1) //驼峰命名
}

//测试
alert(prefixStyle('transform'))// webkitTransform (谷歌浏览器 webkit内核)

获取DOM大小和位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getRect(el) {
if (el instanceof window.SVGElement) {
let rect = el.getBoundingClientRect()
return {
top: rect.top,
left: rect.left,
width: rect.width,
height: rect.height
}
} else {
return {
top: el.offsetTop,
left: el.offsetLeft,
width: el.offsetWidth,
height: el.offsetHeight
}
}
}

对象

hasOwnProperty

对象本身的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//构造函数
function Foo(name){
this.name=name
}
Foo.prototype.alertName=function(){
alert(this.name)
}
// 创建示例
var f = new Foo('小明')
f.printName=function(){
console.log(this.name) //小明
}
//测试
f.printName()
f.alertName()
f.toString() //要去f.__proto__.__proto__中查找
var item
for(item in f){
//高级浏览器已经在 for in 中 屏蔽了来自原型的属性
//但是这里还是建议大家还是加上这个判断,保证程序的健壮性
if(f.hasOwnProperty(item)){
console.log(item) // name printName
}
}

原型链

原型链

instanceof
用于判断引用类型属于哪个构造函数的方法

  • f instanceof 的判断逻辑是:
  1. f的__proto__一层一层往上,能否找打对应到Foo.prototype
  2. 再试判断f instanceof Object

instanceof

变量 属于 数组

1
2
3
var arr=[]
arr instanceof Array //true
typeof arr //object, typeof 是无法判断是否是数组的

例子

DOM操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) { //设置/获取innerHTML
var elem = this.elem
if (val) {
elem.innerHTML = val
return this //链式操作
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function(type,fn) { //绑定事件
var elem=this.elem
elem.addEventListener(type,fn)
return this
}
let div1 = new Elem('div1') //获取设置id类

//console.log(div1.html()) //innerHTML
div1.html("<p>hello world</p>").on('click',function(){
alert('clicked')
})

深层拷贝

1
2
3
4
5
6
7
function deepClone(obj){
var newObj=obj instanceof Array ? []:{}
for(var key in obj){
newObj[key]= typeof obj[key]==='object'? deepClone(obj[key]):obj[key]
}
return newObj
}

日期

Date.now() //获取当前毫秒数1531824326654
new Date().getTime()//获取毫秒数

1
2
3
4
5
6
7
8
9
10
11
function getTime(){
var dt=new Date() //中国标准时间
var year=dt.getFullYear() //年
var month=dt.getMonth()+1 //月(0-11)
var date=dt.getDate() //日(0-31)
var hour=dt.getHours() //时(0-23)
var minute=dt.getMinutes() //分 (0-59)
var second=dt.getSeconds() //秒 (0-59)
return year+'-'+month+'-'+date+' '+hour+':'+minute+':'+second
}
getTime() //2018-6-17 18:58:22

递归

阶乘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//书P70 可以被es6引擎优化
//阶乘
function factorial(n,p=1){
if(n<=1){
return 1*p
}else{
let result =n*p

//优化后
return factorial(n-1,result)
}
}

factorial(3)//6

##菲波那契

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//菲波那契 
//1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144
function fibo(n) {
if (n >= 2) {
return fibo(n - 1) + fibo(n - 2)
} else {
return n;
}
}

fibo(3) //2


//最优解
// 菲波那契可能是最普通的解法
var series = function (n) {
var sum = [0, 1];
if(n < 2) {
return sum[n];
}

var firstNum = 0;
var secondNum = 1;
var total = 0;
for (var i = 2; i<= n; i++) {
total = firstNum + secondNum;
firstNum = secondNum;
secondNum = total;
}
return total;
}

浏览器内置对象

navigator.userAgent 浏览器代理器名称

location

例子
location.href=’跳转的地址’
https://www.baidu.com/index.html?id=99&a=b#mid=100

location
location.protocolhttps:
location.pathname/index.html
location.search?id=99&a=b
location.hash#mid=100

事件

event. stopPropagatio()是阻止冒泡事件的方法,
在ie浏览器上没有stopPropagatio()这个方法,
在ie上要用e.cancelBubble=true阻止冒泡事件

1
2
3
4
5
6
7
8
9
function stopPropagation(event){
var e=window.event||event;
if(document.all){
e.cancelBubble=true;
}else{
e.stopPropagation();//阻止冒泡
e.preventDefault()// 取消默认行为
};
}

事件委托代理

1
2
3
4
5
6
7
8
9
10
<div id="div1"><a href="">这是a标签</a></div>
<script>
let div1=document.getElementById('div1')
div1.addEventListener('click',function(e){
let target=e.target
if(target.nodeName==='A'){
alert(target.innerHTML)
}
})
</script>

完善封装代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function bindEvent(elem,type,selector,fn){
if(fn==null){ //3个参数
fn=selector
selector=null
}
elem.addEventListener(type,function(e){
var target
if(selector){ //四个参数(代理)
target=e.target
console.log(target)
if (target.matches(selector)){
fn.call(target,e)
}
}else{ //没有代理
fn(e)
}
})
}

//使用代理
var div1=document.getElementById('div1')
bindEvent(div1,'click','a',function(e){
console.log(this.innerHTML)
})
//不使用代理
// var a=document.getElementById('a1')
// bindEvent(div1,'click',function(e){
// console.log(a.innerHTML)
// })

ajax

1
2
3
4
5
6
7
8
9
10
11
12
var xhr =new XMLHttpRequest()
xhr.open('GET','/api',false)
xhr.onreadystatechange=function(){
//这里的函数异步执行
if(xhr.readyState=4){ //ajax状态码
if(xhr.status==200){ //http请求状态码
alert(xhr.responseText)
}
}
}

xhr.send(null)

AMD

异步模块定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//1.util.js
define(function(){
var util={
getFormatData:function(date,type){
if(type===1){
return '2018-06-20'
}if(type===2){
return '2018年6月20日'
}
}
}
return util
})
//2.a-util.js
define(['./util.js'],function(util){
var aUtil={
aGetFormatDate:function(date){
return util.getFormatData(date,2)
}
}
return aUtil
})
//3.a.js
define(['./a-util.js'],function(util){
var a={
printDate:function(date){
console.log(util.aGetFormatDate(date))
}
}
return a
})
//4.main.js
require(['./a.js'],function(a){
var date=new Date()
a.printDate(date) //2018年6月20日
})

使用 data-main

1
<script src="https://cdn.bootcss.com/require.js/2.3.4/require.min.js" data-main='./main.js'></script>

运动

运动的tool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
function getStyle(ele, attr) //获取样式
{
if(ele.currentStyle)
{
return ele.currentStyle[attr];
}
else
{
return getComputedStyle(ele, false)[attr];
}
}

function startMove(ele, obj, fn)
{
clearInterval(ele.timer);
ele.timer=setInterval(function (){
var bStop=true; //这一次运动就结束了――所有的值都到达了
for(var attr in obj)
{
//1.取当前的值
var iCur=0;

if(attr=='opacity')
{
iCur=parseInt(parseFloat(getStyle(ele, attr))*100);
}
else
{
iCur=parseInt(getStyle(ele, attr));
}

//2.算速度
var iSpeed=(obj[attr]-iCur)/8;
iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);

//3.检测停止
if(iCur!=obj[attr])
{
bStop=false;
}

if(attr=='opacity')
{
ele.style.filter='alpha(opacity:'+(iCur+iSpeed)+')';
ele.style.opacity=(iCur+iSpeed)/100;
}
else
{
ele.style[attr]=iCur+iSpeed+'px';
}
}

if(bStop)
{
clearInterval(ele.timer);

if(fn)
{
fn();
}
}
}, 30)
}


//例子
// let div1=document.getElementById('div1')
// startMove(div1,{height:300},function(){ //高度变化300px
// cosnole.log('运动完成')
// })

vue 中ajax

直接返回data数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const axios = require('axios')

module.exports = function ajax(url = '', data = {}, type = 'GET') {
return new Promise(function (resolve, reject) {

let promise

if (type === 'GET') {
// 准备url query参数数据
let dataStr = '' //数据拼接字符串
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&'
})
if (dataStr !== '') {
dataStr = dataStr.substr(0, dataStr.lastIndexOf('&'))
url = url + '?' + dataStr
}
// 发送get请求
promise = axios.get(url)
} else {
// 发送post请求
promise = axios.post(url, data)
}

promise.then(response => {
resolve(response.data)
})
.catch(error => {
reject(error)
})
})
}