今天在网上,看到一篇关于js函数难点的文章,js函数的一些难点。在那上面提了一下,关于js函数返回另一个函数的问题,并附上了一道面试题:

  1. var add = function(x){
  2. var sum = 1;
  3. var tmp = function(x){
  4. sum = sum + x;
  5. return tmp;
  6. }
  7. tmp.toString = function(){
  8. return sum;
  9. }
  10. return tmp;
  11. } // alert(add(1)(2)(3)) --> 6

接下来,就来详细的解读返回另一个函数的问题。

其实我是从Java转过来的,一开始看到那篇文章,我对于返回另一个函数并没有什么认识,我之所以写这篇文章是因为,在那里面有一点让我感到奇怪,那就是最后的调用方式

  1. add(1)(2)(3)

由于在java中,我没有见到过这样的函数调用方式,所以引起了我的注意,我决定去研究研究;下面就将我的研究分享出来,当然如果你对此已经有了深刻的认识,你可以选择跳过,或者对于不足的地方,给出指点。好了闲话不多说,进入正题。

我们来看一个最简单的例子:

  1. function create1(pro) {
  2. console.log("pro : " + pro);
  3. return function(obj1, obj2){
  4. console.log(obj1 + " -- " + obj2);
  5. return obj1 + obj2;
  6. }
  7. }

我构建了一个简单的函数create1,并且有一个返回值,返回值是一个内部函数。函数构建完了,接下来进行调用:

  1. var c1 = create1("pro"); // 创建函数

如果按照我之前的理解,当我调用了这个方法后,应该会打印出 pro : pro,接着然后报错的。如果你看完过后,也跟我有一样的想法,那恭喜你想多了或者有了固型思维

。真实的是当我们通过上面的代码调用的时候,日志是打印出了  pro : pro ,但是并没有报错,并且我们反复来回的调用过后,也只是来回的打印相同的日志。这也就说明这个时候,只是进入了create1()方法,并没有进入到该函数的内部函数内。通过面试题的启发,我在试着调用了一次,发现打印出了后续的。

  1. c1(1, 2); // 调用函数

这样就打印出了下面的日志;这说明其实我们一开始调用方法的时候,其实是并没有进入到里层的函数的,只是进入了外层函数体,我们只有再调用才能进入里层函数体,并且这个时候,我们重复上面的调用,他只会是调用里层的函数体,并没有外面的函数体。

类似这种函数返回另一个函数的,我们第一次调用只是构建了一个外层函数体对象,只有有后续的调用,才能调用内层函数体,并且重复调用,只会重复内层函数体。
不要急,还没有完,后面还有……

接下来,我们看一看另一种情况,我们先声明一个函数,用来做加法运算:

  1. function infun(obj1, obj2) {
  2. console.log(obj1 + " -- " + obj2);
  3. return obj1 + obj2;
  4. }

然后再声明一个函数,在该函数中调用上面声明的函数:

  1. function create2(pro) {
  2. console.log("pro = " + pro);
  3. return infun(obj1, obj2); // 这个时候,会报错
  4. }

最后是调用:

  1. var c1 = create2("pro");

查看日志:

pro = pro
‌Uncaught ReferenceError: obj1 is not defined

会发现,打印出了一条日志后,接着抛出了异常。对方法做一下改动,

  1. function create2(pro) {
  2. console.log("pro = " + pro);
  3. var obj1 = 1, obj2 = 2;
  4. return infun(obj1, obj2); // 这个时候,会报错
  5. }

在调用会发现正常运行,并且打印出了两条日志记录。

这说明,类似于这种,在一个函数内返回一个已经声明的函数,其实是调用已经声明的函数,跟上面的情况是不一样的。
好了,现在回过头来,仔细看看开头的面试题,就会发现一切都明了了:

  1. // 声明一个函数表达式
  2. var add = function(x){
  3. var sum = 1;
  4. // 在函数表达式内部有一个求和的内部函数
  5. var tmp = function(x){
  6. sum = sum + x;// 求和
  7. return tmp;
  8. }
  9. // 构建一个函数体的toString()函数
  10. tmp.toString = function(){
  11. return sum;
  12. }
  13. return tmp; // 返回的是一个函数体,如果该函数体有toString()方法,则会调用函数体的toString()方法
  14. }

然后再来看看调用:

  1. alert(add(1)(2)(3))

结果为6,至于原因就跟我们第一种讨论的情况一样,接下来,我们反复调用:

  1. // 以下结果输出为:6
  2. alert(add(10)(2)(3))
  3. alert(add(100)(2)(3))
  4. // 下面的结果输出变了
  5. alert(add(1)(3)(3))
  6. alert(add(1)(2)(5))

js fuction函数内return一个内部函数详解的更多相关文章

  1. JavaScript中return的用法详解

    JavaScript中return的用法详解 最近,跟身边学前端的朋友了解,有很多人对函数中的this的用法和指向问题比较模糊,这里写一篇博客跟大家一起探讨一下this的用法和指向性问题. 1定义 t ...

  2. Spark2.1.0——内置Web框架详解

    Spark2.1.0——内置Web框架详解 任何系统都需要提供监控功能,否则在运行期间发生一些异常时,我们将会束手无策.也许有人说,可以增加日志来解决这个问题.日志只能解决你的程序逻辑在运行期的监控, ...

  3. Spark2.1.0——内置RPC框架详解

    Spark2.1.0——内置RPC框架详解 在Spark中很多地方都涉及网络通信,比如Spark各个组件间的消息互通.用户文件与Jar包的上传.节点间的Shuffle过程.Block数据的复制与备份等 ...

  4. vue.js循环for(列表渲染)详解

    vue.js循环for(列表渲染)详解 一.总结 一句话总结: v-for <ul id="example-1"> <li v-for="item in ...

  5. Angular.js中处理页面闪烁的方法详解

    Angular.js中处理页面闪烁的方法详解 前言 大家在使用{{}}绑定数据的时候,页面加载会出现满屏尽是{{xxx}}的情况.数据还没响应,但页面已经渲染了.这是因为浏览器和angularjs渲染 ...

  6. js正则实现二代身份证号码验证详解

    js正则实现二代身份证号码验证详解 根据[中华人民共和国国家标准 GB 11643-1999]中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成.排列顺序从左至 ...

  7. vue.js选择if(条件渲染)详解

    vue.js选择if(条件渲染)详解 一.总结 一句话总结: v-if <!DOCTYPE html> <html lang="en"> <head& ...

  8. js keyup、keypress和keydown事件 详解

    js keyup.keypress和keydown事件  详解 js keyup.keypress和keydown事件都是有关于键盘的事件 当一个按键被pressed 或released在每一个现代浏 ...

  9. (转载)--SG函数和SG定理【详解】

    在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念:        P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败.        N点:必胜点 ...

随机推荐

  1. C# System.Reflection (反射)

    在使用.NET创建的程序或组件时,元数据(metadata)和代码(code)都存储于“自成一体”的单元中,这个单元称为装配件.我们可以在程序运行期间访问这些信息. 在System.Reflectio ...

  2. luogu P1758 [NOI2009]管道取珠

    luogu 这个题中的平方有点东西,考虑他的组合意义,也就是做这个过程两次,如果两次得到的结果一样就给答案+1,所以可以考虑dp,设\(f_{i,j,k,l}\)表示第一个过程中上面取到的第\(i\) ...

  3. {经典}springmvc+mybatis+restful+webservice Jeesz分布式架构

    框架简介--主要定位于互联网企业架构,已内置企业信息化系统的基础功能和高效的代码生成工具,包括:系统权限组件.数据权限组件.数据字典组件.核心工具 组件.视图操作组件.工作流组件组件.代码生成等.采用 ...

  4. vue 列表渲染 v-for

    1.数组列表       v-for 块中,我们拥有对父作用域属性的完全访问权限.v-for 还支持一个可选的第二个参数为当前项的索引 1.1 普通渲染       v-for="item ...

  5. MATLAB仿真 让波形动起来

    dt=1e-6;T=2*1e-3;for N=0:500; t=N*T+(0:dt:T); input=2*cos(2*pi*1005*t); carrier=5*cos(2*pi*(1e4)*t+0 ...

  6. Linux系统账户管理指令

    sudo passwd -l weblogic 锁定账户 sudo passwd -u weblogic 解锁账户 useradd weblogic -p xxxxx 添加账户指定密码 sudo us ...

  7. 021-Zabbix4.2对IIS监控摸索记录

    Zabbix是很强大,但是相关的细节技术文档貌似很少,摸索之路就显得异常难. 度娘搜了下,关于Zabbix对IIS的监控资料确实有,确实也讲如何操作了,但是细细按照对方的要求操作下,总是缺数据,no ...

  8. 使用 Maven Profile 和 Filtering 打各种环境的包(转)

    http://tunzao.me/articles/maven-profile/ https://blog.csdn.net/syani/article/details/52237470

  9. SpringBoot 1.x 之入门

    1 SpringBoot简介 SpringBoot简化Spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用. 背景: J2EE笨重的开发.繁多的配置.低下的 ...

  10. /etc/sysconfig/network-scripts/ifcfg-ens33

    因为最近重新搭建CDH集群: DEVICE     接口名(设备,网卡) USERCTL    [yes|no](非root用户是否可以控制该设备) BOOTPROTO  IP的配置方法[none|s ...