JS红宝书10.1-10.5 函数
箭头函数
函数实际上是对象,每个函数都是Function类型的实例,而Function也有属性和方法,跟其他引用类型一样。函数名是指向函数对象的指针,而且不一定与函数本身紧密绑定
箭头函数不能使用arguments、super和new.target,也不能用作构造函数。此外,箭头函数也没有prototype属性
函数名
函数名就是指向函数的指针,一个函数可以有多个名称,使用不带括号的函数名会访问函数指针,而不是执行函数
ES6的所有函数对象都会暴露一个只读的name属性,其中包含关于函数的信息。多数情况下,这个属性中保存的就是一个函数标识符,或者说是一个字符串化的变量名。即使函数没有名称,也会如实显示成空字符串,如果它是使用function构造函数创建的,则会标识成anonymous,如果函数是一个获取函数、设置函数,或者使用bind实例化,那么标识符前面会加上一个前缀
函数参数
ES函数既不关心传入的参数个数,也不关心这些参数的数据类型。
ES函数的参数在内部表现为一个数组,函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么。
在使用function关键字定义函数时,可以在函数内部访问arguments对象,从中取得传进来的每个参数值
arguments对象是一个类数组对象(不是Array的实例),因此可以使用中括号语法访问其中的元素,而要确定传进来多少个参数,可以访问arguments.length属性
ES函数的参数只是为了方便才写出来的,并不是必须写出来的,命名参数不会创建让之后的调用必须匹配的函数签名,因为根本不存在验证命名参数的机制
arguments对象可以跟命名参数一起使用,arguments的值始终会与对应的命名参数同步,但这并不意味着它们都访问同一个内存地址,它们在内存中还是分开的,只不过会保持同步而已。
对于命名参数而言,如果调用函数时没有传这个参数,那么它的值就是undefined,这就类似于定义了变量但没有初始化
严格模式下,arguments对象与命名参数不同步,并且在函数中尝试重写arguments对象会导致语法错误
如果函数是箭头语法定义的,那么传给函数的参数将不能使用arguments关键字访问,而只能通过定义的命名参数访问。虽然箭头函数中没有arguments对象,但可以在包装函数中把它提供给箭头函数
ES中的所有参数都是按值传递的,不可能按引用传递参数,如果把对象作为参数传递,那么传递的值就是这个对象的引用
函数重载
ES函数没有签名,因为参数是由包含零个或多个值的数组表示的,自然也就没有重载。如果在ES中定义了两个同名函数,则后定义的会覆盖先定义的。
可以通过检查参数的类型和数量,然后分别执行不同的逻辑来模拟函数重载
默认参数
ES5之前,实现默认参数的一种常用方式就是检测某个参数是否等于undefined,如果是则意味着没有传这个参数,那就给它赋一个值
ES6支持显示定义默认参数,只要在函数定义中的参数后面用=就可以为参数赋一个默认值
给参数传undefined相当于没有传值,不过这样可以利用多个独立的默认值
在使用默认参数时,arguments对应的值不反映参数的默认值,只反映传给函数的参数。
默认参数值并不限于原始值或对象类型,也可以使用调用函数返回的值
函数默认参数只有在函数被调用时才会求值,不会在函数定义时求值,而且计算默认值的函数只有在调用函数但未传相应参数时才会被调用
箭头函数同样也可以这样使用默认参数
给多个参数定义默认值实际上跟使用let关键字顺序声明变量一样,默认参数会按照定义它们的顺序依次被初始化,后定义默认值的参数可以引用先定义的参数。
参数初始化顺序遵循暂时性死区规则,即前面定义的参数不能引用后面定义的,参数也存在于自己的作用域中,它们不能引用函数体的作用域