变量提升题
var a = 1;function fn(a) { console.log(a); var a = 2; function a() {} console.log(a); }fn(a); console.log(a);
console.log(a)var a=12; function fn(){ console.log(a); var a=13; }fn(); console.log(a);
console.log(a)var a=12; function fn(){ console.log(a); a=13; }fn(); console.log(a);
console.log(a);a=12;function fn(){ console.log(a); a=13; }fn();console.log(a);
console.log(foo); { console.log(foo); function foo() {} console.log(foo); foo = 1; console.log(foo); }console.log(foo);
答案解析
/* * EC(G) * a --> 1 * fn --> 0x000 作用域链[[scope]]:EC(G) * 变量提升: * var a; * function fn(a) {...}; * 代码执行: * fn(a) 跳掉函数体内 */var a = 1;function fn(a) { /* * EC(FN) * a --> 1 * -->赋值了一个函数地址为0x001[scope]:EC(FN) * -->2 * 变量提升 var a (私有) */ console.log(a); // =>函数 var a = 2; function a() {} console.log(a); // =>2}fn(a); console.log(a);// =>1 (全局)
/* * EC(G) * a --> 12 * fn --> 0x000 作用域链[[scope]]:EC(G) * 变量提升: * var a; * function fn(a) {...}; * 代码执行: * fn() 跳掉函数体内 */console.log(a)var a=12; function fn(){ /* * EC(FN) * a --> 13 * 作用域链:<EC(FN),EC(G)> * 形参赋值:-- * 变量提升:var a;(私有) */ console.log(a); // =>undefined 变量提升但没赋值 var a=13; }fn(); console.log(a); // =>12 (全局)
/* * EC(G) * a --> 12 * fn --> 0x000 作用域链[[scope]]:EC(G) * 变量提升: * var a; * function fn(a) {...}; * 代码执行: * fn() 跳掉函数体内 */console.log(a)var a=12; function fn(){ /* * EC(FN) * a --> 因为内部没有所以去全局寻找 * 作用域链:<EC(FN),EC(G)> * 形参赋值:-- * 变量提升:-- */ console.log(a); // =>12 a=13; //修改了全局都a值}fn(); console.log(a); // =>13
console.log(a); //=>报错 Uncaught ReferenceError: a is not defined // a 为声明 直接报错 下面也不会运行a=12;function fn(){ console.log(a); a=13; }fn();console.log(a);
一道同名块级作用域题
console.log(foo); { console.log(foo); function foo() {1} console.log(foo); foo = 1; console.log(foo); function foo() {2} foo = 3; console.log(foo); }console.log(foo);
知识点
- 块级作用域中
函数和var变量被提升到全局作用域但并不赋值 let和const不会被提升 - 如果是
函数和var随后在块级作用域中会被提升到顶部 并且函数赋值堆地址 - 当块级作用域执行遇到函数创建时,浏览器会把在创建函数之前对同名变量(foo)的所有操作同步给全局一份(这是为了兼容ES5又兼容ES6)
但创建函数之后对同名变量的操作就只会在其私有作用域下了不会到全局
/* * EC(G) * foo --> 1 * 变量提升: * var foo; 开始时但并不赋值 * foo() * 代码执行: * fn(a) 跳掉函数体内 */console.log(foo); // =>undefined { console.log(foo); // =>函数(0x002) function foo() {1} //变量提升到全局:foo; 开始时但并不赋值 //随后提升到块级作用域顶部 赋值函数堆地址此时是return 1的函数(0x001) console.log(foo); // =>函数(0x002) foo = 1; //此时修改了 foo的值 但如果没有函数(0x002)的存在,只修改了块级作用域的foo值不会全局的 console.log(foo); // =>1 function foo() {2} // @1 -- 和1一样 赋值函数堆地址此时修改成return 2的函数(0x002) // @2 --遇到函数(0x002)创建 此时会把之前对foo的 修改同步给全局一份 全局的 --> foo值为1了 foo = 3; //此时修改了 foo的值 但后面没有了函数创建 所以只修改块级作用域的foo console.log(foo); // =>3 块级作用域的foo }console.log(foo); // =>1 全局的