web小结

2020-10-14  本文已影响0人  来了啊小老弟

DOM操作部分

DOM的数据结构是一种树

attribute和property的区别

节点的property

const pList document.querySelectorAll('p')
const p = pList[0]
console.log(p.style.width) //获取样式
p.style.width = '100px' //修改样式
console.log(p.className) //获取class
p.className = 'p1' //修改class

节点的attribute

const pList document.querySelectorAll('p')
const p = pList[0]
p.getAttribute('data-name')
p.setAttribute('data-name','p1')
p.getAttribute('style')
p.setAttribute('style','font-size:50px;')

区别

property:修改对象属性,不会体现到html结构中(推荐,不会重新渲染DOM)
attribute:修改html属性,会改变html结构。

DOM性能

1.DOM操作非常昂贵,应该避免频繁操作DOM

2.对DOM查询做缓存

3.将频繁操作改为一次性操作

//不缓存DOM查询结果
for(let i=0;i<document.getElementsByTagName('p').length;i++){}
//缓存DOM查询结果
const pList = document.getElementsByTagName('p')
const length =  pList.length
for(let i=0;i<length;i++){}

//将频繁操作改为一次性操作
const listNode = document.getrElementById('list')
//创建一个文档片段,此时还没有插入到DOM树中
const frag = document.createDocumentFragment()
//执行插入
for(let x = 0;x<10;x++){
  const li = document.createElement('li')
  li.innerHTML = 'list"+x
  frag.appendChild(li)
}
//都完成之后,再插入到DOM树中
listNode.appendChild(frag)

客户端存储

cookie localstorage 和sessionstorage

cookie

H5之前用来客户端存储数据
document.cookie = 'a:100'
缺点:1.存储大小,最大4KB.
2.http请求时需要发送到服务端,增加请求数据量
3.只能用document.cookie = ’‘来修改,太过简陋

localstorage 和sessionstorage

1.H5新增,专门为了存储而设计,最大可存5M
2.api简单易用:getItem,setItem
3.不会随着http请求发送出去。

区别

localstorage数据会永远存储,除非代码或者手动删除
sessionstorage数据只存储在当前会话,浏览器关闭则清空
一般用localstorage会更多一些

性能优化之防抖与节流

防抖debounce

监听一个input输入框的keyup,但是不能一松开键盘就触发事件,因为可能会频繁调用接口,应该松开若干毫秒后不再按下,才开始调用接口

const input1 = document.getElementById('input')
var timer = null
input1.addEventListener('keyup',function(){
  //假如输入123,首先输入1的时候,time是null,触发定时器,
  // 500毫秒之后打印,但是在500毫秒之内再次输入了2,触发keyup,此时time!=null
  // 就清空了原来应该打印1的定时器,重新执行一个新的定时器打印12,关键在于清空原来的定时器
  if(timer){   
    clearTimeout(timer)
  }
  timer = setTimeout(() => {
    console.log(input1.value)
    timer = null
  }, 500);
})
// 封装一个方法
function debounce(fn,delay = 500){
  // timer在闭包中
  let timer =null
  return function(){
    if(timer){   
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn()
      // fn.apply(this,arguments) 用这种更完美
      timer = null
    }, delay);
  }
}
input1.addEventListener('keyup',debounce(()=>{
  console.log(input1.value)
},1000))

节流throttle

拖拽一个元素时,要随时拿到该元素被拖拽的位置,直接用drag事件,则会频繁触发,很容易导致卡顿。 节流:无论拖拽速度多快,都会每隔100ms触发一次

const div1 = document.getElementById('div1')
var timer = null
div1.addEventListener('drag',function(e){
  //存在timer则说明前一次还没执行完,必须前一次执行完,才能执行下一次操作,确保规定时间只执行一次,
  // 和防抖的区别在于,防抖是清空原来执行新的,节流是执行原来的,正好相反
  if(timer){ 
    return
  }
  timer = setTimeout(() => {
    console.log(e.offsetX,e.offsetY)
    timer = null
  }, 500);
  
})

// 封装一个方法
function throttle(fn,delay = 500){
  // timer在闭包中
  let timer =null
  return function(){
    if(timer){   
      return
    }
    timer = setTimeout(() => {
      console.log(this) //this是div1,箭头函数承接上文,就是return的方法
      fn.apply(this,arguments) //只是为了绑定事件的参数,fn.apply({},arguments)也可以起到效果
      timer = null
    }, delay);
  }
}
div1.addEventListener('drag',throttle((e)=>{
  console.log(this) //this是window 箭头函数承接上文,就是window
  console.log(e.offsetX,e.offsetY)
},1000))
div1.addEventListener('drag',throttle(function(e){
  console.log(this) //this是div
  console.log(e.offsetX,e.offsetY)
},1000))

WEB安全

XSS跨站请求攻击

XSRF跨站请求伪造

1.XSS跨站请求攻击

<body>
  <div>123<div>
  <script>alert(document.cookie)</script>
</body>

往网页中恶意插入代码,获取用户信息,这样很轻松就获取到了用户的cookie信息,这是很不安全的。

预防

替换特殊字符,如< 变为< >变成>
<script>变为<script>直接显示,不会作为脚本执行
也可以用xss插件 Npm install xss

2.XSRF跨站请求伪造


微信截图_20201014173257.png 微信截图_20201014173325.png
微信截图_20201014173517.png

箭头函数

1.语法编写简洁,但是可读性不是很好。
2.没有自己的this,继承上级的this。
3.没有arguments
4.没有prototype,也就没有Constructor,也就是不能被new.

Flex布局

一、基本概念

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。


微信截图_20201015151059.png 微信截图_20201015151132.png 微信截图_20201015161833.png

1C:对象以数字123做健名时,会覆盖原来的字符串'123'的健名
2B:symbol是唯一属性
3C:以对象为属性时,会转为字符串'[object,object]',多个对象健名重复,取最后一个。

判断输入的是一个正确的URL

let str = 'https://www.sdafsdfdsf.cn/index.html?name=admin&age=22#video'
let reg = /(^(http|https|ftp):\/\/)?(([\w-]+\.)+[a-z0-9]+)((\/[^/?#]*)+)?(\?[^#]+)?(#.+)?$/i
console.log(reg.exec(str))
console.log(reg.test(str))

正向预查和负向预查

正向预查: ?= 表示一定要匹配, ?=[0-9] 必须匹配数字
负向预查: ?! 表示不能匹配, ?![0-9] 后面不能是数字

正则验证6-16位必须包含大写小写数字的字符串

let reg = /(?!^[a-zA-Z]+$)(?!^[0-9]+$)(?!^[a-z0-9]+$)(?!^[A-Z0-9]+$)(^[a-zA-Z0-9]{6,16}$)/

小括号代表一个组,一个小括号返回一个正则的结果true或者false.


微信截图_20201015172125.png 微信截图_20201016103821.png

答案:


微信截图_20201016104121.png

let obj = new Foo()时,调用了Foo(),当成普通函数执行,就改写了里面的Foo.a的指向,所以最后一个输出是1,new操作之后this就是obj,所以obj.a()输出2,私有属性有a(),就不去共有属性prototype上找了。

手写一个new 函数

function Dog(name){
  this.name = name
}
Dog.prototype.bark = function(){
  console.log('wangwang'+this.name)
}
function _new(fn, ...arg){
  // let obj ={}
  // obj.__proto__ = fn.prototype
  let obj = Object.create(fn.prototype) 
  // 上面两句等于Object.create(fn.prototype) 
  //Object.create(a对象) 等于创建一个空对象,并且让空对象作为a对象所属构造函数的实例,即obj.__proto__ =a对象
  fn.call(obj,...arg)
  return obj
}
var newDog = _new(Dog,'tom')
newDog.bark()

数据类型转换题

a=?的情况下
满足if(a==1&&a==2&&a==3){}

a= {
  n:0,
  toString:function(){
    ++this.n
  }
}

非常巧妙,因为当比较的两边数据类型不一样时,都是先转化为数字,对象转换为数字之前,先调用toString()方法转换成字符串,再转换为数字。所以重写它的toString()方法,覆盖原型链上的toString(),连续调用就可以实现以上效果。
再介绍两种方式:

//1
let a= [1,2,3]
a.toString = a.shift
//2
Object.defineProperty(window,'a',{
  get:function(){
    this.value?this.value++:this.value = 1
    return this.value
  }
})

各位应该能看懂。

再出一题

微信截图_20201016164545.png

接下来三大经典算法

冒泡排序

 // 冒泡排序:当前项和后一项比较,如果当前项比后一项大,则让大的靠后
let arr =[12,8,24,16,1,88,66,34,67,99,1]
 function getArr(arr){
  let count = arr.length
  for(let i = 0;i<count-1;i++){
    for(let j = 0;j<count-i-1;j++){
      if(arr[j]>arr[j+1]){
        [arr[j],arr[j+1]] = [arr[j+1],arr[j]]
      }
    }
  }
  return arr
 }
 getArr(arr)

插入排序

//插入排序:打扑克牌,抓一张牌,插到手里,进行排序的过程。
function insert(arr){
  let count = arr.length
  let newArr = [arr[0]] // 存储第一张牌
  for(let i = 1;i<count;i++){ //依次抓牌 i从1开始,因为0已经存进去了
    let A = arr[i] //新抓的牌
     for(let j= newArr.length-1;j>=0;j--){
       let B = newArr[j] //每一次比较手里的牌
       if(A>B){
        newArr.push(A)
        // newArr.splice(j+1,0,A) //如果当前新牌比手里要比较的牌大,就插在后面
        break
       }
       if(j===0){
        newArr.unshift(A) //比到第一张了,就插在第一张
       }
     }
  }
  console.log(newArr)
  return newArr
}
insert(arr)

快速排序

let arr =[12,8,24,16,1,88,66,34,67,99,1]
 //快速排序,找到中间项,把他从原来的数组中移除,获取这一项的结果
 function quick(arg){
   //4.结束递归(ary种小于等于一项)
  if(arg.length<=1){
    return arg
  }
  //1.找到数组的中间项,在原有数据中删除
  let middleIndex =  Math.floor(arg.length/2)
  let middleValue =  arg.splice(middleIndex,1)[0]
  //2.准备左右两个数组,循环剩下数组中的每一项,小的放左大的方右
  let arrleft=[],arrRight = [];
  for(let i=0;i<arg.length;i++){
    if(arg[i]<middleValue){
      arrleft.push(arg[i])
    } else {
      arrRight.push(arg[i])
    }
  }
  //3 递归操作
  return quick(arrleft).concat(middleValue,quick(arrRight))

 }
 let a = quick(arr)
 console.log(a)

计算斐波那契

1。普通递归:代码优美逻辑清晰。但是有重复计算的问题,如:当n为5的时候要计算fibonacci(4) + fibonacci(3),当n为4的要计算fibonacci(3) + fibonacci(2) ,这时fibonacci(3)就是重复计算了。运行 fibonacci(50) 会出现浏览器假死现象,毕竟递归需要堆栈,数字过大内存不够。

function fibonacci(n) {
    if (n == 1 || n == 2) {
        return 1
    };
    return fibonacci(n - 2) + fibonacci(n - 1);
}
fibonacci(30)

2.方法二:改进递归-把前两位数字做成参数避免重复计算

function fibonacci(n) {
    function fib(n, v1, v2) {
        if (n == 1)
            return v1;
        if (n == 2)
            return v2;
        else
            return fib(n - 1, v2, v1 + v2)
    }
    return fib(n, 1, 1)
}
fibonacci(30)

3.普通for循环

function fibonacci(n) {
    var n1 = 1, n2 = 1, sum;
    for (let i = 2; i < n; i++) {
        sum = n1 + n2
        n1 = n2
        n2 = sum
    }
    return sum
}
fibonacci(30)

4.for循环+解构赋值

var fibonacci = function (n) {
    let n1 = 1; n2 = 1;
    for (let i = 2; i < n; i++) {
        [n1, n2] = [n2, n1 + n2]
    }
    return n2
}
fibonacci(30)

正向代理和反向代理

QQ截图20201023162443.png
上一篇下一篇

猜你喜欢

热点阅读