【FE学习-JS】函数
概述⁍
声明方法⁍
- 普通方法
- 赋值语句(将 匿名函数 赋值给某个变量)
第一等公民⁍
JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。
1 |
|
函数名提升与重复声明⁍
- 用赋值语句定义的函数 不能 在调用前声明,因为变量提升到前面后并未赋值,相当于
undefined
- 采用
function
命令和var
赋值语句声明同一个函数,由于存在函数提升,最后会采用var
赋值语句的定义。- 而一般情况下,重复声明,后面声明的会覆盖前面的
属性和方法⁍
name
属性:函数的名字/匿名函数声明时赋给的变量名- 可以用于获取传入的参数函数的名字
length
属性:返回 定义 的参数个数- 如果是剩余参数
...args
,则会返回0
- 如果是剩余参数
toString()
方法返回一个字符串,内容是函数的源码。- 函数内部的注释也可以返回。利用这一点,可以变相实现多行字符串。[1]
- 对于那些原生的函数,
toString()
方法返回function (){[native code]}
。
函数作用域scope⁍
- 全局作用域
- 函数作用域
- 块级作用域(ES6新增)
函数作用域内部也会产生“变量提升”现象。var
命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
参数⁍
参数的省略⁍
没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined
。
传递方式⁍
变量p
是一个原始类型的值,传入函数f
的方式是传值传递。
如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。
如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。(重新对o
赋值导致o
指向另一个地址,保存在原地址上的值当然不受影响。)
同名参数⁍
如果有同名的参数,则取最后出现的那个值。
arguments对象⁍
arguments
对象包含了函数运行时的所有参数,arguments[0]
就是第一个参数,arguments[1]
就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
- 数组专有的方法(比如
slice
和forEach
),不能在arguments
对象上直接使用。
callee 属性
arguments
对象带有一个callee
属性,返回它所对应的原函数。
可以通过arguments.callee()
,达到调用函数自身的目的。( ES5禁止在严格模式下使用此属性 )
闭包⁍
JavaScript 允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。[2]
但是,嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的表达式(通常是函数)。这给内部函数的变量提供了一定的 安全性 。
总结如下:
- 内部函数只可以在外部函数中访问。
- 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。
由于内部函数可以访问外部函数的作用域,因此当内部函数 生存周期 大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
就是说,一个闭包必须 保存它可见作用域中所有参数和变量 。因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。
1 |
|
闭包(上例的inc
)用到了外层变量(start
),导致外层函数(createIncrementor
)不能从内存释放。只要闭包没有被垃圾回收机制清除,外层函数提供的运行环境也不会被清除,它的内部变量就始终保存着当前值,供闭包读取。
闭包的用处:
- 读取外层函数内部的变量
- 让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。
- 封装对象的私有属性和私有方法
立即调用的函数表达式(IIFE)⁍
JavaScript 规定,如果function
关键字出现在行首,一律解释成语句。因此,引擎看到行首是function
关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
函数定义后立即调用的解决方法,最简单的处理,就是将其放在一个圆括号里面。(Immediately-Invoked Function Expression),简称 IIFE。(注意分号)
1 |
|
通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:
- 不必为函数命名,避免了污染全局变量;
- IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
箭头函数⁍
箭头函数总是匿名的 ref 箭头函数表达式 (mozilla.org)/深度了解ES6:箭头函数 (mozilla.org)
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this
,arguments
,super
或new.target
。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。
预定义函数⁍
函数 - JavaScript | MDN (mozilla.org)
eval⁍
eval
命令接受一个字符串作为参数,并将这个字符串当作语句执行。