ecmascript - javascript this 的问题
ringa_lee
ringa_lee 2017-04-10 17:02:46
[JavaScript讨论组]
({
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

ringa_lee
ringa_lee

ringa_lee

全部回复(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 影响。

纯属瞎猜,以上。

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

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号