javascript this 的问题

({
x: 10,
foo: function () {
    function bar() {
        console.log(x);
        console.log(y);
        console.log(this.x);
    }
    with (this) {
        var x = 20;
        var y = 30;
        bar.call(this);
    }
}
}).foo();

上面的代码是 http://dmitrysoshnikov.com/ecmascript/the-quiz/ 中的第九题,
请问为什么console.log(x)输出undefined

阅读 3.7k
3 个回答

声明提升

var声明会被提升到函数作用域顶部,方法可以改写为

({
x: 10,
foo: function () {
    var x,y;
    function bar() {
        console.log(x);
        console.log(y);
        console.log(this.x);
    }
    with (this) {
        x = 20;
        y = 30;
        bar.call(this);
    }
}).foo();

with作用域

在with作用域里寻找变量的时候先去with对象里找,找不到时按照正常的闭包的方式找,见下注释(注意注释前的数字顺序)

({//1. 这个对象叫OBJ
x: 10,//2. X1(OBJ.x) <= 10
foo: function () {
    var x,y;//3. 声明提升,把这里新建的变量叫X2, Y2
    function bar() {
        console.log(x);//7. 这里不在with作用域中,按照普通的闭包方式,x指X2,此时只被声明没有赋值,所以是undefined
        console.log(y);//8. 同理,这个y是Y2,30
        console.log(this.x);//9. 因为是call调用的,这里的this是OBJ,OBJ.x即X1,之前被赋值为20
    }
    with (this) {//4. this === OBJ 
        x = 20;//5. 受with作用域影响,先找OBJ.x,找到了,所以这里的x指的是X1,X1被赋值为20
        y = 30;//6. 受with作用域影响,先找OBJ.y,没找到,所以这里的y指的是Y2
        bar.call(this);
    }
}).foo();

sorry,搞错了。
这里的关键点在于with(this),with的作用是设置代码在特定对象中的作用域。简单理解就是在with范围内的变量,就是this对象的变量,无需再写this.x。所以

({
  x: 10,
  foo: function () {
    function bar() {
      console.log(x);
      console.log(y);
      console.log(this.x);
    }
    
    // 这里的x实际上是this.x,var x会进行变量提升,也就是this.x = 20,但是y提升到前面去了,所以y等于30,x提升到前面去未赋值即undefined
    with (this) {
      var x = 20; 
      var y = 30;
      bar.call(this);
    }
  }
}).foo();

因为

var x = 20;

实际上相当于两个分开的语句―

var x; // before run
x = 20; // runtime assignment

变量声明时,在 with 中声明的变量相当于被提升到函数顶部,因此具有函数作用域,所以 xy 都是是这个对象的 foo 函数所可以访问的标识符,而 bar 在其内部,所以 xy 属性均可访问。

而在赋值时,with 作用域优先,而 with 的作用域已经有 x 了,赋值时直接对 this.x 赋值,函数作用域的 x 保持 undefined. 相反,标识符 ywith 作用域不存在,所以对函数作用域的 y 赋值。

而函数 bar 不受 with 影响。

纯属瞎猜,以上。

另外代码少了一个 }。。。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题