變量提升練習題
// 第一題
console.log(a,b,c); // undefined *3
var a = 12,
b = 13,
c = 14;
function fn(a){
console.log(a,b,c); // 10 13 14
a = 100;
c = 200;
console.log(a,b,c); // 100 13 200
}
b = fn(10); // 函數執行,如果函數中沒有return值,則預設傳回undefined
console.log(a,b,c) // 12 undefined 200
// 第二題
var i = 0;
function A() {
var i = 10;
function x() {
console.log(i);
}
return x;
}
var y = A();
y(); // 10
function B() {
var i = 20;
y(); // 10 函數的上級作用域是函數建立時所在的上下文,跟函數在哪裡執行是沒有關系的
}
B();
// 全程輸出的i都是函數A中的私有i,跟全局的i沒有關系
// 第三題
var a = 1;
var obj = {
name: 'tom'
};
function fn() {
var a2 = a;
obj2 = obj; // obj2既不是私有的,也不是全局的,則相當于給window添加一個名為 obj2 的屬性,值是obj
a2 = a;
obj2.name = 'jack';
}
fn();
console.log(a); // 1
console.log(obj); // {name: 'jack}
// 第四題
var a = 1;
function fn(a) {
// 先形參指派,後變量提升
console.log(a); // 函數a
var a = 2;
function a(){}
console.log(a); // 2
}
fn(a);
console.log(a); // 1
// 第五題
console.log(a); // undefined
var a = 12;
function fn() {
console.log(a); // undefined
var a = 13;
}
fn();
console.log(a) // 12
// ==============
/* console.log(a); // undefined
var a = 12;
function fn() {
console.log(a); // 12
a = 13;
}
fn();
console.log(a); // 13 */
// ================
/* console.log(a); // 報錯:a is not defined 之後的代碼不會被執行
a = 12;
function fn(){
console.log(a);
a = 13;
}
fn();
console.log(a); */
// 第六題
var foo = 'hello';
(function(foo) {
console.log(foo); // 'holle'
// A || B:如果A的值為真,則傳回A的值,否則傳回B的值
// A && B:如果A的值為真,則傳回B的值,否則傳回A的值
var foo = foo || 'world';
console.log(foo); // 'holle'
})(foo);
console.log(foo); // 'hello'
// 第七題
{
function foo(){}; // 執行到這一行,會把foo也映射一份給全局
foo = 1; // 這裡隻是更改私有的 foo,跟全局沒有關系
console.log(foo); // 1
}
console.log(foo); // function foo(){}
// =================
/* {
function foo(n) {}
foo = 1;
function foo(m) {} // 執行到這裡,會把之前對foo的值映射一份給全局
console.log(foo); // 1
}
console.log(foo); // 1 */
//==============
/* {
function foo(n){}
foo = 1;
function foo(m) {}
foo = 2;
console.log(foo); // 2
}
console.log(foo); // 1 */
// 第八題
var x = 1;
function func(x, y=function an(){x = 2}) {
x = 3;
y();
console.log(x); // 2
}
func(5);
console.log(x); // 1
/* var x = 1;
function func(x, y=function an(){x = 2}) {
var x = 3;
y(); // 這裡更改的是函數func中的形參x的值
console.log(x); // 3 這裡輸出的是私有塊級上下文中聲明的變量x的值,而不是函數func中的形參x的值
}
func(5);
console.log(x); // 1 */
/*
* 解析:
全局上下文 EC(G): {
變量提升:
var x;
function func = AF0; [[scope]]: EC(G)
代碼執行:
x = 1;
func(5);
func(5)執行:EC(func) {
作用域鍊:[[scope-chain]] = <EC(func), EC(G)>
形參指派:
x = 5;
y = AF1; [[scope]]: EC(func)
變量提升:發現有變量聲明,立即形成一個塊級私有上下文
代碼執行:
聲明的變量屬于這個塊級中私有的變量;
EC(Block): {
作用域鍊:[[scope-chain]] = <EC(Block), EC(func)>
代碼執行:
x = 3;
y(); // 根據作用域鍊查找機制,這個函數中改變的是 EC(func)中的x的值,
console.log(x)
}
y()執行 EC(Y):{
作用域鍊:[[scope-chain]] = <EC(Y), EC(func)>
代碼執行:
x = 2; x不是私有變量,按照作用域鍊查找機制,在 EC(func)中找到變量x,将其值改為2
}
}
}
函數執行:
條件1:有形參指派預設值(不論是否傳遞實參,也不論預設值的類型)
條件2:函數體中有變量聲明(必須是用var/let/const聲明的變量,注意let/const不允許重複聲明,不能和形參變量名一樣)
滿足這兩個條件的話,函數執行時除了形成函數本身的私有上下文外,還會多建立一個塊級私有上下文(函數體大括号包起來的部分),此時聲明的變量是屬性這個私有塊級作用域的,并且在指派之前,如果變量跟函數的形參變量名一樣,則會把函數的形參處理後的結果映射該私有塊級上下文中的聲明的變量
*/
debugger;
function fn(b=12, y) {
var b = 15;
const bb = function(){
console.log(b);
}
bb();
console.log(b); // 12
}
fn();
/* var x = 1;
function func(x, y = function an(){x = 2}){
var x = 3; // 屬于私有塊級上下文中的變量
y(); // 執行的是預設值 an函數 [[scope]]: EC(func)
var y = function an1(){x = 4}; // [[scope]]: EC(Block)
console.log(x); // 3
y(); // 作用域鍊:[[scope-chain]] = <EC(y), EC(Block)>
console.log(x); // 4 輸出私有塊級上下文中的x
}
func(5);
console.log(x); // 1 */