javascript之作用域四(作用域的应用)

295 阅读4分钟

四、作用域的应用

前面写了什么是作用域,作用域有那些特点,现在说一下作用域的应用。 看一下例子

1. 应用一

var a = 1;
function fn() {
  console.log('1:' + a);
  var a = 2;
  bar()
  console.log('2:' + a)
}
function bar() {
  console.log('3:' + a)
}

fn()

代码分析:

  1. 第一个 a 打印的值是 1:undefined 而不是 1。因为我们在 fn() 中定义了变量 a,用 var 定义的变量会在当前作用域提升,但是并不会携带赋给变量的值一起提升。
  2. 第二个 a 打印的值是 3:1 而不是 2。因为函数 bar 是定义在全局作用域中的,所以作用域链是 bar -> global,bar 里面没有定义a,所以就会顺着作用域链向上找,然后在 global 中找到了 a。
  3. 第三个 a 打印的值是 2:2。这句话所在的作用域链是 fn -> global,执行 console.log('2:' + a) 会首先在 fn 作用域里查找 a,找到有 a,并且值为2,所以结果就是2。

答案:

// 正确答案
1:undefined
3:1
2:2

2. 应用二

var a = 1;
function fn() {
  console.log('1:' + a);
  a = 2
}
a = 3;
function bar() {
  console.log('2:' + a);
}
fn();
bar();

代码分析:

  1. 第一个 a 打印的值是 1:3,既不是 undefined 也不是 1。首先, fn 中的 a = 2 是给变量 a 赋值,并没有定义变量。然后,执行函数 fn,在查找变量 a 时,此时查找的变量就是全局变量 a,不过此时 a 的值为3。
  2. 第二个 a 打印的值是 2:2。函数 bar 所能访问的作用域链为 bar->global,在执行函数 bar 时,a 的值已经被修改成了 2。

答案:

//正确答案
1:3
2:2

3.应用三

if(!("a" in window)){
    var a = 10;
}
console.log(a); 

代码分析:

  1. 因为全局变量提升,所以 a声明已经存在window中。
  2. 所以if得到是"a" in window是ture
  3. 所以不走里面赋值 console.log(a) //undefined
//解析
var a;
if(!("a" in window)){
    a = 10;
}
// 变种题
(function(){
 var  x = c =  b = {a:1}
})()
console.log(x.a); // error , x is not defined
console.log(c,b) // {a: 1} {a: 1}

4.应用四

(function(){
  var a = b = 3;
})()

console.log(typeof a === "undefined"); // true
console.log(typeof b === "undefined"); // false

代码分析:

  1. 这里涉及的就是立即执行和闭包的问题,还有变量提升,
  2. 运算符执行方向(=号自左向右)
// 那个函数可以拆成这样
(function()
  var a; /* 局部变量,外部没法访问*/
  b = 3; /* 全局变量,so . window.b === 3 , 外部可以访问到*/
  a = b;
})()
// 若是改成这样,这道题应该是对的
console.log(typeof b === "number" && b ===3); // true

5.应用五

var x = 1;
if (function f(){}) {
    x += typeof f;  
}
console.log(x);  // 1undefined

代码分析:

  1. 因为函数体在()中会以表达式去运行。
  2. 最后转换为true,不会存在函数整体声明提升。
  3. 所以typeof为undefined

6.应用六

function fun(n,o) {
     console.log(o)
         return {
          fun:function(m){
            return fun(m,n);
          }
     };
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);   //输出什么 undefined 0 0 0 
var b = fun(0).fun(1).fun(2).fun(3);      //输出什么 undefined 0 1 2
var c = fun(0).fun(1); c.fun(2); c.fun(3);   //输出什么 undefined 0 1 1

我看这道题的时候,比较晕,但是拆分后,就容易理解多了

function fun(n,o) {
     console.log(o)
         return {
          fun:function(m){
            return fun(m,n);
          }
     };
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);   //输出什么 undefined 0 0 0 

//fun(0)调用时候等同于
function fun(n,o) {
    var n=0;
    var o;
     console.log(o)  //undefined
         return {
          fun:function(m){
            return fun(m,n); 
            ---> n就获取到fun里面的n为0的值。然后调用一次fun就会出现下面函数显示
          }
     };
}
//a.fun(1)调用时候等同于fun(1,0)
function fun(n,o) {
    var n=1;
    var o=0;
     console.log(o)  //0
         return {
          fun:function(m){
            return fun(m,n);  ---> n 就获取到fun里面的n为1的值。
          }
     };
}

7.知识点总结

  1. 在JavaScript中,通过 let 和 const 定义的变量具有块级作用域的特性。
  2. 通过 var 定义的变量会在它自身的作用域中进行提升,而 let 和 const 定义的变量不会。
  3. 每个JavaScript程序都具有一个全局作用域,每创建一个函数都会创建一个作用域。
  4. 在创建函数时,将这些函数进行嵌套,它们的作用域也会嵌套,形成作用域链,子作用域可以访问父作用域,但是父作用域不能访问子作用域。
  5. 在执行一个函数时,如果我们需要查找某个变量值,那么会去这个函数被 定义 时所在的作用域链中查找,一旦找到需要的变量,就会停止向上查找。
  6. “变量的值由函数定义时的位置决定”这句话有歧义,准确说是查找变量时,是去定义这个函数时所在的作用域链查找。

参考文章:

www.imooc.com/article/701…