天天看点

变量提升全面练习

变量提升练习题

// 第一题
 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 */

           

继续阅读