前端笔记(二) 对象的深浅拷贝,函数的防抖与撙节,函数柯里化 ,图片的预加载与懒加载

对象的深浅拷贝

对象的深拷贝与浅拷贝的区分:

  • 浅拷贝:仅仅复制对象的援用, 而不是对象自身。
  • 深拷贝:把复制的对象所援用的悉数对象都复制一遍

浅拷贝的完成:

var obj = {
   age : 18,
   person : {
     hobby : "movie",
     skill : "Java"
   }
}
//要领一
function shallowClone(initial) {
   var obj = {};
   for( var i in initial ) {
      obj[i] = initial[i];
   }
   return obj;
}
//要领二
var newobj = Object.assign({}, obj);
console.log(newobj);

var clone = shallowClone(obj);
console.log(clone.age); //18
clone.person.skill = "JavaScript";
console.log(obj.person.skill); //JavaScript

深拷贝的完成:

var obj = {
   age : 18,
   person : {
     hobby : "movie",
     skill : "Java"
   }
}

/* 要领一:
 * 这类要领能准确处置惩罚的对象只要 Number, String, Boolean, Array, 扁平对象。
 * 即那些能够被 json 直接示意的  数据结构。RegExp对象是没法经由过程这类体式格局深拷贝。
 */
function deepCopy(initial) {
   var obj = {};
   obj = JSON.parse(JSON.stringify(initial));
   return obj;
}
var copy = deepCopy(obj);
console.log(copy);

//要领二 (递归拷贝)
function deepClone(initial, final) {
    var obj = final || {};
    for( var i in initial ) {
       var prop = initial[i];
       //防止互相援用致使死循环
       if( prop === obj ) {
           continue;
       }
       if( typeof prop === 'object' ) {
           obj[i] = ( prop.constructor === Array ) ? prop : Object.create(prop);
       }else {
           obj[i] = prop;
       }
    }
  return obj;
}
var now = {}
deepClone(obj, now);
now.person.hobby = "sport";
console.log(obj.person.hobby); //movie


函数的防抖与撙节

我们经常会碰到如许一种情形, 用户高频次触发一些JS事宜。但是在肯定时间内实行代码的次数太多往往会致使浏览器的机能下落以至形成卡顿的征象, 所以我们能够把js实行代码的次数控制在合理的范围内, 在完成雷同结果的情况下使页面交互变得越发流通。这就是函数防抖和撙节要做的事变。

函数防抖:

//debounce
function debounce(func, context) {
   clearTimeout(func.setTime);
   func.setTime = setTimeout(() => {
      func.call(context); 
   }, 300);
}

window.onscroll = function() {
   debounce(doSomething);
}

function doSomething() {
   console.log("函数防抖");
   //实行一些消耗机能的事宜...
}

从上面代码能够看出函数防抖的中心头脑是在挪用定时器实行某个函数之前起首消灭这个定时器。当函数屡次被挪用时, 每一次都邑将之前的定时器消灭, 即只要在实行函数的要求住手了一段时间以后才会真正实行函数。

函数撙节:

//throttle
function throttle(func, time, context) {
   let start = Date.now();
   return function() {
      if (Date.now() - start > time && time > 0) {
          func.call(context);
          start = Date.now();
      }
   }
}
window.onscroll = throttle(doSomething, 300);

function doSomething() {
   console.log("函数撙节");
   //实行一些消耗机能的事宜...
}

函数撙节的头脑是设置一个实行函数间隔时间time, 当屡次触发某个事宜时便将实行函数的频次降低到time。

如许一来就到达了我们所想要的结果了。

/*函数撙节的另一种完成体式格局*/
var flag = true;

function throttle(fn, context) {
   if(!flag) {
      return;
   }
   flag = false;
   setTimeout(() => {
      fn.call(context);
      flag = true;
   }, 300)
}

window.onscroll = function() {
   throttle(doSomething);
}

function doSomething() {
   console.log("函数撙节");
   //实行一些消耗机能的事宜...
}

值得注意的是这两种要领在详细浏览器中的运转下结果有所差别。函数防抖当触发频次太高时函数基础住手实行, 而函数撙节则是依据肯定的频次实行js事宜。

/* @防抖与撙节夹杂版 
--- 有第三个参数时为撙节结果, 若没有则为防抖结果 ---
*/
var tdmixer = function(fn, delay, reqDelay, context) {
    var timer = null;
    var start;
    return function() {
        var args = arguments;
        var current = +new Date();
        clearTimeout(timer);
        if ( !start ) {
            start = current;
        }
        if ( current - start >= reqDelay ) {
            fn.apply(context, args);
            start = current;
        }else {
            timer = setTimeout( function() {
                fn.apply(context, args);
            }, delay);
        }
    }
}

window.onscroll = tdmixer(doSomething, 100, 300);

function doSomething() {
   console.log("This is a mix version.");
   //实行一些消耗机能的事宜...
}


函数柯里化

它与函数绑定严密相干, 用于建立已设置好了一个或多个参数的函数, 其详细做法时运用一个闭包返回一个函数, 当函数被挪用时, 返回的函数还须要设置一些传入的参数。

柯里化的三个作用 : 1.参数复用 2. 提早返回 3.耽误盘算

function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function() {
        var innerargs = Array.prototype.slice.call(arguments);
        var finalargs = args.concat(innerargs);
        return fn.apply(null, finalargs);
    }
}

function addAll(x,y,z) {
    return x + y + z;
}
var excute = curry(addAll,5,10);
excute(50); //65

ES5中的bind要领也用到过柯里化, 下面是简朴的函数绑定的完成。

function bind(fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function() {
        var innerargs = Array.prototype.slice.call(arguments);
        var finalargs = args.concat(innerargs);
        return fn.apply(context, finalargs);
    }
}
var handler = {
    message: "PIPI",
    handleClick(name) {
        console.log(name + "and" + this.message);
    }
}
var excute = bind(handler.handleClick, handler);
excute("POP");  //POPandPIPI

图片预加载与懒加载

  1. 预加载:

望文生义, 图片的预加载就是将图片预先加载到浏览器的当地缓存中, 当须要时直接从当地加载图片到页面中, 如此一来就很好的提高了用户的体验。但瑕玷是增加了服务器端的开支。

  1. 懒加载:

也叫耽误加载, 即耽误加载图片或许当相符某些前提时才最先加载图片, 它与预加载相反, 其作用是对服务器端的机能优化, 削减要求数或耽误要求数, 从而到达减缓服务器端压力的结果。

— preload code —

//对预加载图片举行一些回调事宜处置惩罚
function preLoadImg(url, callback) {
    var img = new Image();
    if ( img.complete ) { //若图片已在当地缓存, 则直接挪用回调函数
        callback.call(img);
        return;
    }
    img.onload = function() { //图片下载完以后异步挪用callback
        img.onload = null;
        callback.call(img);
    }
    img.src = url; 
}

//大批图片预加载
var arr = ['pic1.png', 'pic2.png', 'pic3.png'];
function fn() { console.log('Do something...') };

function preLoadImages(urls, callback) {
    var wrap = Array.prototype.slice.call(arguments, 0, 1);
    var urls = [].concat.apply([], wrap);  //将其转化为一维数组
    for ( var i = 0; i < urls.length; i++) { 
        var img = new Image(); 
        img.onload = function() {
            callback.call(img);
        }
        img.src = urls[i];   
    }
}
preLoadImages(arr, fn);

— lazyload code —

//懒加载的完成
var lazyload = {
    //初始化
    init() {
        this.container = document.querySelector('Container'); //猎取容器元素
        this.images = this.getImages();
        this.update();
        this.bindEvent();
    },
    //猎取图片
    getImages() {
        var arr = [];
        var images = this.container.querySelectorAll('img');
        images.forEach( (img) => {
            arr.push(img);
        });
        return arr;
    },
    //加载图片
    update() {
        if ( !this.images.length ) { return };
        var i  = this.images.length;
        for ( i--; i >= 0; i-- ) {
            if ( this.couldShow(i) ) {
                this.images[i].src = this.images[i].getAttribute('data-src'); //需事前设置途径
                this.images.splice(i, 1);
            }
        }
    },
    //推断图片是不是在可视地区并给予src值
    couldShow(i) {
        var img = this.images[i];
        scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        scrollBottom = scrollTop + document.documentElement.clientHeight;
        imgTop = this.rectY(img);
        imgBottom = imgTop + img.offsetHeight;
        if ( imgBottom < scrollBottom && imgBottom > scrollTop 
        || imgTop > scrollTop && imgTop < scrollBottom ) {
            return true;
        }else {
            return false;
        }
    },
    //递归挪用猎取图片顶部到全部页面的最顶端的间隔
    rectY(el) {
        if ( el.offsetParent ) {
            return el.offsetTop + this.rectY(el.offsetParent);
        }else {
            return el.offsetTop;
        }
    },
    //事宜绑定
    bindEvent() {
        var that = this;
        that.on(window, "scroll", () => {
          var fn = tdmixer(that.update, 100, 300, that); //函数撙节
          fn();
        } ) 
    },
    //监听
    on(el, type, fn) {
        if ( el.addEventListener ) {
            el.addEventListener(type, fn);
        }else {
            el.attachEvent("on" + type, fn);
        }
    }
}

lazyload.init();

//上文所给出的夹杂撙节函数
var tdmixer = function(fn, delay, reqDelay, context) {
    var timer = null;
    var start;
    return function() {
        var args = arguments;
        var current = +new Date();
        clearTimeout(timer);
        if ( !start ) {
            start = current;
        }
        if ( current - start >= reqDelay ) {
            fn.apply(context, args);
            start = current;
        }else {
            timer = setTimeout( function() {
                fn.apply(context, args);
            }, delay);
        }
    }
}

从上面的两段代码能够看出, 图片预加载完成起来要简朴很多, 固然两种功用都有很多种差别的完成要领, 有简朴的也有庞杂的, 这都须要依据详细的情形来编写代码。预加载一次性就加载须要的图片到当地贮存从而提高了用户的体验却也加大了服务器端的累赘, 而懒加载则须要依据某些详细的前提来推断什么时候向服务器端要求图片数据, 虽然削减了服务器端的开支, 但详细完成的步骤也变得越发庞杂。所以在现实情况下二者最好夹杂运用且用在准确的处所上最为适宜。

    原文作者:RetroAstro
    原文地址: https://segmentfault.com/a/1190000013267205
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞