匿名函数具名化【官方推荐规范】

395 阅读2分钟

一、匿名函数

自执行函数

函数表达式

回调函数

二、匿名函数具名化特点

1.设置的名字,并不会在所处上下文中进行声明

(function A() {
    // ...
})();
console.log(A); //Uncaught ReferenceError: A is not defined 

2.在函数执行形成的私有上下文中,会把这个名字作为一个私有变量「存储到AO中」,变量值是当前函数本身「堆内存地址」; 并且默认情况下,对这个变量值进行修改是无效的;

(function A() {
    A = 100; //无效操作 
    console.log(A); //函数本身
})(); 

3.但凡函数内部,这个名字被我们手动的声明过「例如:形参/var/function/let/const...」,都认为这个名字是我们自己玩的私有变量,和默认值是当前函数本身没关系了!! “默认是函数本身的这个点,权重太低”

/*
*   EC(AA)
*       A--------->函数本身
* 作用域链
* 形参赋值--
* 变量提升:var A
*/

(function A() { 
    console.log(A); //undefined
    var A = 100;
    console.log(A); //100
})();

/*
*   EC(AA)
*       A--------->函数本身
* 作用域链
* 形参赋值 A ===100
* 变量提升:---
*/

(function A(A) {
    console.log(A); //100
    A = 200;
    console.log(A); //200
})(100); 


(function A(A) {
    console.log(A); //100
   function A(){}
    console.log(A); //200
})(100); 
/* 
/!*
 * EC(G)
 *   b --> 10
 *    
 * 变量提升: var b;
 *!/
var b = 10;
(function b() {
    /!*
     * EC(B) 私有上下文 
     *    b --> 当前函数本身
     * 作用域链:<EC(B),EC(G)>
     * 形参赋值:--
     * 变量提升:--
     *!/
    b = 20; //无效操作
    console.log(b); //当前函数本身
})();
console.log(b); //10 

三、匿名函数具名化作用:

因为我们可以在函数内部,基于这个名字访问到这个函数,这样就可以实现一些原本不具备的能力,例如:递归 "use strict"; 开启JS严格模式「语法要更加严谨,目前我们开发,基于webpack打包后,都是严格模式」

"use strict"; 
(function () {
    // 递归?
    // arguments.callee:代表当前函数本身
    // arguments.callee.caller:存储函数在哪执行的
    // 但是在严格模式下,都嗝屁了,不允许使用....
    console.log(arguments);
})(); 


(function A() {
    // 实现递归处理
    // console.log(A); //函数本身
    A();
})(); //死递归 内存溢出

四、arguments.callee 和arguments.callee.caller

  • arguments.callee:指的是函数本身
  • arguments.callee.caller 指的是函数执行的宿主环境,如果是在函数A中执行,打印出来的就是A,如果是在全局作用域中执行,打印出来的就是null。
function fn(){
  console.log(arguments.callee); // 打印出的是fn 函数本身
  
}
fn();
function fn(){
   console.log(arguments.callee.caller);
}

fn();  // 此时打印出的是 null(在全局作用域中执行)


function fn(){
   console.log(arguments.callee.caller);
}
function A(){
  fn();  // 此时打印出的是 A这个函数
}
A();