精华内容
下载资源
问答
  • 闭包的使用场景

    2021-03-09 19:24:52
    闭包的使用场景 1.setTimeout 原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。 function f1(a) { function f2() { console.log(a); } return f2; } var fun = f1(1); setTimeout(fun,...

    闭包的使用场景

    1.setTimeout

    原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。

    function f1(a) {
        function f2() {
            console.log(a);
        }
        return f2;
    }
    var fun = f1(1);
    setTimeout(fun,1000);//一秒之后打印出1
    

    2.回调

    定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。
    比如下面这段代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试</title>
    </head>
    <body>
        <a href="#" id="size-12">12</a>
        <a href="#" id="size-20">20</a>
        <a href="#" id="size-30">30</a>
    
        <script type="text/javascript">
            function changeSize(size){
                return function(){
                    document.body.style.fontSize = size + 'px';
                };
            }
    
            var size12 = changeSize(12);
            var size14 = changeSize(20);
            var size16 = changeSize(30);
    
            document.getElementById('size-12').onclick = size12;
            document.getElementById('size-20').onclick = size14;
            document.getElementById('size-30').onclick = size16;
    
        </script>
    </body>
    </html>
    

    当点击数字时,字体也会变成相应的大小。

    3.函数防抖

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

    实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。

    如下代码所示:

    * fn [function] 需要防抖的函数
    * delay [number] 毫秒,防抖期限值
    */
    function debounce(fn,delay){
        let timer = null
        //借助闭包
        return function() {
            if(timer){
                clearTimeout(timer) //进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时
                timer = setTimeOut(fn,delay) 
            }else{
                timer = setTimeOut(fn,delay) // 进入该分支说明当前并没有在计时,那么就开始一个计时
            }
        }
    }
    

    4.封装私有变量

    如下面代码:用js创建一个计数器

    方法1:

    function f1() {
        var sum = 0;
        var obj = {
           inc:function () {
               sum++;
               return sum;
           }
    };
        return obj;
    }
    let result = f1();
    console.log(result.inc());//1
    console.log(result.inc());//2
    console.log(result.inc());//3
    

    在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。

    方法2:

    function f1() {
        var sum = 0;
        function f2() {
            sum++;
            return f2;
        }
        f2.valueOf = function () {
            return sum;
        };
        f2.toString = function () {
            return sum+'';
        };
        return f2;
    }
    //执行函数f1,返回的是函数f2
    console.log(+f1());//0
    console.log(+f1()())//1
    console.log(+f1()()())//2
    

    所有js数据类型都拥有valueOf和toString这两个方法,null除外
    valueOf()方法:返回指定对象的原始值。
    toString()方法:返回对象的字符串表示。
    在数值运算中,优先调用了valueOf,字符串运算中,优先调用toString
    sum+’ '是一个字符串类型的数据

    展开全文
  • 主要介绍了JavaScript 闭包的使用场景,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下
  • 闭包的使用场景闭包的使用场景一、![在这里插入图片描述](https://img-blog.csdnimg.cn/2021031002034444.png) 闭包的使用场景 昨天面试官问我:你在项目中使用过闭包吗?我说没有。 现在想想挺想打自己的,防抖里面...

    闭包的使用场景

    闭包的使用场景

    定义:闭包就是能够读取其他函数内部变量的函数。把内部函数作为返回值不就可以了。

    在这里插入图片描述
    在这里插入图片描述
    项目中的防抖函数。

    展开全文
  • 一、闭包由于在Javascript语言中,只有函数内部子函数才能读取局部变量,闭包就是能够读取其他函数内部变量函数。所以,在本质上,闭包就是将函数内部和函数外部连接起来一座桥梁。比如下面代码:functionf1...

    一、闭包

    由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,闭包就是能够读取其他函数内部变量的函数。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

    比如下面的代码:

    functionf1() {var n = 999;functionf2() {

    console.log(n);

    }returnf2;

    }var result =f1();

    result();//999

    函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。

    这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

    既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,就可以在f1外部读取它的内部变量了。

    二、闭包的使用场景

    1.setTimeout

    原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。

    functionf1(a) {functionf2() {

    console.log(a);

    }returnf2;

    }var fun = f1(1);

    setTimeout(fun,1000);//一秒之后打印出1

    2.回调

    定义行为,然后把它关联到某个用户事件上(点击或者按键)。代码通常会作为一个回调(事件触发时调用的函数)绑定到事件。

    比如下面这段代码:

    测试

    12

    20

    30

    function changeSize(size){

    return function(){

    document.body.style.fontSize = size + 'px';

    };

    }var size12 = changeSize(12);var size14 = changeSize(20);var size16 = changeSize(30);

    document.getElementById('size-12').onclick =size12;

    document.getElementById('size-20').onclick =size14;

    document.getElementById('size-30').onclick =size16;

    当点击数字时,字体也会变成相应的大小。

    3.函数防抖

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

    实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。

    如下代码所示:

    /** fn [function] 需要防抖的函数

    * delay [number] 毫秒,防抖期限值*/

    functiondebounce(fn,delay){

    let timer= null //借助闭包

    return function() {if(timer){

    clearTimeout(timer)//进入该分支语句,说明当前正在一个计时过程中,并且又触发了相同事件。所以要取消当前的计时,重新开始计时

    timer =setTimeOut(fn,delay)

    }else{

    timer= setTimeOut(fn,delay) //进入该分支说明当前并没有在计时,那么就开始一个计时

    }

    }

    }

    4.封装私有变量

    如下面代码:用js创建一个计数器

    方法1:

    function f1() {

    var sum = 0;

    var obj = {

    inc:function () {

    sum++;

    return sum;

    }

    };

    return obj;

    }

    let result = f1();

    console.log(result.inc());//1

    console.log(result.inc());//2

    console.log(result.inc());//3

    在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。

    方法2:

    functionf1() {var sum = 0;functionf2() {

    sum++;returnf2;

    }

    f2.valueOf= function() {returnsum;

    };

    f2.toString= function() {return sum+'';

    };returnf2;

    }//执行函数f1,返回的是函数f2

    console.log(+f1());//0

    console.log(+f1()())//1

    console.log(+f1()()())//2

    所有js数据类型都拥有valueOf和toString这两个方法,null除外

    valueOf()方法:返回指定对象的原始值。

    toString()方法:返回对象的字符串表示。

    在数值运算中,优先调用了valueOf,字符串运算中,优先调用toString

    sum+' '是一个字符串类型的数据

    展开全文
  • 概念闭包是指有权访问另外一个函数作用域中的变量的函数闭包的优点可以重复使用变量,并且不会造成变量污染全局变量可以重复使用,但是容易造成变量污染。局部变量仅在局部作用域内有效,不可以重复使用,不会造成...

    概念

    闭包是指有权访问另外一个函数作用域中的变量的函数

    闭包的优点

    可以重复使用变量,并且不会造成变量污染

    全局变量可以重复使用,但是容易造成变量污染。局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。闭包结合了全局变量和局部变量的优点。

    可以用来定义私有属性和私有方法。

    闭包的缺点

    比普通函数更占用内存,会导致网页性能变差,在IE下容易造成内存泄露。

    什么是内存泄漏

    首先,需要了解浏览器自身的内存回收机制。

    每个浏览器会有自己的一套回收机制,当分配出去的内存不使用的时候便会回收;内存泄露的根本原因就是你的代码中分配了一些‘顽固的’内存,浏览器无法进行回收,如果这些’顽固的’内存还在一直不停地分配就会导致后面所用内存不足,造成泄露。

    闭包造成内存泄漏

    因为闭包就是能够访问外部函数变量的一个函数,而函数是必须保存在内存中的对象,所以位于函数执行上下文中的所有变量也需要保存在内存中,这样就不会被回收,如果一旦循环引用或创建闭包,就会占据大量内存,可能会引起内存泄漏

    内存泄漏的解决方案

    造成内存泄露的原因:

    意外的全局变量(在函数内部没有使用var进行声明的变量)

    console.log

    闭包

    对象的循环引用

    未清除的计时器

    DOM泄露(获取到DOM节点之后,将DOM节点删除,但是没有手动释放变量,拿对应的DOM节点在变量中还可以访问到,就会造成泄露)

    如何避免闭包引起的内存泄漏:

    在退出函数之前,将不使用的局部变量全部删除,可以使变量赋值为null

    //这段代码会导致内存泄露

    window.onload = function(){

    var el = document.getElementById("id");

    el.onclick = function(){

    alert(el.id);

    }

    }

    //解决方法为

    window.onload = function(){

    var el = document.getElementById("id");

    var id = el.id; //解除循环引用

    el.onclick = function(){

    alert(id);

    }

    el = null; // 将闭包引用的外部函数中活动对象清除

    }

    避免变量的循环赋值和引用(代码如上)

    由于jQuery考虑到了内存泄漏的潜在危害,所以它会手动释放自己指定的所有事件处理程序。只要坚持使用jQuery的事件绑定方法,就可以一定程度上避免这种特定的常见原因导致的内存泄漏。

    //这段代码会导致内存泄露

    $(document).ready(function() {

    var button = document.getElementById('button-1');

    button.onclick = function() {

    console.log('hello');

    return false;

    };

    });

    //当指定单击事件处理程序时,就创建了一个在其封闭的环境中包含button变量的闭包。而且,现在的button也包含一个指向闭包(onclick属性自身)的引用。这样,就导致了在IE中即使离开当前页面也不会释放这个循环。

    //用jQuery化解引用循环

    $(document).ready(function() {

    var $button = $('#button-1');

    $button.click(function(event) {

    event.preventDefault();

    console.log('hello');

    });

    });

    闭包的使用场景

    封装功能时(需要使用私有的属性和方法),函数防抖、函数节流、函数柯里化、给元素伪数组添加事件需要使用元素的索引值。

    闭包实例--函数防抖

    /**

    * @function debounce 函数防抖

    * @param {Function} fn 需要防抖的函数

    * @param {Number} interval 间隔时间

    * @return {Function} 经过防抖处理的函数

    * */

    function debounce(fn, interval) {

    let timer = null; // 定时器

    return function() {

    // 清除上一次的定时器

    clearTimeout(timer);

    // 拿到当前的函数作用域

    let _this = this;

    // 拿到当前函数的参数数组

    let args = Array.prototype.slice.call(arguments, 0);

    // 开启倒计时定时器

    timer = setTimeout(function() {

    // 通过apply传递当前函数this,以及参数

    fn.apply(_this, args);

    // 默认300ms执行

    }, interval || 300)

    }

    }

    概念:

    就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

    通俗一点:在一段固定的时间内,只能触发一次函数,在多次触发事件时,只执行最后一次。

    使用时机:

    搜索功能,在用户输入结束以后才开始发送搜索请求,可以使用函数防抖来实现;

    闭包实例--函数节流

    /**

    * @function throttle 函数节流

    * @param {Function} fn 需要节流的函数

    * @param {Number} interval 间隔时间

    * @return {Function} 经过节流处理的函数

    * */

    function throttle(fn, interval) {

    let timer = null; // 定时器

    let firstTime = true; // 判断是否是第一次执行

    // 利用闭包

    return function() {

    // 拿到函数的参数数组

    let args = Array.prototype.slice.call(arguments, 0);

    // 拿到当前的函数作用域

    let _this = this;

    // 如果是第一次执行的话,需要立即执行该函数

    if(firstTime) {

    // 通过apply,绑定当前函数的作用域以及传递参数

    fn.apply(_this, args);

    // 修改标识为null,释放内存

    firstTime = null;

    }

    // 如果当前有正在等待执行的函数则直接返回

    if(timer) return;

    // 开启一个倒计时定时器

    timer = setTimeout(function() {

    // 通过apply,绑定当前函数的作用域以及传递参数

    fn.apply(_this, args);

    // 清除之前的定时器

    timer = null;

    // 默认300ms执行一次

    }, interval || 300)

    }

    }

    概念

    就是限制一个函数在一定时间内只能执行一次。

    使用时机

    改变浏览器窗口尺寸,可以使用函数节流,避免函数不断执行;

    滚动条scroll事件,通过函数节流,避免函数不断执行。

    函数节流与函数防抖的区别:

    我们以一个案例来讲一下它们之间的区别:

    设定一个间隔时间为一秒,在一分钟内,不断的移动鼠标,让它触发一个函数,打印一些内容。

    函数防抖:会打印1次,在鼠标停止移动的一秒后打印。

    函数节流:会打印60次,因为在一分钟内有60秒,每秒会触发一次。

    总结:节流是为了限制函数的执行次数,而防抖是为了限制函数的执行时机。

    函数节流与函数防抖的使用

    此处使用一个对象的方法,主要为了测试this指向绑定的问题,调用的时候传递参数问题等。

    function log(a,b) {

    console.log(a,b);

    console.log(this);

    }

    const throttleLog = throttle(log, 1000);

    const debounceLog = debounce(log, 1000);

    let a = {

    b: throttleLog,

    c: debounceLog

    };

    document.body.onmousemove = function() {

    a.b('throttle', 'log');

    a.c('debounce', 'log');

    };

    闭包实例--给元素伪数组添加事件

    // DOM操作

    let li = document.querySelectorAll('li');

    for(var i = 0; i < li.length; i++) {

    (function(i){

    li[i].onclick = function() {

    alert(i);

    }

    })(i)

    }

    闭包实例--不使用循环返回数组

    function getArr() {

    let num = 10;

    let arr = [];

    return (function(){

    arr.unshift(num);

    num--;

    if(num > 0) {

    arguments.callee();

    }

    return arr;

    })()

    }

    console.log(getArr()); //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    展开全文
  • 闭包是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。...闭包的优缺点,闭包的使用场景:http
  • 闭包什么是闭包闭包很简单,就是能够访问另一个函数作用域变量函数,更简单说,闭包就是函数,只不过是声明在其它函数内部而已。例如:functiongetOuter(){ varco...
  • 闭包的优点 可以重复使用变量,并且不会造成变量污染 全局变量可以重复使用,但是容易造成变量污染。局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。闭包结合了全局变量和局部变量的优点。 ...
  • 深入理解闭包以及闭包的使用场景

    千次阅读 2019-02-22 19:34:29
    理解:能访问父函数参数并且能立即执行或者被直接return出来函数为闭包 理解“闭包” step 1:掌握嵌套函数词法作用域规则 var scope = &amp;quot;global scope&amp;quot;; function checkScope...
  • 二、闭包的优缺点以及闭包的特性 优点: 保护函数内变量的安全 可以重复使用变量,并且不会造成变量污染 方便调用访问上下文的局部变量 可以用来定义私有属性和私有方法 缺点: 常驻内存中,会增大内存使用量,使用...
  • JS : 闭包的使用场景

    2019-03-11 20:47:49
    有时候,我们需要得到函数内部的局部变量,但是前面讲到,正常...**创建闭包的常见方式,就是在一个函数内部创建另一个函数。 实例1: var a = 10; function f1(){ var b = 1000; function f2(){ console.lo...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 668
精华内容 267
关键字:

闭包的使用场景