国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端筆記(二) 對象的深淺拷貝,函數的防抖與節流,函數柯里化 ,圖片的預加載與懶加載

dongxiawu / 2841人閱讀

摘要:對象是無法通過這種方式深拷貝。這就是函數防抖和節流要做的事情。函數防抖當觸發頻率過高時函數基本停止執行而函數節流則是按照一定的頻率執行事件。

對象的深淺拷貝

對象的深拷貝與淺拷貝的區別:

淺拷貝:僅僅復制對象的引用, 而不是對象本身。

深拷貝:把復制的對象所引用的全部對象都復制一遍

淺拷貝的實現:

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
圖片預加載與懶加載

預加載:

顧名思義, 圖片的預加載就是將圖片預先加載到瀏覽器的本地緩存中, 當需要時直接從本地加載圖片到頁面中, 如此一來就很好的提高了用戶的體驗。但缺點是增加了服務器端的開銷。

懶加載:

也叫延遲加載, 即延遲加載圖片或者當符合某些條件時才開始加載圖片, 它與預加載相反, 其作用是對服務器端的性能優化, 減少請求數或延遲請求數, 從而達到緩解服務器端壓力的效果。

--- 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);
        }
    }
}

從上面的兩段代碼可以看出, 圖片預加載實現起來要簡單許多, 當然兩種功能都有很多種不同的實現方法, 有簡單的也有復雜的, 這都需要根據具體的情景來編寫代碼。預加載一次性就加載需要的圖片到本地儲存從而提高了用戶的體驗卻也加大了服務器端的負擔, 而懶加載則需要根據某些具體的條件來判斷何時向服務器端請求圖片數據, 雖然減少了服務器端的開銷, 但具體實現的步驟也變得更加復雜。所以在實際情況下兩者最好混合使用且用在正確的地方上最為合適。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107442.html

相關文章

  • 小菊花課堂之JS抖與節流

    摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...

    leoperfect 評論0 收藏0
  • 小菊花課堂之JS抖與節流

    摘要:文章來源詳談防抖和節流輕松理解函數節流和函數防抖函數防抖和節流好啦,今天的小菊花課堂之的防抖與節流的內容就告一段落啦,感各位能耐心看到這里。 前言 陸游有一首《冬夜讀書示子聿》——古人學問無遺力,少壯工夫老始成。紙上得來終覺淺,絕知此事要躬行。,其中的意思想必大家都能明白,在學習或工作中,不斷的印證著這首詩的內涵。所以,又有了此篇小菊花文章。 詳解 在前端開發中,我們經常會碰到一些會持...

    Yangder 評論0 收藏0
  • JavaScript專題系列文章

    摘要:專題系列共計篇,主要研究日常開發中一些功能點的實現,比如防抖節流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點是研究專題之函數組合專題系列第十六篇,講解函數組合,并且使用柯里化和函數組合實現模式需求我們需要寫一個函數,輸入,返回。 JavaScript 專題之從零實現 jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實現一個 jQuery 的 ext...

    Maxiye 評論0 收藏0
  • 說說JavaScript中函數防抖 (Debounce) 與節流 (Throttle)

    摘要:基礎防抖我們現在寫一個最基礎的防抖處理標記事件也做如下改寫現在試一下,我們會發現只有我們停止滾動秒鐘的時候,控制臺才會打印出一行隨機數。 為何要防抖和節流 有時候會在項目開發中頻繁地觸發一些事件,如 resize、 scroll、 keyup、 keydown等,或者諸如輸入框的實時搜索功能,我們知道如果事件處理函數無限制調用,會大大加重瀏覽器的工作量,有可能導致頁面卡頓影響體驗;后臺...

    yanwei 評論0 收藏0
  • JavaScript專題系列20篇正式完結!

    摘要:寫在前面專題系列是我寫的第二個系列,第一個系列是深入系列。專題系列自月日發布第一篇文章,到月日發布最后一篇,感謝各位朋友的收藏點贊,鼓勵指正。 寫在前面 JavaScript 專題系列是我寫的第二個系列,第一個系列是 JavaScript 深入系列。 JavaScript 專題系列共計 20 篇,主要研究日常開發中一些功能點的實現,比如防抖、節流、去重、類型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評論0 收藏0

發表評論

0條評論

dongxiawu

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<