js底层原理

防抖

/*
 * debounce:实现函数的防抖(目的是频繁触发中只执行一次)
 *  @params
 *     func:需要执行的函数
 *     wait:检测防抖的间隔频率
 *     immediate:是否是立即执行(如果为TRUE是控制第一次触发的时候就执行函数,默认FALSE是以最后一次触发为准)
 *  @return
 *     可被调用执行的函数
 */
function debounce(func, wait = 100, immediate = false) {
    let timer = null;
    return function anonymous(...params) {
        let now = immediate && !timer;
        clearTimeout(timer);
        timer = setTimeout(() => {
            timer = null;
            // 执行函数:注意保持THIS和参数的完整度
            !immediate ? func.call(this, ...params) : null;
        }, wait);
        now ? func.call(this, ...params) : null;
    };
}

节流

/*
 * throttle:实现函数的节流(目的是频繁触发中缩减频率)
 *   @params
 *      func:需要执行的函数
 *      wait:自己设定的间隔时间(频率)
 *   @return
 *      可被调用执行的函数
 */
function throttle(func, wait = 100) {
    let timer = null,
        previous = 0; //记录上一次操作时间
    return function anonymous(...params) {
        let now = new Date(), //当前操作的时间
            remaining = wait - (now - previous);
        if (remaining <= 0) {
            // 两次间隔时间超过频率:把方法执行即可
            clearTimeout(timer);
            timer = null;
            previous = now;
            func.call(this, ...params);
        } else if (!timer) {
            // 两次间隔时间没有超过频率,说明还没有达到触发标准呢,设置定时器等待即可(还差多久等多久)
            timer = setTimeout(() => {
                clearTimeout(timer);
                timer = null;
                previous = new Date();
                func.call(this, ...params);
            }, remaining);
        }
    };
}

获取元素距离BODY的偏移值

/*
 * 获取元素距离BODY的偏移值 
 */
function offset(element) {
    let parent = element.offsetParent,
        top = element.offsetTop,
        left = element.offsetLeft;
    while (parent) {
        if (!/MSIE 8/.test(navigator.userAgent)) {
            left += parent.clientLeft;
            top += parent.clientTop;
        }
        left += parent.offsetLeft;
        top += parent.offsetTop;
        parent = parent.offsetParent;
    }
    return {
        top,
        left
    };
}

定时器动画
在这里插入图片描述

两套代码实现方式比较

/* setInterval
clearInterval
setTimeout
clearTimeout
弊端 
容易出现卡顿 抖动现象
定时器设定的


 */
(function () {
  let Box = document.querySelector(".box");
  console.log(
    "[ Box ]",
    Box,
    parseFloat(getComputedStyle(Box)["width"]),
    getComputedStyle(Box)["left"]
  );
  let curl = parseFloat(getComputedStyle(Box)["left"]),
    timer = null,
    minL = 0,
    maxL = document.documentElement.clientWidth - Box.offsetWidth,
    step = 10,
    direction = "right";
  function move() {
    if (direction === "right") {
      curl += step;
      if (curl >= maxL) {
        curl = maxL;
        direction = "left";
      }
    } else {
      curl -= step;
      if (curl <= minL) {
        curl = minL;
        direction = "right";
      }
    }
    Box.style.left = curl + "px";
  }
  timer = setInterval(move, 16.7);
})();

//
(function () {
  let Box = document.querySelector(".box2");
  console.log(
    "[ Box ]",
    Box,
    parseFloat(getComputedStyle(Box)["width"]),
    getComputedStyle(Box)["left"]
  );
  let curl = parseFloat(getComputedStyle(Box)["left"]),
    timer = null,
    minL = 0,
    maxL = document.documentElement.clientWidth - Box.offsetWidth,
    step = 10,
    direction = "right";
  function move() {
    if (direction === "right") {
      curl += step;
      if (curl >= maxL) {
        curl = maxL;
        direction = "left";
      }
    } else {
      curl -= step;
      if (curl <= minL) {
        curl = minL;
        direction = "right";
      }
    }
    Box.style.left = curl + "px";
    timer = requestAnimationFrame(move);
    // console.log('[ timer ]', timer)
  }
  // timer = setInterval(move, 17.6);
  timer = requestAnimationFrame(move);
  
})();

js捕获冒泡使用理解

/* 
事件的捕获和冒泡机制你了解多少
1. 基本概念

捕获:自顶向下
冒泡:自底向上

2.监听那个阶段的事件?  
window.addEventListener('click',()=>{
})
第三个参数 Beallen
默认 false 冒泡阶段  true  的捕获阶段

3.平常那些场景用到啦这个机制?

4.有一个历史页面,上面若干个按钮,每个按钮都有自己的click事件

新的需求:当你给每个访问用户都加一个属性,banned=true,此用户点击点击按钮任何元素都不能响应原来的函数,而是直接alert 提示,你被封禁啦

就是在最顶层绑定一个捕获事件,最先触发,判断用户是否有权限  弹出提示信息
window.addEventListener("click", (e) => {
    if (bananed === true) {
      e.target.stopPropagation();
    }
  })
*/
(function () {
  let ulo = document.querySelector(".ulist");
  ulo.addEventListener("click", function (e) {
    const target = e.target;
    if (target.tagName.toLowerCase() === "li") {
      console.log("[ this ]", this);
      const lilist = this.querySelectorAll("li");
      const i = Array.prototype.indexOf.call(lilist, target);
      alert(`内容为${target.innerHTML},索引为${i}`);
    }
  });
  console.log("[ ulo ]", ulo);
  /* 
  事件委托利用啦事件的冒泡
  */
})();

js发布订阅事件池

let pools = (function () {
  let pond = {};

  let on = function on(type, cb) {
    !pond.hasOwnProperty(type) ? (pond[type] = []) : null;
    let arr = pond[type];

    // 去重操作
    let index = 0;
    for (; index < arr.length; index++) {
      if (arr[index] == cb) {
        return;
      }
    }
    // 然后再添加
    arr.push(cb);
  };
  let off = function off(type, cb) {
    let arr = pond[type] || [];
    let index = 0;
    for (; index < arr.length; index++) {
      if (arr[index] == cb) {
        // 防止数组塌陷
        arr[index] = null;
        return;
      }
    }
  };
  let emit = function emit(type, ...params) {
    let arr = pond[type] || [];
    let index = 0;
    for (; index < arr.length; index++) {
      if (arr[index] == null) {
        arr.splice(index, 1);
        index--;
        continue;
      }
      arr[index](...params);
    }
  };
  return {
    on,
    emit,
    off,
  };
})();

let fn1 = (...params) => console.log("[ params 1]", params);
let fn2 = (...params) => console.log("[ params 2]", params);

pools.on("zhufeng", fn1);
pools.on("zhufeng", fn1);
pools.on("zhufeng", fn2);

pools.off("zhufeng", fn2);

setTimeout(() => {
  pools.emit("zhufeng", 1, 2, 3);
}, 300);
对比操作
(function () {
  function EventEmitter() {
    this._events = Object.create(null);
  }
  // {'失恋':[]}
  EventEmitter.prototype.on = function (eventName, callback) {
    // 判断实例是否有此属性
    if (!this._events) this._events = Object.create(null);
    if (eventName !== "newListener") {
      let listeners = this._events["newListener"];
      if (listeners) {
        // 如果有newLister就触发newListener对应的事件
        this.emit("newListener", eventName);
      }
    }
    let stack = this._events[eventName] || [];
    stack.push(callback);
    this._events[eventName] = stack;
  };
  EventEmitter.prototype.once = function (eventName, callback) {
    // 先绑定 绑定完触发后 去删除掉
    const one = (...args) => {
      callback(...args); // 原函数 ,原函数执行后 将自己删除掉即可
      this.off(eventName, one);
    };
    one.l = callback;
    this.on(eventName, one);
  };
  // 删除数组中的某一项
  EventEmitter.prototype.off = function (eventName, callback) {
    if (this._events[eventName]) {
      this._events[eventName] = this._events[eventName].filter((item) => {
        // 如果绑定的one 和要关闭 的回调一样我也要删除掉这个函数
        return item !== callback && item.l !== callback;
      });
    }
  };
  EventEmitter.prototype.emit = function (eventName, ...args) {
    if (this._events[eventName]) {
      this._events[eventName].forEach((fn) => {
        fn(...args);
      });
    }
  };
  module.exports = EventEmitter;
})();

  • 图片的加载速度往往影响着网站整体的用户体验,尤其对于包含大量图片的网站。
  • 对图片进行预加载,不失为一个高效的解决方案。如何实现预加载?
  • 预加载图片是提高用户体验的一个很好方法。图片预先加载到浏览器中,
    访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度。
    这对图片画廊及图片占据很大比例的网站来说十分有利,它保证了图片快速、无缝地发布,也可帮助用户在浏览你网站内容时获得更好的用户体验。
首先将需要加载的图片放置到一个数组中
 export default {
  data() {
    return {
      preloadImgs : [
        require('图片路径'),
        require('图片路径'),
        require('图片路径'),
     ],
      num: 0
    }
  },
  computed: {
    percent() {
      //计算图片加载的百分进度
      return parseInt((this.num / this.preloadImgs.length) * 100)
    }
  },
  mounted() {
    this.preload()
  },
  methods: {
    preload() {
      for (let i = 0; i < this.preloadImgs.length; i++) {
        const img = new Image()
        img.src = this.preloadImgs[i]
        img.onload = (e) => {
          this.num++
          this.loaded()
        }
        img.onerror = () => {
          this.num++
          this.loaded()
        }
      }
    },
    loaded() {
      if (this.num === this.preloadImgs.length) {
       //此时是所有图片加载完成的时候要做事情
      }
    }
  },

事件冒泡捕获api

/* 
事件的捕获和冒泡机制你了解多少
1. 基本概念

捕获:自顶向下
冒泡:自底向上

2.监听那个阶段的事件?  
window.addEventListener('click',()=>{
})
第三个参数 Beallen
默认 false 冒泡阶段  true  的捕获阶段

3.平常那些场景用到啦这个机制?

4.有一个历史页面,上面若干个按钮,每个按钮都有自己的click事件

新的需求:当你给每个访问用户都加一个属性,banned=true,此用户点击点击按钮任何元素都不能响应原来的函数,而是直接alert 提示,你被封禁啦

就是在最顶层绑定一个捕获事件,最先触发,判断用户是否有权限  弹出提示信息
window.addEventListener("click", (e) => {
    if (bananed === true) {
      e.target.stopPropagation();
    }
  })
*/
(function () {
  let ulo = document.querySelector(".ulist");
  ulo.addEventListener("click", function (e) {
    const target = e.target;
    if (target.tagName.toLowerCase() === "li") {
      console.log("[ this ]", this);
      const lilist = this.querySelectorAll("li");
      const i = Array.prototype.indexOf.call(lilist, target);
      alert(`内容为${target.innerHTML},索引为${i}`);
    }
  });
  console.log("[ ulo ]", ulo);
  /* 
  事件委托利用啦事件的冒泡
  */
})();

Symbol
在这里插入图片描述

/* let arr = [1, 2, 3, 4, 5, 6];

arr[Symbol.iterator] = function iterator(params) {
  console.log("[ kok ]");
  let index = 0,
    self = this;
  return {
    next() {
      if (index >= self.length) {
        return {
          done: true,
          value: undefined,
        };
      }
      return {
        done: false,
        value: self[index++] * 100,
      };
    },
  };
};
for (const item of arr) {
  console.log("[ item ]", item);
} */

/* let obj = {
  name: "zhufeng",
  age: 12,
  0: 100,
  1: 200,
  // [Symbol('AA')]:300
};
obj[Symbol.iterator] = function iterator(params) {
  let index = 0,
    self = this,
    keys = Reflect.ownKeys(self);
  return {
    next() {
      if (index >= keys.length) {
        return {
          done: true,
          value: undefined,
        };
      }
      return {
        done: false,
        value: self[keys[index++]],
      };
    },
  };
};
for (const iterator of obj) {
  console.log("[ iterator ]", iterator);
} */

// 函数前的加*就是生成器函数

// function *generator(params) {

// }

// let intor=generator()

// console.log('[ intor ]', intor)

const fn1 = function () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
};

const fn2 = function () {
  return Promise.resolve(2);
};
const fn3 = (function () {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(3);
    }, 3000);
  });
})
(async () => {
  let obj = {};
  obj[Symbol.asyncIterator] = async function* iterator() {
    console.log(1);
    yield 1;
    console.log(2);
    yield 2;
    console.log(3);
    yield 3;
  };
  for await (let iterator of obj) {
    console.log("[ iterator ]", iterator);
  }
})();





柯力化

function fn(a, b, c, d) {
  console.log("[  ]", a + b + c + d);
  return a + b + c + d;
}
function isType(type,val){
    return Object.prototype.toString.call(val)===`[object ${type}]`
}
function curring(cb) {
  const inner = (...args) => {
    return args.length === cb.length ? cb(...args) : (arg) => inner(...args, arg);
  };
  return inner;
}
let type = curring(isType);
let isString=type('String')
let isNumber=type('Number')
let isArray=type('Array')
let isObject=type('Object')
let isFunction=type('Function')
let isNull=type('Null')
console.log('[ isNumber(122) ]', isNumber(null))
console.log('[ isString(122) ]', isString('122'))


// fn2(1,2, 3, 4);
// fn2(1)(1)(1,2)
// fn2(2)(3)
// fn2(4)(5)
// console.log("[  ]", fn2(1)(2, 3, 4, 5));

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值