js手写题

197 阅读2分钟

1 实现一个事件委托函数

  <ul id="myul">
    <li>这是第一个li</li>
    <li>这是第二个li</li>
  </ul>
var $ul = document.getElementById("myul");
    $ul.addEventListener('click', function (e) {
      if (e.target.tagName.toLowerCase() === "li") {
        console.log("dayin")
      }
    }, false)

2 实现一个可以拖拽的DIV

实现拖动图片到矩形框中
 #div1 {
      width: 350px;
      height: 70px;
      padding: 10px;
      border: 1px solid #aaaaaa;
    }
    
  <p>拖动 RUNOOB.COM 图片到矩形框中:</p>
  <div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
  <br>
  <img id="drag1" src="/images/logo.png" draggable="true" ondragstart="drag(event)" width="336" height="69">
    function allowDrop(ev) {
      ev.preventDefault();
    }

    function drag(ev) {
      ev.dataTransfer.setData("Text", ev.target.id);
    }

    function drop(ev) {
      ev.preventDefault();
      var data = ev.dataTransfer.getData("Text");
      ev.target.appendChild(document.getElementById(data));
    }
实现一个可以拖动的div
var dragging = false
var position = null

xxx.addEventListener('mousedown',function(e){
  dragging = true
  position = [e.clientX, e.clientY]
})

document.addEventListener('mousemove', function(e){
  if(dragging === false) return null
  const x = e.clientX
  const y = e.clientY
  const deltaX = x - position[0]
  const deltaY = y - position[1]
  const left = parseInt(xxx.style.left || 0)
  const top = parseInt(xxx.style.top || 0)
  xxx.style.left = left + deltaX + 'px'
  xxx.style.top = top + deltaY + 'px'
  position = [x, y]
})
document.addEventListener('mouseup', function(e){
  dragging = false
})

3 函数节流和函数防抖

函数防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

场景:

  • 浏览器窗口大小resize避免次数过于频繁
  • 登录,发短信等按钮避免发送多次请求
  • 文本编辑器实时保存
function debounce(func, delay) {
    var timeout;
    return function(e) {
        console.log("清除",timeout,e.target.value)
        clearTimeout(timeout);
        var context = this, args = arguments
        console.log("新的",timeout, e.target.value)
        timeout = setTimeout(function(){
          console.log("----")
          func.apply(context, args);
        },delay)
    };
};

var validate = debounce(function(e) {
    console.log("change", e.target.value, new Date-0)
}, 380);

// 绑定监听
document.querySelector("input").addEventListener('input', validate);

函数节流:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

场景:

  • scroll滚动事件,每隔特定描述执行回调函数
  • input输入框,每个特定时间发送请求或是展开下拉列表,(防抖也可以)
function throttle(fn, threshhold) {
 var timeout
 var start = new Date;
 var threshhold = threshhold || 160
 return function () {

 var context = this, args = arguments, curr = new Date() - 0
 
 clearTimeout(timeout)//总是干掉事件回调
 if(curr - start >= threshhold){ 
     console.log("now", curr, curr - start)//注意这里相减的结果,都差不多是160左右
     fn.apply(context, args) //只执行一部分方法,这些方法是在某个时间段内执行一次
     start = curr
 }else{
 //让方法在脱离事件后也能执行一次
     timeout = setTimeout(function(){
        fn.apply(context, args) 
     }, threshhold);
    }
  }
}
var mousemove = throttle(function(e) {
 console.log(e.pageX, e.pageY)
});

// 绑定监听
document.querySelector("#panel").addEventListener('mousemove', mousemove);

4 数组去重

var arr = [1, 1, 2, 3]
var arr = arr.reduce((init, cur) => init.includes(cur) ? init : [...init, cur], [])
// arr = arr.reduce((pre, cur) => pre.includes(cur) ? pre : [...pre, cur], []);
console.log(arr) 

5 手写bind()

Function.prototype.mybind = function(context,...args){
  return (...newargs)=>{
      return this.call(context,...args,...newargs)
}
}
//测试
let cc = {
      name: 'TianTian'
    }
function say(something, other) {
    console.log(`I want to tell ${this.name} ${something}`);
    console.log('This is some' + other)
    }
let tmp = say.mybind(cc, 'happy', 'you are kute')
let tmp1 = say.bind(cc, 'happy', 'you are kute')
tmp()
tmp1()