这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战
前言
今天我们谈一谈函数内部的问题,大家可能一谈到可能就联想到this指向的问题,但是大家可能对于arguments可能就不太熟了,今天我们来看看吧。
函数内部
ECMAScript 5中,存在一个特殊的对象: arguments 和 this 。 ECMAScript 6又新增 了 new . target 属性。
arguments
arguments 对象,它是一个类数组对象,包含调用函数时传人的所有参数。这 e 口有以 function 关键子定义凼效(相对于使用箭头语法创建函数)时才会有。虽然主要用于包含参数,但 arguments 对家共头还有一个 callee 属性,是一个指向 arguments 对象所在函数的 指针。来看下面这个经典的阶乘函数:
function factorial ( num ){ if ( num <=1)(
return 1;) else {
return num * factorial ( num -1);}
阶乘函数一般定义成递归调用的,就像上面这个例子一样。只要给函数一个名称,而且这个名称不今变,这样定义就没有问题。但是,这个函数要正确执行就必须保证函数名是 factorial ,从而导致了紧密耦合。使用 arguments . callee 就可以让函数逻辑与函数名解耦:\
function factorial ( num )( if ( num <=1)(
return 1;) else (
return num * argument В. callee ( num -1);}
这个重写之后的 factorial ()函数已经用 arguments . callee 代替了之前硬编码的 factorial 。这意味着无论函数叫什么名称,都可以引用正确的函数。考虑下面的情况:
let trueFactorial = factorial ; factorial = function ()(\ return 0;\
这个重写之后的 factorial ()函数已经用 arguments . callee 代替了之前硬编码的 factorial 。这意味着无论函数叫什么名称,都可以引用正确的函数。考虑下面的情况:
let trueFactorial = factorial ; factorial = function (){
return 0;;
console . log ( trueFactorial (5));/ //120
console . log ( factorial (5)); //0
这里, trueFactorial 变量被赋值为 factorial ,实际上把同一个函数的指针又保存到∫另一个位置。然后, factorial 函数又被重写为一个返回0的函数。如果像 factorial ()最初的版本那样不使用 arguments . callee ,那么像上面这样调用 trueFactorial ()就会返回0。不过,通过将函数与名称解耦, trueFactorial ()就可以正确计算阶乘,而 factorialO 则只能返回0。
this
另一个特殊的对象是 this ,它在标准函数和箭头函数中有不同的行为。 在标准函数中、 this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 this 值(在 网页的全局上下文中调用函数时, this 指向 windows )。来看下面的例子:
window 、 color ' red ';
function ayColor (){
console . log ( this . color );
sayColor (0: //' red
o . sayColor = sayColor ;0. sayColor//' blue '
定义在全局上下文中的函数 sayColor (引用了 this 对象。这个 this 到底引用哪个对象必须了函数被调用时才能确定。因此这个值在代码执行的过程中可能会变。如果在全局上下文中调) ayColor (),这结果会输出" red ",因为 this 指向 window ,而 this . color 相当于 window . colo 在把 sayColor O )赋值给 o 之后再调用 o . sayColor O , this 会指向 o ,即 this . color 相当 color ,所以会显示" blue "。 在箭头函数中, his 引用的是定义箭头函数的上下文。下面的例子演示了这一点。在对 sayColor 两次调用中, chis 引用的都是 window 对象,因为这个前头函数是在 window 上下文中定义的:
定义在全局上下文中的函数 sayColorO 引用了 this 对象。这个th1S到底使用哪个对象函数被调用时才能确定。因此这个值在代码执行的过程中可能会变。如来在全局上下文中 sayColor (),这结果会输出" red ",因为 this 指向 window ,而 this。color和 Window。color不同,而在把 sayColor ()赋值给 o 之后再调用 o . sayColor (), this 会指向 O 。 在箭头函数中, this 引用的是定义箭头函数的上下文。下面的例子演示了这一点。在对 sayColors 的两次调用中, this 引用的都是 window 对象,因为这个箭头函数是在 window 上下文中定义的:
window . color =' red ';1et O={
color :' blue '
let sayColor =()=> console . log ( this . color );
sayColor (); //' red '
O . sayColor = sayColor ; O . sayColor ();//' red
大家知道,在事件回调或定时回调中调用某个函数时, this 值指向的并非想要的对象。此时将回调函数写成箭头函数就可以解决问题。这是因为箭头函数中的 this 会保留定义该函数时的上下文:
function King (){
thiS . royaltyName =‘ Henry ';// this 引用 King 的实例
setTimeout (()=> console . log ( this . royaltyName ),1000);
function Queen (){
this . royaltyName =' Elizabeth ';
// this 引用 window 对象
setTimeout ( function (){ console . log ( this . royaltyName );},1000);
new King ();// Henry
new Queen ();// undefined
注意函数名只是保存指针的变量。因此全局定义的 sayColor ()函数和 o . sayColor ()是同一个函数,只不过执行的上下文不同。