前言:“函数是对象,函数名是指针。”,函数名仅仅是指向函数的指针,与其他包含函数指针的变量没有什么区别,话句话说,一个函数可能有多个名字。

-1.函数声明,function+函数名称。调用方法:函数名(参数);

function f1(x,y){
return x+y; //函数体
}
console.log(f1(2,3));

这是最常见的指定函数名声明函数,在函数体内返回参数值,函数调用时才会输出结果。既然说到函数,那就免不了提一提它的预解析以及作用域。

此类方法定义的函数,在代码开始执行之前会通过解释器进行一个函数声明提前的过程,并将其添加到执行环境中, JavaScript 引擎会将其提升到代码树的顶端,率先执行,所以即使声明函数的代码在函数调用代码的后面,也能正确访问,上述过程就被称为函数的预解析。例如:

console.log(sum);          //控制台输出函数源代码,证明函数可以被调用
console.log(sum(3,2)); //
function sum(x,y){
return x+y;
}

执行环境定义了变量或者函数有权访问其他数据,每个环境中都有一个与之关联的变量对象,环境中定义的变量和函数都保存在这个对象中,解析器在处理数据时就会使用这个对象。

- 2.匿名函数,即没有命名的函数,通过给将函数赋值给变量的形式声明函数,也称之为函数表达式。调用方法:函数名(参数);

var f2 = function(x,y){
return x+y;
}
f2(4,5);

此类方法定义的函数不能在函数声明前调用函数,因为在预解析机制中:

1.把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。

2.把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。

3.先提升var,在提升function

所以上述代码如果提前调用函数,在预解析的执行环境中是:

var f2;       //变量声明提升,但赋值没有
f2(4,5); //报错
console.log(f2(4,5));
f2 = function(x,y){
return x+y;
}

匿名函数是用一个变量去接收函数,因此预解析只将变量的声明提前了,此时的函数位于一个初始化语句中,在执行到函数体代码之前变量不会保存对函数的引用,所以直接报错。

-3.自调用函数,顾名思义就是自己调用自己的函数,在声明的同时进行调用,虽然方便但只能执行一次。

(function(){
console.log("这是一个自调用函数");
})();
/*
*
* 而它的演变过程也很简单,是由函数表达式演变而来。
* var f1 = function(){
* console.log("这是一个自调用函数");
* }
* f1();
* 这里把调用时的 f1 替换成 function(){}
* 所以调用时就是function(){}();
* 为了保持代码的整体性,所以在最外层加了一个括号。
*
* */ //这里还有一个点需要注意,自调用函数前的一个函数如果没有输出调用,需要在函数表达式的结尾加上分号,以和自调用函数区分开来,防止将上一个函数也解析成自调用函数。

-4.Function 构造函数,Function 构造函数可以接受任意数量的参数,但最后一个参数始终被看做是函数体,而前面则看作是函数体的参数。调用:函数名();

var sum = new Function("sum1","sum2","return sum1+sum2");

但这种定义函数的方法并不推荐使用,因为在此类函数在执行时会先解析一次常规ECMAscript 代码,再解析传入函数中的字符串,反复调用时将会影响性能。

函数也是有数据类型的,所有函数的类型都是 function 。

关于作用域链

作用域链的用途是,保证执行环境中,有权访问的所有函数和变量的有序访问。简单来说就是变量的使用范围。

全局变量:在函数以外,用 var 声明的变量都是全局变量,在全局执行环境中都可以使用。 !!! 但需要注意,全局变量只有在整个程序退出或者销毁后才会被释放,否则就一直占内存。

局部变量:在函数内部定义的变量就是局部变量,只能在函数内部使用。

隐式全局变量:没有var 声明的,也是作用于全局,但是可以使用delete删除。

全局作用域:全局变量的使用范围,始终是作用域链中的最后一个对象。

局部作用域:局部变量的使用范围。

块级作用域:指的是在一对大括号内声明的变量,就只能在这对大括号中使用,但是js中全部都可以使用,所以js没有块级作用域,函数除外。

使用过程:1.作用域链的前端始终是当前执行代码所在环境的变量对象,解析过程是按照作用域链一级一级搜索的过程。

     2.始终是从作用域的前端开始的,然后逐级向后回溯。

     3.内部变量可以通过作用域链访问外部变量,但外部变量不能访问任何内部的变量或者函数。(自内向外访问)

最后给大家举个栗子,综合解说函数调用、预解析以及作用域:

f1();
console.log(c);
console.log(b);
console.log(a);
function f1(){
   var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}

输出的结果为:9  9  9  9  9  报错,原因如下

function f1(){
// var a = b = c = 9; 变量的声明也提升
var a;
a = 9; // 此时的 a 是被 var 声明的,作为函数内的局部变量,只能在函数内被调用,所以最后的a会报错
b = 9;
c = 9; // b,c 则是隐式全局变量
console.log(a);
console.log(b);
console.log(c);
}
f1(); //调用f1函数,预解析后f1函数的声明提升到作用域的最前面,此时的代码为
console.log(c);
console.log(b);
console.log(a); 

第二个小栗子

f1();
var f1 = function (){
console.log(a);
var a = 10;
};
//结果是报错
//因为预解析的存在,所以函数和变量提前
//由于是函数表达式的形式,所以预解析后的代码为: // var f1;
// f1();
// function (){
// console.log(a);
// var a = 10;
// };

  

最新文章

  1. double 和 float
  2. WordPress基础:小工具的使用
  3. Structs2配置文件相关说明
  4. .net程序员转行做手游开发经历(二)
  5. JavaScript一些函数
  6. IE firefox 兼容性整理
  7. 读<你必须知道的.NET>IL指令笔记
  8. plot a critical difference diagram , MATLAB code
  9. [Java Web – Maven – 1A]maven 3.3.3 for windows 配置(转)
  10. jquery调用页面的方法
  11. Thinking in scala (8)---- 乘幂计算
  12. SpringAop源码情操陶冶-JdkDynamicAopProxy
  13. controller层中,参数的获取方式以及作用域的问题
  14. Mybatis增删改查,Demo整合
  15. IIS部署Angular2
  16. Commander
  17. 修改XAMPP的默认根目录
  18. k8s网络之calico
  19. django基于中间件的IP访问频率控制
  20. ubuntu jdk 安装

热门文章

  1. python 教程 第十八章、 Web编程
  2. WPF中使用cefsharp
  3. 隐藏在QRCode二维码背后的秘密
  4. EF CodeFirst的步骤
  5. nodejs timer block-timer timer-ease
  6. VC中出现“烫”和“屯”的原因(栈区的每一个字节都被0xCC填充了,也就是int 3h的机器码,动态分配的堆,VC的Debug用0xCD填充堆的空间,就出现了“屯”)
  7. git/github初级运用自如 (good)
  8. workerman源码分析之启动过程
  9. Win8Metro(C#)数字图像处理--2.18图像平移变换
  10. Qt在Windows上的调试器CDB安装与配置