函数表达式

在编程时,我们可以看到不管是什么类库,jquery也好,zepto也好,都会用到大量的命名函数和匿名函数表达式,本节点就是为了弄懂为何会有这些函数表达式,以及在什么情况下会使用到这些表达式。

在之前,通过对于javaScript高级程序设计的学习,定义函数的方式有两种

函数声明和函数表达式

首先是函数声明:

  //函数声明
function functionName(arg0,arg1,arg2){}

在这里,有个functionName,FireFox、Safari、Chrome和Opera都给函数定义了一个非标准的name属性,而在ie中不支持这个属性。

而关于函数声明,它的一个重要特征就是函数声明提升,意思是在执行代码之前会先读取函数声明。这就意味着可以把函数声明放在调用它的语句后面。在使用函数声明时,因为没有被标准化的原因,最好不要在Block({...})出现

  sayHi();

  function sayHi(){
alert("Hi!");
}

第二种就是函数表达式,函数表达式有几种不同的语法形式,首先是:

  var functionName = function(arg0,arg1,arg2){}

这种形式看起来好像是常规的变量赋值语句,即创建一个函数并将它赋值给变量functionName的,就叫做匿名函数,匿名函数的name属性是空字符串。

那么,可以看出,在不声明函数名称的情况下,该函数一定是表达式,而如果声明了函数名称的话,则可以通过上下文来区分,如果function是作为复制表达式的一部分的话,那它就是函数表达式,如果function被包含在一个函数体内或处于局域内,则是函数声明。

除了什么时候可以通过变量访问函数这一点区别之外,函数声明与函数表达式的语法其实是等价的。

命名函数表达式

对于命名函数表达式来说,首先要明确为什么需要使用这种方式来定义函数表达式,在现代浏览器里,会有调试器,其中可以给我们写的函数取名并显示,所以命名函数可以方便调试时搞清楚调用栈的顺序,这点在判断bug方向上可能会尤其有效

  //首先举匿名函数实例
function first(){
return second();
}
var second = (function(){
return third();
})(); function third(){
debugger;
}
first();

一共有三次调用,可以看到调用栈中会有两个未知函数。

  function first(){
return second();
}
var second = (function(){
return function second(){
return third();
}
})(); function third(){
debugger;
}
first();



一共有四次调用,但已经可以看到调用顺序。

而在ie的低版本浏览器中,命名函数表达式是可以访问到的

var test = function g(){};
document.write(typeof g);//ie中为function

所以可以使用一种方法

模仿块级作用域

JavaScript没有块级作用域的概念,因为JavaScript从来都不会告诉我们是否多次声明了同一个变量,所以需要在使用时多加注意。

function output(){
for(var i=0;i<3;i++){
document.write(i);
} document.write(i);
}
//012 3

而使用匿名函数可以来模仿块级作用域:

(function(){
//块级作用域
})();

以上代码定义并立即调用了一个匿名函数,将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。

而之所以不能使用

function(){
//
}();

则是因为JavaScript将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号,而函数表达式的后面就可以跟圆括号,这些定义在匿名函数中的变量,都会在执行结束时被销毁(没有指向匿名函数的引用)。

zepto

没有块级作用域

主要是其它语言的花括号封闭的代码块,都有自己的作用域(在外部无法访问到内部定义的变量),但javaScript则不会有这种结果;

if(true){
var i=0;
}
console.log(i);// 0

只有执行环境,而没有块级作用域,是javaScipt的特点(缺点?)

闭包

闭包是指有权访问另一个函数作用域中的变量的函数.因为JavaScript的函数内部所定义的变量实际上都处于局部环境中,在函数执行完毕之后就会被销毁,而如果不想让其中的变量销毁,则需要保持对其内部函数的引用.

demo1:如何判断变量被销毁?

// 如果每次使用函数,其返回值都一样,则说明该变量是在执行完之后就被销毁了
function demo1(){
var i=0;
return i;
} console.log(demo1());// 0;
console.log(demo1());// 0; function demo2(){
var i=0;
return function(){
return i++;
}
}; var a = demo2();
console.log(typeof a);// func
console.log(a());// 0
console.log(a());// 1

当然,使用闭包也需要注意,因为javaScript的链式调用,实际上,能够请求到的局部变量的状态始终都是最后一个.

还要注意,闭包的this对象是指执行环境的this,而不是能够访问的函数的this.

小结

该章节主要讲述了本人对于函数表达式的相关认知;开始整理一年来的收获与总结。

javascipt的【函数表达式】的更多相关文章

  1. 立即执行函数表达式(IIFE)

    原文地址:benalman.com/news/2010/11/immediately-invoked-function-expression/ 译者:nzbin 也许你还没有注意到,我是一个对术语比较 ...

  2. JavaScript 函数表达式

    JavaScript中创建函数主要有两种方法:函数声明和函数表达式.这两种方式都有不同的适用场景.这篇笔记主要关注的是函数表达式的几大特点以及它的使用场景,下面一一描述. 主要特点 可选的函数名称 函 ...

  3. JavaScript函数表达式、闭包、模仿块级作用域、私有变量

    函数表达式是一种非常有用的技术,使用函数表达式可以无需对函数命名,从而实现动态编程.匿名函数,是一种强大的方式,一下总结了函数表达式的特点: 1.函数表达式不同于函数声明,函数声明要求有名字,但函数表 ...

  4. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  5. js立即调用的函数表达式

    1.多种实现 // 下面2个括弧()都会立即执行 (function () { /* code */ } ()); // 推荐使用这个 (function () { /* code */ })(); ...

  6. 深入理解javascript系列(4):立即调用的函数表达式

    本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...

  7. 一步步学习javascript基础篇(6):函数表达式之【闭包】

    回顾前面介绍过的三种定义函数方式 1. function sum (num1, num2) { return num1 + num2; }  //函数声明语法定义 2. var sum = funct ...

  8. javascript中函数声明和函数表达式浅析

    记得在面试腾讯实习生的时候,面试官问了我这样一道问题. //下述两种声明方式有什么不同 function foo(){}; var bar = function foo(){}; 当初只知道两种声明方 ...

  9. JavaScript函数表达式

    函数表达式的基本语法形式 var functionName = function(arguments){ //函数体 } 递归建议 我们通过例子来一步步说明,递归的最佳实现方式.下面是普通递归调用的例 ...

随机推荐

  1. python中的TypeError错误解决办法

    新手在学习python时候,会遇到很多的坑,下面来具体说说其中一个. 在使用python编写面向对象的程序时,新手可能遇到TypeError: this constructor takes no ar ...

  2. Effective java笔记(一),创建与销毁对象

    1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...

  3. 单台机器配置redis多实例

    1.增加/usr/local/redis/etc中拷贝一份配置文件重新命名为redis6483.conf 2.编辑redis6483.conf daemonize yes  //以后台进程启动 pid ...

  4. 解决ngnix服务器上的Discuz!x2.5 Upload Error:413错误

    1.修改php.ini sudo nano /etc/php5/fpm/php.ini #打开php.ini找到并修改以下的参数,目的是修改上传限制 max_execution_time = 900 ...

  5. Microsoft Dynamics CRM 2013 Js Odata 查询

    实现功能:   在新建记录时,(大区,省区,城市)的值默认为当前用户的值.tips:字段均为lookup类型; function Default_region(){ var fromtype=Xrm. ...

  6. SharePoint 2013 新手注意事项总结[不断更新ing]

    前言 最近自己的QQ群里,经常有新加入的人,带着一些很入门的问题进行提问,这里,自己也总结总结,入门会经常碰到那些问题,希望能够带给入门的人以帮助. 1. SharePoint搭建环境 大家可以参考下 ...

  7. Android 防止控件被重复点击

    转载: 工具类: public class Utils { private static long lastClickTime; public static boolean isFastDoubleC ...

  8. Android开发学习—— Service 服务

    Service运行于后台的一个组件,用来运行适合运行在后台的代码,服务是没有前台界面,可以视为没有界面的activity. 服务可以被手动关闭,不会重启,但是如果被自动关闭,内存充足就会重启. sta ...

  9. 面向初学者之烦人的mainactivity启动前的actionBAR

    相信各位初学者的童鞋都遇到过一个问题,(大神们就别喷我哦,多多帮帮指正,嘿嘿)那就是当你点开你开发的软件或者是dome时,会发现这么一个问题: 你曾今以为你的软件点开的时候是这样的: 然而事实是残酷的 ...

  10. gitflow以及git

    git大概只会用常用的那几个命令,自己用的最多的也只是add commit push pull之类的,然后那天电话面试问我版本回退怎么办我都忘记了. 然后又看了看教程,此时想起来做项目的时候师兄说的g ...