你不可不知的JS面试题(第三期)

简介: 闭包就是一个定义在函数内部的函数,其作用是将函数内部和函数外部连接起来。 大家知道,作用域的问题,就是在函数内部定义的变量称为局部变量,外部取不到值。

1、什么是闭包?


网络异常,图片无法展示
|


如图所示,闭包就是一个定义在函数内部的函数,其作用是将函数内部和函数外部连接起来。大家知道,作用域的问题,就是在函数内部定义的变量称为局部变量,外部取不到值。 下面我们通过代码来更加详细地看一下:


function A() {
       let x = 1;
       return function B() {
           console.log(x);
           x++;
       }
   }
   console.log(A()); //直接打印返回的B
   let b = A();
   b(); //1
   b(); //2
   b(); //3


上述代码我们可以看到的是再次执行A函数的时候(其实这时候执行的是B),会打印出1,再次执行,会打印出2,再执行会打印出3。我们知道了闭包不仅可以拿到函数内部的变量,还可以保存内部的变量。


接下来,我们来看下闭包的使用场景,


for (var index = 0; index < 5; index++) {
    setTimeout(function () {
        console.log(index)
    });
}


上面的代码段,我们会打印5个5,为啥呢?因为当我们执行for循环时,setTimeout是异步的,所以每次等for循环加完,再执行setTimeout函数,一共执行5次。另一个原因因为使用了var 声明的。循环体里的index跟外部的index是存在于同一个作用域,相当于在全局定义了一次。


下面我们来使用let来声明一下。结果就不一样。分别打印0、1、2、3、4


for (let index = 0; index < 5; index++) {
        setTimeout(function () {
            console.log(index)
        });
    }


最后,我们使用闭包也来实现一下,同样分别打印0、1、2、3、4,在外部函数每次传入实参时,也就是每次循环的值index,作用到形参i,因为setTimeout为内部函数,每次都会记录值,然后打印出来。


for (var index = 0; index < 5; index++) {
        (function (i) {
            setTimeout(function () {
                console.log(i)
            });
        })(index);
    }


另一个使用场景是柯里化。下面一个问题我们将详解。


2、什么是柯里化?


是把接受多个参数的函数变换成接受一个单一参数(最初的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。


网络异常,图片无法展示
|


3、柯里化的好处?


  • 提高适用性
  • 延迟执行
  • 提前确认


(1)、提高适用性


我们之前使用函数都是这样写,很冗余。


function check(reg,text) {
     return reg.test(text);
 }
 console.log(check(/\d+/g,'123456')) //true
 console.log(check(/\d+/g,'abcd')) // false
 console.log(check(/\d+/g,'r8r8r7')) // true


那么我们通过柯里化的形式简化一下。


function check(reg) {
     return function (text) {
        return reg.test(text);
     }
 }
 const checkNum=check(/\d+/g);
 console.log(checkNum('123456')) //true
 console.log(checkNum('abcd')) // false
 console.log(checkNum('r8r8r7')) // true


(2)、延迟执行在需要的时候再执行。


const getResult = add(1)(2)(3);
// TODO
getResult();


或者


const getResult =add.bind(null,1).bind(null,2).bind(null,3);
// TODO
getResult();


(3)、提前确认


之前执行一次,就不会每次都去判断了,下面举例:


function getBindEvent(isIE) {
     if(isIE){
         return  function () {
             // TODO
             console.log(1)
         }
     }
     return function () {
            // TODO
             console.log(0)
     }
 }
 const isIE = !!window.ActiveXObject||"ActiveXObject" in window;
 const bindEvent = getBindEvent(isIE);
 bindEvent(); 


最后这里来实现下图所示:


网络异常,图片无法展示
|


function add() {
    // arguments是一个类数组
    const args = Array.prototype.slice.call(arguments); // 将参数都放在一个数组里
    return function () {
        // 下面的arguments与上面的不一样,下面的arguments为当前函数环境下的参数
        if(arguments.length){ // 如果有传进来的参数
          args.push(...arguments); // 添加到数组里
          return arguments.callee; // 返回闭包函数自身
        }
        return args.reduce((n,m)=>{return n+m}); // 否则参数没传进来,就直接执行他
    }
}
console.log(add(1)(2)()); // 3
console.log(add(1,2)(3)(4)()); // 10



相关文章
|
10天前
|
JSON JavaScript 前端开发
Javascript基础 86个面试题汇总 (附答案)
该文章汇总了JavaScript的基础面试题及其答案,涵盖了JavaScript的核心概念、特性以及常见的面试问题。
29 3
|
16天前
|
前端开发 JavaScript
JavaScript 面试系列:如何理解 ES6 中 Generator ?常用使用场景有哪些?
JavaScript 面试系列:如何理解 ES6 中 Generator ?常用使用场景有哪些?
|
2月前
|
JavaScript 前端开发
常见的JS面试题
【8月更文挑战第5天】 常见的JS面试题
53 3
|
2月前
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
29 0
|
2月前
|
JavaScript 前端开发 程序员
JS小白请看!一招让你的面试成功率大大提高——规范代码
JS小白请看!一招让你的面试成功率大大提高——规范代码
|
2月前
|
JavaScript 前端开发 UED
小白请看! 大厂面试题 :如何用JS实现瀑布流
小白请看! 大厂面试题 :如何用JS实现瀑布流
|
2月前
|
存储 JavaScript 前端开发
JS浅拷贝及面试时手写源码
JS浅拷贝及面试时手写源码
|
2月前
|
JavaScript 前端开发
JS:类型转换(四)从底层逻辑让你搞懂经典面试问题 [ ] == ![ ] ?
JS:类型转换(四)从底层逻辑让你搞懂经典面试问题 [ ] == ![ ] ?
|
3月前
|
缓存 JavaScript 前端开发
js高频面试题,整理好咯
中级前端面试题,不低于12k,整理的是js较高频知识点,可能不够完善,大家有兴趣可以留言补充,我会逐步完善,若发现哪里有错,还请多多斧正。
|
3月前
|
JavaScript
JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)
JS【详解】setTimeout 延时(含清除 setTimeout,计时开始时间,0 秒延时解析,多 setTimeout 执行顺序,setTimeout 应用场景,网红面试题)
380 0
下一篇
无影云桌面