JavaScript 函数
1、函数描述
1.1 函数是头等(first-class)对象
因为它们可以像任何其他对象一样具有属性和方法。
它们与其他对象的区别在于函数可以被调用。
每个函数其实都是一个 Function 对象
1.2 返回值
默认返回 undefined
使用 return 语句来指定一个要返回的值(使用 new 关键字调用一个构造函数除外)
1.3 函数参数
调用函数时,传递给函数的值被称为函数的实参(值传递),
对应位置的函数参数名叫作形参。
如果实参是一个包含原始值(数字,字符串,布尔值)的变量,则就算函数在内部改变了对应形参的值,返回后,该实参变量的值也不会改变。
如果实参是一个对象引用,则对应形参会和该实参指向同一个对象。假如函数在内部改变了对应形参的值,返回后,实参指向的对象的值也会改变。
1.4 this 指向
在函数执行时,this 关键字并不会指向正在运行的函数本身,而是指向调用该函数的对象
如果你想在函数内部获取函数自身的引用,只能使用函数名或者使用 arguments.callee 属性(严格模式下不可用),如果该函数是一个匿名函数,则你只能使用后者。
2、函数定义
2.1 函数声明
2.1.1 用法
2.1.2 函数声明提升
JavaScript 中的函数声明被提升到了函数定义,可以在函数声明之前使用该函数。
函数声明同时也创建了一个和函数名相同的变量。因此,以函数声明定义的函数能够在它们被定义的作用域内通过函数名而被访问到
2.2 函数表达式
2.2.1 用法
函数名称可被省略,此种情况下的函数是匿名函数(anonymous)
函数名称只是函数体中的一个本地变量。
2.2.2 没有提升
2.3 函数生成器声明 (function* 声明)
定义一个生成器函数 (generator function),它返回一个 Generator 对象。
生成器函数在执行时能暂停,后面又能从暂停处继续执行。
调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 ( iterator )对象。
当这个迭代器的 next() 方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现 yield 的位置为止,yield 后紧跟迭代器要返回的值。
或者如果用的是 yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。
next()方法返回一个对象,这个对象包含两个属性:value 和 done,
value 属性表示本次 yield 表达式的返回值,
done 属性为布尔类型,表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回。
2.4 函数生成器表达式 (function*表达式)
function 表达式和 function 声明比较相似,并具有几乎相同的语法。
function 表达式和 function 声明之间主要区别就是函数名,
即在创建匿名函数时,function*表达式可以省略函数名
2.5 箭头函数表达式 (=>)
更简短的函数
不绑定 this
2.5.1 更短的函数
2.5.2 不绑定 this
2.6 Function 构造函数表达式(不推荐)
2.6.1 描述
使用 Function 构造函数生成的 Function 对象是在函数创建时解析的。
这比你使用函数声明或者函数表达式并在你的代码中调用更为低效,
因为使用后者创建的函数是跟其他代码一起解析的。
以调用函数的方式调用 Function 的构造函数(而不是使用 new 关键字) 跟以构造函数来调用是一样的。
2.6.2 实例属性
Function.caller 获取调用函数的具体对象。(存在兼容性问题)
Function.length 获取函数的接收参数个数。
Function.name 获取函数的名称。
2.6.3 实例方法
Function.prototype.apply() 在一个对象的上下文中应用另一个对象的方法;参数能够以数组形式传入。
Function.prototype.bind()
- bind()方法会创建一个新函数,称为绑定函数.
- 当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,
- 传入 bind()方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.
Function.prototype.call() 在一个对象的上下文中应用另一个对象的方法;参数能够以列表形式传入。
Function.prototype.toString() 获取函数的实现源码的字符串。覆盖了 Object.prototype.toString 方法。
2.6.4 与函数声明、函数表达式区别
和函数表达式一样没有函数声明提升。不能在声明前调用
不能创建当前环境闭包,只能被创建于全局环境
只能访问全局变量和自己的局部变量
2.6.5 尽量避免使用的原因
每次构造函数被调用,传递给 Function 构造函数的函数体字符串都要被解析一次 。
虽然函数表达式每次都创建了一个闭包,但函数体不会被重复解析,因此函数表达式仍然要快于"new Function(...)"
在通过解析 Function 构造函数字符串产生的函数里,内嵌的函数表达式和函数声明不会被重复解析。
2.7 生成器函数的构造函数(不推荐)
GeneratorFunction 构造器生成新的生成器函数 对象。
在 JavaScript 中,生成器函数实际上都是 GeneratorFunction 的实例对象。
GeneratorFunction 并不是一个全局对象。它可以通过下面的代码获取。
2.7.1 语法
2.7.2 尽量避免使用的原因
当创建函数时,将使用 GeneratorFunction 构造函数创建的生成器函数对象进行解析。
这比使用 function* 表达式 声明生成器函数效率更低,
使用 GeneratorFunction 构造函数创建的生成器函数不会为其创建上下文创建闭包;它们始终在全局范围内创建。
当运行它们时,它们只能访问自己的本地变量和全局变量,而不是从 GeneratorFunction 构造函数调用的范围的变量。
3、函数作用域
在函数内定义的变量不能在函数之外的任何地方访问,因为变量仅仅在该函数的域的内部有定义。
一个函数可以访问其定义所在作用域内的任何变量和函数。例如,定义在全局域中的函数可以访问所有定义在全局域中的变量。
在另一个函数中定义的函数也可以访问在其父函数中定义的所有变量和父函数有权访问的任何其他变量。
4、闭包
JavaScript 允许函数嵌套,
内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。
外部函数却不能够访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一定的安全性。
由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行时间长。
当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
4.1 命名冲突
当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。
更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。这就是作用域链。
链的第一个元素就是最里面的作用域,最后一个元素便是最外层的作用域。
5.arguments 对象
arguments 是一个对应于传递给函数的参数的类数组对象
arguments 变量只是 ”类数组对象“,并不是一个数组。
称其为类数组对象是说它有一个索引编号和 length 属性。
尽管如此,它并不拥有全部的 Array 对象的操作方法。
arguments 对象是所有(非箭头)函数中都可用的局部变量。
5.1 属性
arguments.callee : 当前正在执行的函数。
arguments.caller : 调用当前执行函数的函数。
arguments.length : 传给函数的参数的数目。
6. 函数参数
从 ECMAScript 6 开始,有两个新的类型的参数:默认参数,剩余参数
6.1 默认参数
在 JavaScript 中,函数参数的默认值是 undefined。在过去,用于设定默认参数的一般策略是在函数的主体中测试参数值是否为 undefined,如果是则赋予这个参数一个默认值。
6.2 剩余参数
剩余参数语法允许将不确定数量的参数表示为数组。
参考链接
评论