函数是根基
目录
在 JavaScript 中,函数是第一型对象,也就是说函数可以共处,可以将其视为其他任意类型的 JavaScript 对象。就像普通的 JavaScript 数据类型,函数可以被任意变量进行引用,或声明称对象字面量,甚至可以将其作为函数参数进行传递。
函数是第一型对象
对象在 JavaScript 中有如下功能:
- 可以通过字面量进行创建
- 可以赋值给变量、数组或其他对象的属性
- 可以作为参数传递给函数
- 可以作为函数的返回值进行返回
- 可以拥有动态创建并赋值的属性
在 JavaScript 中,函数拥有全部这些功能,也就是说可以像这门语言的其他对象一样使用。因此,我们说函数是第一型对象。 除了可以像其他对象类型一样使用外,函数还有一个特殊的功能,他们可以被调用。 这些调用通常以异步方式进行调用。
函数声明
JavaScript 函数是使用函数字面量进行声明从而创建函数值的,就像使用数字字面量创建数字值一样。记住,作为第一型对象,函数可以像其他值一样在语言中使用,比如字符串和数字。
函数字面量由四个部分组成:
- function 关键字
- 可选名称,如果指定名称,则必须是一个有效的 JavaScript 标志符
- 符号内部,一个以逗号分隔的参数列表。各个参数名称必须是有效的标志符,而且参数列表允许为空。即使是空参数列表,圆括号也必须始终存在
- 函数体,包含一个大括号内的一系列 JavaScript 语句。函数体可以为空,但大括号必须始终存在
作用域和函数
当我们声明一个函数时,我们不仅要关注该函数可用的作用域,还要关注该函数自身所创建的作用域,以及函数内部的声明是如何影响这些作用域。在 JavaScript 中,作用域是由 function 进行声明的,而不是代码块。声明的作用域创建于代码块,但不是终结于代码块。
if (window) {
var x = 123;
}
alert(x); // 弹出 123
函数调用
调用方式:
- 作为一个函数进行调用
- 作为一个方法进行调用,在对象上进行调用,支持面向对象编程
- 作为构造器进行调用,创建一个新对象
- 通过 apply() 或 call() 方法进行调用
expression(arg1, arg2);
从参数到函数形参
当一个参数列表作为函数调用的一部分时,这些参数会按照函数声明里的形参声明顺序,将参数值分别赋值给这些形参
如果传入的参数个数和声明的形参数量不一致,不会抛错,JavaScript 处理策略:
- 如果实际传递的参数数量大于函数声明的形参数量,超出的参数则不会配给形参名称;但依旧有办法获取它们
- 如果实际传递的参数数量小于于函数声明的形参数量,则没有对应参数的形参会赋值为 undefined
注意: 所有函数调用会传递两个隐式参数:arguments 和 this
- arguments 参数:传递给函数的所有参数的一个集合,该集合有一个 length 属性,其值是全部参数的个数,单个参数值可以像访问数组索引一样进行获取,但不能使用数组的各种方法。只需将 arguments 想象成一个类数组结构,并且只拥有数组的某些特性。
- this 参数:一个函数被调用时,除了传入了函数的显式参数以外,名为 this 的隐式参数也被传入了函数。this 参数引用了与该函数调用进行隐式关联的一个对象,被称之为函数上下文
作为函数调用
function func() {}
func();
var func1 = function () {};
func1();
作为方法进行调用
当一个函数被赋值给对象的一个属性,并并使用引用该函数的这个属性进行调用时,那么函数就作为该对象的一个方法进行调用的
var obj = {};
obj.func = function () {};
obj.func();
作为构造器进行调用
将函数作为构造器进行调用,我们要在函数调用前使用
new
关键字
function func() {
return this;
}
const newFunc = new func();
构造器的超能力
将函数作为构造器进行调用,是 JavaScript
的一个超特性,因为构造器调用时,如下特殊行为会发生:
- 创建一个新的空对象
- 传递给构造器的对象是 this 参数,从而成为构造器的函数上下文
- 如果没有显式的返回值,新创建的对象则作为构造器的返回值进行返回
构造器的目的是要创建一个新对象并对其进行设置,然后将其作为构造器的返回值进行返回。任何干扰这种意图的函数都不适合作为构造器
使用 apply() 和 call() 方法进行调用
到目前为止,函数调用方式之间的主要差异是:作为 this 参数传递给执行函数的上下文对象之间的区别
函数调用方式 | 上下文对象 |
---|---|
作为方法调用 | 方法拥有者 |
作为全局函数调用 | window |
作为构造器调用 | 新创建的对象示例 |
使用 apply() 和 call() 方法
apply() 传入两个参数:
- 作为函数上下文的对象
- 作为函数参数所组成的数组
func.apply(obj, [1, 2, 3])
call() 传入两个参数:
- 作为函数上下文的对象
- 函数传入的参数是一个参数列表
func.call(obj, 1, 2, 3)
总结
- 以函数式语言学习 JavaScript,从而编写更复杂的代码
- 函数是第一型对象,就像是 JavaScript 中的其他任意对象一样。和其他任意对象类型一样,他们有如下特点:
- 通过字面量进行创建
- 赋值给变量或属性
- 作为参数进行传递
- 作为函数结果进行返回
- 拥有属性和方法
- 每个对象都有一个与众不同的”小宇宙“,函数的小宇宙是他可以被调用
- 函数是通过字面量进行创建的,其名称是可选的
- 在页面生命周期内,浏览器可以将函数作为各种类型的事件处理程序进行调用
- 函数内部的作用域与大多数其他语言的作用域不同。(具体来说:变量的作用域开始于声明处,结束于函数尾部,其会跨域边界块)。内部函数在当前函数的任何地方都可以(提升),即便是提前引用
- 函数形参列表和实际参数列表的长度可以不同(未赋值的参数被设置为 undefined;多出的参数是不会绑定到参数名称的)
- 每个函数调用都会传入两个隐式参数(arguments:实际传入的参数集合;this:作为函数上下文的对象引用)
- 可以用不同的方法进行函数调用,不同调用机制决定了函数上下文的不同
- 作为普通函数调用时,其上下文是全局对象(window)
- 作为方法进行调用时,其上下文是拥有该方法的对象
- 作为构造器进行调用时,其上下文是一个新分配的对象
- 通过函数的 apply() 和 call() 方法进行调用时,上下文可以设为任意值