#函数表达式

##函数声明和函数表达式的区别

函数的定义有两种形式,一种是函数声明,一种是函数表达式

使用声明时,要注意函数声明提升现象,比如说在if语句中使用声明会出错,但是表达式就不存在这个问题

表达式要在使用前定义,而声明不用

通过声明会获得一个name属性,而表达式中其name为空

function fn() {}
    var fn1 = function() {};
    console.log(fn.name);    //fn
    console.log(fn1.name);    //

##递归调用

下面是一个很常见的递归的使用,进行阶乘:

function fn(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * fn(num - 1);
        }
    }
    console.log(fn(5))    //120

如果我们把这个fn函数赋值给另一个变量,则这个变量中将指向这个函数。

var a = new Object();
    a.say = fn;
    console.log(a.say(5));  //120

函数里面的内容仍然是fn,如果该变这个fn,将会发生有意思的事情:

fn = function (num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * fn(num - 2)
        }
    };
    console.log(a.say(5));    //40
    console.log(fn(5));     //15

在改变fn之后再次调用a.say(),实际上就相当于是在一个函数里面调用了一个外层定义的另外的不同函数而已。并不会让里面的fn变成a.say。

我们会想,这样一直定义这个函数会有些浪费,我把它设置为null,a.say不会变为空,因为他们已经不是指向同一个函数的指针了。

fn = null;
    console.log(a.say(5));    //报错

但是还是会报错,因为a.say方法里面的函数fn已经纬null了.

我们希望a.say方法中会递归调用a.say本身,而不是一直fn,因为不知道后期它会不会有变回。
我们可以用到arguments.callee

function fn1(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * arguments.callee(num - 1);
        }
    }
    var b = new Object();
    b.say = fn1;
    fn1 = null;
    console.log(b.say(5));   //120

看,这样无论fn1怎么变化,都不会再影响到我b.say方法了。

但要注意在严格模式下arguments.callee不能通过脚本访问。我们可以使用**命名函数表达式**

var c = new Object();
    c.say = (function fn2(num) {
        if (num <= 1) {
            return 1;
        } else {
            return num * fn2(num - 1);
        }
    });
    fn2 = null;
    console.log(c.say(5));   //120

这样,即使后面fn2被改动,c.say同样能够实现递归调用自身。

##闭包

闭包的严格定义时“由函数(环境)及其封闭的自由变量组成的集合体”(Node.js开发指南,郭家宝)

我们先看一下这个有趣的例子

function fn() {
        var result = [];
        for (var i = 0; i < 10; i ++) {
            result[i] = function() {
                return i;
            }();
        }
        console.log(result);
    }
    function fn1() {
        var result = [];
        var myarr = [];
        for (var i = 0; i < 10; i ++) {
            result[i] = function() {
                return i;
            };
        }
        for (var j = 0; j < 10; j ++) {
            myarr.push(result[j]());
        }
        console.log(myarr);
    }    
    fn();    //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    fn1();    //[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

从平时的角度来理解:

fn中,通过for循环,每一个result的成员都是得到的一个值;
fn1中,for循环下,每一个result的成员得到的是一个函数。通过对这个函数的调用,才获得一个值。可是为什么得到的结果和fn()不一样呢?

因为每一个result中的i都是从它外层的函数中获得的。fn中,当i=0时函数就执行了,所以它的得到的i的值是当前的0;而在fn1中,对result[j]函数调用时,i都已经是10了,所以它所有的结果都是10;

现在来学习一下作用域链的问题,再从这个角度来解释上面的例子。

当一个函数被**调用**时,会发生:

* 一个执行环境被创建;
 * 响应的作用域链被创建,作用域链保存自函数的内部属性[[Scope]]中,作用域链本质是一个列表,里面是指向不同‘变量对象’的指针。
 * 函数的arguments和this值被获得。
 * arguments和其他命名参数的值初始化了函数的‘活动对象’

在作用域链中,自身函数的活动对象排在第一位,然后是外层函数的活动对象,再是外层的外层,最后是全局执行环境的‘变量对象’。
在函数中访问一个变量,就会从作用域链不同变量对象中去搜索具有相同名字的变量。搜索到了就不往外搜索了。

上面的第一个fn中,并不是在里面创建了一个函数,而是直接执行了一个函数,将它的返回值赋给了result[i];

javascript中函数表达式的问题讨论的更多相关文章

  1. javascript中函数声明和函数表达式的区别 分类: JavaScript 2015-05-07 21:41 897人阅读 评论(0) 收藏

    1.js中函数表达式的定义 表达式(expression)JavaScript中的一个短语,javascript会将其计算(evaluate)出一个结果.程序中的常量是一个最简单的表达式.变量名也是一 ...

  2. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  3. Javascript学习2 - Javascript中的表达式和运算符

    原文:Javascript学习2 - Javascript中的表达式和运算符 Javascript中的运算符与C/C++中的运算符相似,但有几处不同的地方,相对于C/C++,也增加了几个不同的运算符, ...

  4. JavaScript中函数作为另一个函数的参数的时候它存在于哪个作用域

    一直对函数作为参数被传递进另外一个函数理解的不是很清除.先看下这段代码吧: function test(fn){ var bar = 1; fn(); } var bar = 99; test(fun ...

  5. JavaScript中函数的定义!

    JavaScript中函数的定义! 1 自定义函数(命名函数) function fun() {}; 2 函数表达式(匿名函数) var fun = function () {}; 3 利用 new ...

  6. 了解Javascript中函数作为对象的魅力

    前言 Javascript赋予了函数非常多的特性,其中最重要的特性之一就是将函数作为第一型的对象.那就意味着在javascript中函数可以有属性,可以有方法, 可以享有所有对象所拥有的特性.并且最重 ...

  7. JavaScript中函数函数的定义与变量的声明<基础知识一>

    1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...

  8. JavaScript中函数的形参和实参的实现原理剖析

    我们都知道JS里面参数的传递是可以不一样的,比如我们有一个函数: <script type="text/javascript"> function one(a,b,c) ...

  9. JavaScript 中函数节流和函数去抖的讲解

    JavaScript 中函数节流和函数去抖的讲解 我们都知道频繁触发执行一段js逻辑代码对性能会有很大的影响,尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所 ...

随机推荐

  1. Proc、宿主变量、指示变量、数组变量、通信区sqlca,oraca ---(day07)

    PROC 主要内容: ) proc简介 ) proc程序的开发过程 ) 宿主变量和指示变量 ) 嵌入sql语句 ) 连接数据库 ) 错误处理 ) 数据的存取更新操作 ) 动态sql --------- ...

  2. Python-jquery-datatable服务器分页.

    第一步: js初始化: part01:ajax设置 part02:语言设置 part03: 行列设置: part04: 具体渲染设置: 第二部: 服务端设置: 第一部分 获取固定表示: 第二部分 对数 ...

  3. python第十周:进程、协程、IO多路复用

    多进程(multiprocessing): 多进程的使用 multiprocessing是一个使用类似于线程模块的API支持产生进程的包. 多处理包提供本地和远程并发,通过使用子进程而不是线程有效地侧 ...

  4. 在ecshop模板使用自定义函数

    https://blog.csdn.net/shaolinld/article/details/46400485 在ecshop模板使用自定义函数 可以增加自定义函数,在模板直接调用,例如: {$us ...

  5. Navicat Premium 下载地址

    Navicat Premium(32 bit)简体中文版:http://xiazai.formysql.com/trial/navicat_premium_trial.exe Navicat Prem ...

  6. 【ACM】nyoj_2_括号配对问题_201308091548

    括号配对问题时间限制:3000 ms  |  内存限制:65535 KB 难度:3描述 现在,有一行括号序列,请你检查这行括号是否配对. 输入 第一行输入一个数N(0<N<=100),表示 ...

  7. IOS - 查找未使用的图片

    实现细节都在代码里面, 帮助 -h. # -*- coding: utf-8 -*- """ 检查IOS应用图片是否使用 1. 读取有效文件: 图片(.png, .jpg ...

  8. uva live 6827 Galaxy collision

    就是给出非常多点,要求分成两个集合,在同一个集合里的点要求随意两个之间的距离都大于5. 求一个集合.它的点数目是全部可能答案中最少的. 直接从随意一个点爆搜,把它范围内的点都丢到跟它不一样的集合里.不 ...

  9. WndProc函数参数列表

    protected override void WndProc(ref Message m) 实现了这一点. 重写WndProc函数,可以捕捉所有窗口发生的消息.这样,我们就可以"篡改&qu ...

  10. HDU Distinct Values

    /* 一开始想到的是 对于每个区间操作 先按左端点排序(包含的区间 留这打的区间) 我们维护pos表示 a数组找到了哪 对于当前这个区间 只需要找 pos--r这个区间 用set维护能用的数 没放到a ...