1 var s = 0, 2 b = 0; 3 function A(s) { 4 A = function () { 5 console.log(s + b++); 6 }; 7 console.log(A); 8 console.log(s++); 9 } 10 A(1); 11 A(2); 12 console.log(delete A); 13 A(2);
A作为全局对象的一个属性,值为一个函数的引用,当执行A函数时,将一个匿名函数传给A,此时会进行作用域链查找,在全局对象中找到了A,然后赋给它。因为A作为一个函数声明,是不能删除的。如果改成下面这样:
1 var s = 0, 2 b = 0; 3 function A(s) { 4 d = function () { 5 console.log(s + b++); 6 }; 7 console.log(d); 8 console.log(s++); 9 } 10 A(1); 11 d(2); 12 console.log(delete d);//true 13 d(2);
注意,d不是一个变量,只是被添加到全局对象中作为了一个属性,变量不能被删除,属性可以被删除。
1 function A() { 2 function B() { 3 function C() { 4 A = function () { 5 console.log(1); 6 }; 7 } 8 C(); 9 } 10 B(); 11 } 12 A(); 13 A();//1
函数声明和命名函数表达式的函数”真“名是不同的。上面的例子中,A是一个函数声明,作为一个全局对象的属性而存在,执行赋值语句时就是通过作用域链查找到的全局对象里的A。
1 (function A() { 2 function B() { 3 function C() { 4 A = function () { 5 console.log(1); 6 }; 7 } 8 C(); 9 } 10 B(); 11 })(); 12 A();//ReferenceError: A is not defined
命名函数表达式的名称存在了一个特殊对象里,这个特殊对象位于父级作用域和A函数作用域之间,上面的例子中,相当于在全局对象和A函数的活动对象之间加 了一个特殊对象,这个特殊对象只有一个属性那就是A,值为A函数。这就是为什么在全局对象里访问A属性不存在,只有在A函数内部作用域才能访问A属性的原因。也就是说:
1 function A() {}
1 (function A() {})();
上面第一个的A是存在于全局对象里的一个属性,上面第二个的A是存在于一个全局对象和A的活动对象之间的一个特殊对象中。
1 function A() { 2 var A = 2; 3 console.log(A); 4 } 5 A();//2 6 A();//2
所以说,在函数体内可以声明和函数名相同的变量或者函数。只不过不建议这么做,虽然语法没错。
1 function A() { 2 function A() { 3 console.log(2); 4 } 5 A(); 6 } 7 A();//2 8 A();//2
时间: 2024-12-28 00:31:45