Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS-作用域链相关问题 #23

Open
jirengu opened this issue Jan 1, 2017 · 6 comments
Open

JS-作用域链相关问题 #23

jirengu opened this issue Jan 1, 2017 · 6 comments

Comments

@jirengu
Copy link
Owner

jirengu commented Jan 1, 2017

如下代码的输出是什么? 为什么?

var a = 1;

function fn(){
	console.log(a); 
	var a = 5;
	console.log(a);  
	a++;
        var a;
	fn2();
	console.log(a);
	function fn2(){
		console.log(a); 
		a = 20;
		b = 100;
	}
}
fn();
console.log(a); 
a = 10;
console.log(a); 
console.log(b);
@hungeroxc
Copy link

一图说明:
image

@starlikerain
Copy link

var a = 1;

    function fn() {
        console.log(a); // undefined,因为下面的有个var a;变量提升了,用let就没事儿啦
        var a = 5;
        console.log(a); // 5,上面的声明赋值了
        a++; // 如果往下走一步,a的本体变成6
        var a; // 这个被提到顶上去了,和上面的重合
        fn2();
        console.log(a);

        function fn2() {
            console.log(a); // 6,因为a++呀
            a = 20;
            b = 100;
        }
    }
    fn();
    console.log(a); // 1,函数作用域的你想拿到?全局的先给你了
    a = 10;
    console.log(a); // 10,上面的覆盖
    console.log(b); // 100,因为直接在函数作用域赋值,不用var,等于window.b = 100;

@RookieDay
Copy link

RookieDay commented Jan 2, 2017

下面是我的理解,有什么问题还望大家指正。

  • 首先贴图,接下来解释
    2

  • 绘制作用域链原则

    1. 先画一条主链条 暂且叫做0级别
    2. 有一个fn就引出一条新的作用域链级别 叫做1级别, 依次累加2级别、3级别.....
  • 解释

fn();
console.log(a); 
a = 10;
console.log(a); 
console.log(b);
  1. 首先是执行fn,进入1级别
第一次 console.log(a) --> 1级别上从此处开始往上找,可以发现a尚未赋值 所以输出**undefined**
第二次 console.log(a)---> 1级别上从此处开始往上找,可以发现a已经赋值5,所以输出**5**
第三次 console.log(a)---> 此时执行fn1(),已经进入2级别,2级别上上从此处开始往上找,前面a++已经自增,所以输出**6**,接下来a重新被赋值为20,所以1级别上的a也就变成了20,接下来b=100,前面没有var,所以为全局变量
第四次console.log(a)---> a 在2级别已经修改为20,所以此时输出**20**

2.接下来是执行 console.log(a) 进入0级别

执行 console.log(a)  在0级别上,此时全局的a的值一直未变,所以输出**1** 

3.接下来是执行 a = 10; console.log(a); 进入0级别

a = 10;              在0级别上,全局变量a被重新赋值为10
console.log(a);  在0级别上,从此处开始往前找,所以这里输出**10**

4.接下来是执行console.log(b)进入0级别

console.log(b); 在0级别上,此时b的值已经被2级别上也就是fn2()里面赋值100了,所以这里输出**100**
(PS: 也就是如果你在fn2()里面,把b=100改成var b = 100,在此处会报错,输出“b is not defined(…)” 因为没有声明此变量)

5.结果

undefined
5
6
20
1
10
100

@ghost
Copy link

ghost commented Jan 3, 2017

将以上代码改写如下:

  var a = 1;

  function fn(){
    var a;
    var a; // 第二次申明变量a,覆盖了第一次申明
    function fn2(){
      console.log('3:'+a); // 6,在上级作用域fn里查找a
      a = 20; // 先在上级作用域fn里查找a并重新赋值
      b = 100;
    }
    console.log('1:'+a); //undefined
    a = 5;
    console.log('2:'+a);  //5
    a++;
    fn2(); 
    console.log('4:'+a); // 20,调用fn2()之后,a重新赋值

  }
  fn();
  console.log('5:'+a); //1
  a = 10;
  console.log('6:'+a); //10
  console.log('7:'+b); //100

@n313893254
Copy link

//undefined,5,6,20,1,10,100

window {
    a: 10
    b: 100
    fn() {
        a: 20
        fn2() {
            
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants
@jirengu @n313893254 @RookieDay @starlikerain @hungeroxc and others