js 函数闭包内部返回函数体调用方法难点解答

时间:2022-06-10 06:49:56

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

var add = function(x){
var sum = 1;
var tmp = function(x){
sum = sum + x;
return tmp;
}
tmp.toString = function(){
return sum;
}
return tmp;
} // alert(add(1)(2)(3)) --> 6

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

之所以写这篇文章是因为,在那里面有一点让我感到奇怪,那就是最后的调用方式

add(1)(2)(3)  

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

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

function create1(pro) {
console.log("pro : " + pro);
return function(obj1, obj2){
console.log(obj1 + " -- " + obj2);
return obj1 + obj2;
}
}

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

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

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

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

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

这样就打印出了下面的日志;这说明其实我们一开始调用方法的时候,其实是并没有进入到里层的函数的,只是进入了外层函数体,

我们只有再调用才能进入里层函数体,并且这个时候,我们重复上面的调用,他只会是调用里层的函数体,并没有外面的函数体。

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

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

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

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

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

最后是调用:

var c1 = create2("pro");   

查看日志:

pro = pro
‌Uncaught ReferenceError: obj1 is not defined 会发现,打印出了一条日志后,接着抛出了异常。对方法做一下改动, function create2(pro) {
console.log("pro = " + pro);
var obj1 = 1, obj2 = 2;
return infun(obj1, obj2); // 这个时候,在内部设了传的变量,则不报错了,事实是调用了外面已经声明过的函数,ifun(obj1,obj2),而obj1与obj2两个传参变量由于是在调用已声明过的ifun函数,所以不能当做声明的传参变量,
                  //只当传参的字符串变量(准确点应该说,与obj1 obj2这两变量名本身没任何关系了,名字可以为任何变量名,前提是已经声明过赋过值),而函数内部和全局都未定义这两变量的值,所以抛出异常,is not defined 
}

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

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

// 声明一个函数表达式
var add = function(x){
var sum = 1;
// 在函数表达式内部有一个求和的内部函数
var tmp = function(x){
sum = sum + x;// 求和
return tmp;
}
// 构建一个函数体的toString()函数
tmp.toString = function(){
return sum;
}
return tmp; // 返回的是一个函数体,如果该函数体有toString()方法,则会调用函数体的toString()方法
}

然后再来看看调用:

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

重点:add(1)(2)(3) 
1、函数add(1)第一次调用,其实是只声明了 var sum=1;这个变量,然后返回了tmp函数体,用于后面调用tmp函数
2、函数add(1)(2)第二次调用才真正的把参数传进来使用了,即第一次传的 1 是没地方用的,没意义,第二次传的 2 是给第一次返回的tmp函数体传的参、即用在sum=sum+x上----sum=1+2
3、函数add(1)(2)(3)第三次调用和第二次一样,由于tmp函数体内部 return tmp  返回了本身,所以后面可以继续调用tmp函数,也就是除第一次调用传参无效外,后面可以调用无数次,sum值会不断累加
4、toString是tmp函数体附带的属性方法函数,会随着主体函数toString执行一次调用一次

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

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

js 函数闭包内部返回函数体调用方法难点解答的更多相关文章

  1. js函数常见的写法以及调用方法

    写在前面:本文详细的介绍了5中js函数常见的写法以及调用的方法,平时看别人代码的时候总是看到各种不同风格的js函数的写法.不明不白的,找了点资料,做了个总结,需要的小伙伴可以看看,做个参考.1.常规写 ...

  2. (转)在网页中JS函数自动执行常用三种方法

    原文:http://blog.sina.com.cn/s/blog_6f6b4c3c0100nxx8.html 在网页中JS函数自动执行常用三种方法 在网页中JS函数自动执行常用三种方法 在HTML中 ...

  3. js函数的各种写法与调用

    以下是我见过的各种js函数的各种写法以及调用,虽然有些写法及其调用我不清楚其专业术语叫啥,但并不影响我写一个总结笔记. 我们刚开始接触js语音,经常看到的这种名叫“使用function关键字来定义函数 ...

  4. 【微信小程序】在js中导入第三方js或自己写的js,使用外部js中的function的两种方法 import和require的区别使用方法 【外加:使用第三方js导出的默认function的调用方法】

    如下 定义了一个外部js文件,其中有一个function import lunaCommon from '../lunaCommon.js'; var ctx = wx.getStorageSync( ...

  5. 在网页中JS函数自动执行常用三种方法

    在网页中JS函数自动执行常用三种方法 在HTML中的Head区域中,有如下函数: <SCRIPT   LANGUAGE="JavaScript">   function ...

  6. 三个JS函数闭包(closure)例子

    闭包是JS较难分辨的一个概念,我只是按自己的理解写下来,如有不对还请指出. 函数闭包是指当一个函数被定义在另一个函数内部时,这个内部函数使用到的变量会被封闭起来形成一个闭包,这些变量会保持形成闭包时设 ...

  7. JS总结之一:字符串的调用方法

    字符串的调用方法:var s="hello, world";document.write(s.charAt(0)); //第一个字符document.write(s.charAt( ...

  8. 关于js函数闭包的理解

    在开始之前我们先来了解一下函数的变量作用域 JavaScript 变量可以是局部变量或全局变量. 私有变量可以用到闭包. 全局变量 函数可以访问由函数内部定义的变量,如: 实例1 function m ...

  9. js函数 test&period;caller 谁在调用test函数

    返回调用指定函数的函数. function test() { if (test.caller === null) console.log('test 函数在全局调用'); // 获取调用 test函数 ...

随机推荐

  1. C标准头文件&lt&semi;string&period;h&gt&semi;

    里面主要包含了一些与字符串关联的函数的声明,这些函数有如下的命名规则: 以"mem"开头的函数操作任意的字符序列 以"strn"开头的函数操作非空字符序列 以& ...

  2. jmeter(五)Sample之JDBC Request

    jmeter中取样器(Sampler)是与服务器进行交互的单元.一个取样器通常进行三部分的工作:向服务器发送请求,记录服务器的响应数据和记录相应时间信息 有时候工作中我们需要对数据库发起请求或者对数据 ...

  3. 常用加密算法的Java实现总结

    常用加密算法的Java实现(一) ——单向加密算法MD5和SHA 1.Java的安全体系架构 1.1           Java的安全体系架构介绍 Java中为安全框架提供类和接口.JDK 安全 A ...

  4. sqlserver关于对列的权限控制

    -- 脚本新建登录数据库的用户 USE [master]GOCREATE LOGIN [sa1] WITH PASSWORD=N'123456', DEFAULT_DATABASE=[master], ...

  5. 曲面Shader

    这是一个能让平面呈现出曲面效果的Shaer. 代码: Shader "Custom/CurvedWorld"{ Properties { // Diffuse texture _M ...

  6. 伺服驱动器UVW电机电源线相序错误

       我们有必要先了解此讨论的前提:编码器初始安装相位正确.伺服驱动器将全然"採信"电机编码器的初始安装相位所表征的电机电角度相位,无需在伺服电机 的UVW动力线接线连接后进行额外 ...

  7. 【续】强行在C&num; Winform中渲染Cocos2d-x 3&period;6

    [前言] 上一篇讲了怎么把Cocos2d-x 3.6渲染进MFC窗体,这里来讲一下怎么在C# Winform中做到同样的功能.如果你不熟悉MFC的使用但对C# Winform比较在行,请往下看. 这一 ...

  8. 架设WIN32汇编程序的开发环境

    笔者在学习Windows下的图形界面应用程序(GUI,Graphical User Interface)的时候碰到的第一个麻烦就是架设WIN32汇编程序的开发环境,在这里笔者愿意和大家分享这段经历. ...

  9. 楼梯T-SQL:超越基础6级:使用CASE表达式和IIF函数

     从他的楼梯到T-SQL DML,Gregory Larsen涵盖了更多的高级方面的T-SQL语言,如子查询. 有时您需要编写一个可以根据另一个表达式的评估返回不同的TSQL表达式的单个TSQL语句. ...

  10. 从零开始学习前端JAVASCRIPT — 2、JavaScript基础ES5

    1:ES5简介 ECMAScript 5.1 (或仅 ES5) 是ECMAScript(基于JavaScript的规范)标准的修正. 与HTML5规范进程本质类似,ES5通过对现有JavaScript ...