javascript函数学习

1、关于嵌套函数

函数只可以在JS顶层代码中或嵌套在其他函数定义中,不可以出现在if或循环等其他语句中。从本质来说function并非一个语句,因为语句是动态的,是解释执行的。而函数定义是静态的,在代码被开始执行前,JS就会将函数解析并作为属性存储(如果是顶层函数则存于全局变量,嵌套函数则存入所嵌套的对象中)。

 

以上为关于犀牛书第五版P133-8.1.1的解释

 

2、可变长度的参数列表:Arguments对象

Arguments对象是一个类似数组的对象,可以按照数目获取传递给函数的参数值。Arguments对象也定义了callee属性,用来引用当前正在执行的函数。

函数内arguments标识符表示了Arguments对象,arguments.length表示了实际传递给函数的参数的个数,可以通过

arguments[0],arguments[1]....来调用参数。利用该特性,可以在函数定义时不指定参数个数,在函数内部通过arguments属性来获取参数,例如:

function max(){
  var m = Number.NEGATIVE_INFINITY;
  for(var i=0; i<arguments.length;i++){
    if(arguments[i]>m){
      m=arguments[i];
    }
  }
  return m;
}

// 调用
var largest = max(1, 10, 27, 100000, 8, 99, 80);

 当函数具有命名了的参数时,Arguments对象和命名了的参数不过是引用同一变量的两种不同方法,用参数名改变一个参数的值同时会改变通过arguments[]数组获取的值,反之亦然。

 

3、作为数据的函数

在JavaScript中函数还可以作为数据,这意味着能够把函数赋给变量,存储在对象的属性中或存储在数组的元素中,作为参数传递给函数等等。可以将定义了的函数赋值给其他变量或对象的属性,在这种情况下,函数成为方法。

 

4、作为方法的函数

函数可以赋值给对象的任何属性,例如:

 

o.m=f;
o.m();

 在方法体中,用来调用方法的对象成为关键字this的值,也就是说,当调用o.m()时,方法体可以使用this关键字来引用对象o。任何用作方法的函数都被有效地传递了一个隐式的参数,即调用函数的对象。

当一个函数作为函数而不是方法调用的时候,这个this关键字引用全局对象。

 

5、构造函数

构造函数是初始化一个对象的属性并且专门和new运算符一起使用的一个函数。

 

6、函数的属性和方法

每个函数都有一个prototype属性,它引用的是与定义的原型对象,原型对象在使用new运算符把函数作为构造函数时起作用。

方法apply()和call()

f.call(o, 1, 1);
//等价于
o.m=f;
o.m(1, 2);
delete o.m;

f.apply(o, [1,2]);

 

 

7、函数的作用域和闭包

先了解词法作用域,javascript中的函数是通过词法来划分作用域的,而不是动态地划分作用域的。这意味着,函数在定义它们的作用域里运行,而不是在执行他们的作用域里运行。

当js解释器调用一个函数,它首先将作用域设置为定义函数的时候起作用的那个作用域链,接下来,它在作用域的前面添加一个新的对象,这叫做调用对象。这个调用对象的一个属性被初始化成一个名叫 arguments 的属性,它引用了这个函数的 Arguments 对象,Arguments 对象是函数的实际参数。所有用 var 语句声明的本地变量也被定义在这个调用对象里。这个时候,调用对象处在作用域链的头部,本地变量、函数形式参数和 Arguments 对象全部都在这个函数的范围里了。当然,这个时候本地变量、函数形式参数和 Arguments 对象就覆盖了作用域链里同名的属性。

 

8、作为闭包的嵌入函数

javascript允许嵌入的函数,允许函数用作数据,并且使用词法作用域,这些因素互相交互,创造了惊人的和强大的效果。

当嵌入的函数在它们定义的同一个词法作用域里调用的时候,它们是很好理解的,并且不会有任何惊人之处,例如:

var x = "global";
function f(){
  var x = "local";
  function g(){alert(x);}
  g();//g在定义的词法作用域中被调用
}
f();// f也在定义的词法作用域中被调用

 

然而,在javascript中,函数和其他值一样,也是数据,因此,它们可以从函数返回,被赋给对象属性,存储在数组中,等等。除非涉及嵌入的函数,这也不会导致什么令人吃惊的事情,考虑如下代码,其中包含了一个函数,它返回一个嵌套的函数。

当定义了局部作用域的函数退出的时候,期待局部作用域能够种植并退出,也就是说,实际上这正是通常所发生的情况。当一个函数被调用的时候,就为它创建了一个调用对象并放置到作用域链中。当该函数退出的时候,调用对象也从作用域链中移除。当没有涉及到嵌套的函数的时候,作用域链是对调用对象的唯一引用,当对象从链中移除了,也就没有对它的引用了,最终通过对它的垃圾收集而完结。

但是嵌套函数改变了这一情景。如果创建了一个嵌套的函数,这个函数的定义引用了调用对象,因为调用对象在这个函数所定义的作用域链的顶端。可是如果嵌套函数只是在外围函数内部使用,那么对嵌套函数的唯一的引用在调用对象之中。当外围函数返回的时候,嵌套的函数引用了调用对象,并且调用对象引用了嵌套的函数,但是,没有其他的东西引用他们二者,因此,对这两个对象都可以进行垃圾收集了。

如果把对嵌套的函数的引用保存到一个全局的作用域中,情况又不相同了。使用嵌套的函数作用外围函数的返回值,或者把嵌套函数的函数存储为某个其他对象的属性来做到这一点,在这种情况下,有哦一个对嵌套的函数的外部引用,并且嵌套的函数将它的引用保留给外围函数的调用对象。结果是,外围函数的一次特定调用的调用对象亦然存在,函数的参数和局部变量的名字和值在这个对象中得以维持。javascript代码不会以任何方式直接访问调用对象,但是它所定义的属性是对嵌入函数任何调用的作用域链的一部分。js函数是将要执行的代码以及执行这些代码的作用域构成一个综合体,在计算机科学术语里,这种代码和作用域的综合体叫做闭包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值