一个普通函数的冷僻属性(length、caller、arguments、name、[[Scopes]]和[[FunctionLocation]])

函数的属性

一个普通函数具有哪些属性?先看下图:


这里写图片描述


可见,一个普通的函数具有8大属性——argumentscallerlengthname、prototype、__proto__、[[FunctionLocation]][[Scopes]]
上述8大属性中,最为关键的自然是prototype和__proto__两大属性,但笔者必须照顾下标题的感受,讲讲其他不常关心的6种属性。


1、arguments


  • arguments并不能显示创建,只有在函数中才可以使用(箭头函数中不能使用)
  • arguments是类数组,并非数组,但它具有数组一样的访问方式:arguments[0]、arguments[1]…也具有数组一样的length属性
  • 看下图,你会发现arguments和数组有一个很明显的区别,arguments会有一个特殊的属性callee,而这个属性是用来做什么的呢?
    这里写图片描述

callee 属性是 arguments 对象的一个成员,仅当相关函数 正在执行时才可用。
callee 属性的初始值就是正被执行的 Function 对象,即:arguments.callee代表正在执行的函数,这允许 匿名的函数递归。(举例一)
callee属性的长度实则为正被执行的Function对象的形参的长度,至于为什么?请看下文length属性。(举例二)
举例一如下:
let sum = function(num){
    if(num === 0){
        return 0;
    }else{
        return num + arguments.callee(num - 1)
    }
}
console.log(sum(5));//15

举例二如下:

function a(i,j,k){
    console.log(arguments);//arguments[0]为1,arguments[1]为2
    console.log(arguments.callee);//正在执行的a函数
    console.log(arguments.callee.length);//形参的长度3
}
a(1,2);


  • arguments主要用途除了使用callee属性外,还用于接收个数不定的实参,这样就不需要一一书写形参了,避免了形参难写的尴尬。

举例:求任何一串数字的和
function count(){
    let sum = 0;
    for(var i = 0;i<arguments.length;i++){
        sum += arguments[i];
    }
    return sum;
}
console.log(count(1,2,3,4,5));

2、caller与callee的区别

callee在第一点中已经简单讲述,那么caller是什么呢?
caller在fun中的作用就是代表调用fun的函数对象,即fun的执行环境。如果fun的执行环境为window,则返回null。


举例一:

function fun(){
    console.log(fun.caller);//null
    console.log(arguments.callee.caller);//null
    /*
        第二个也为null,是因为arguments.callee为正在执行的fun,即arguments.callee === fun
    */
}
fun();//因为是在window下执行的,所以为null

举例二:多层嵌套

function fun(){
    function b(){
        console.log(b.caller === fun);
    }
    b();//打印为true,因为b是在fun中执行的,即执行环境是b
}
fun();

举例三:三层嵌套

function fun(){
    function a(){
        function b(){
            console.log(b.callee === a);
        }
        b();//true,因为b是在a中执行的,即执行环境为a
    }
    a();
}

举例四:对象模式

let obj = {
    fn:function(){
        console.log(obj.fn.caller);//null
    }
}
obj.fn();
总结:
fun.caller代表fun的执行环境
arguments.callee代表的是正在执行的fun
arguments.callee.caller代表fun执行环境,与fun.caller一致(===)
3、length

一个函数的length,表示该函数有多少个必须要传入的参数。
在这里,我们要读懂三个字”必须要“,所谓的必须要指的是除了有默认值、…rest之外的参数。


举例一:

function a(){
    console.log(arguments);
}
console.log(a.length);//0

从字面上理解必须要传入,则上例中,必须要传入的参数个数显然为0个


举例二:

function a(m,n){

}
console.log(a.length);//2

显然,必须要传的则为2个,因为少于2个,那会解析为undefined,多于2个,则多传入的参数作废。
那么,有人问了,是不是只要解析为undefined的都算成length的个数呢?比如:

function a(m,n = undefined){

}
console.log(a.length);//1

显然不是,这里length指的是没有默认值、不是…reset的形参个数


举例三:

function a(m,n = 1){

}
console.log(a.length);//1

这里,要注意的是,必须要传入的为m这个参数,因为n不传默认值为1


举例四:

function a(m,n=1,o=2,...rest){

}
console.log(a.length);//1

跟之前说的一样,length是指必须要传入的,而n、o、rest均是可传可不传,所以这里长度依然为1


这时,我们再来看看上面说的arguments.callee.length,这个length指的是多少呢?
其实很简单,因为arguments.callee指的是当前正在执行的函数fun,所以arguments.callee.length就是fun.length,那么也就是说fun这个函数必须要传入几个参数,那这个length就是多少。

4、name

这个应该不用多讲,name就是函数的名称
并且,这个name是无法修改的

var nn = function a(){};
a.name = 's';
console.dir(nn);//依旧是函数a
5.[[Scopes]]

这块内容,本身我也并不熟悉,然后查阅了一些资料,发现《JavaScript内部属性[[Scope]]与作用域链及其性能问题》这篇文章写的不错,我在这里就不赘述了,直接点击>>传送门<<查看吧!

6、[[FunctionLocation]])

该属性与[[Scope]]一样,是仅供js引擎使用的,我们并不可以使用。
主要作用是定位该函数的代码位置(不重要,不过多讲述)


以上是鄙人对普通函数的一些观点,望各位批评指正!

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值