首页 > 一道稍微综合综合点的JS题,关于with, this, 和call用法?

一道稍微综合综合点的JS题,关于with, this, 和call用法?

题目: 以下代码执行后输出的值分别是?

var o={   
    x: 10,   
    foo: function () {       
        with (this) {            
            function bar() {                 
                alert(x);                 
                alert(this.x);            
            }             
            var x=20;          
            (function() {                      
                bar();                 
            })();         
            bar.call(this);       
       }   
   } 
} 
o.foo();

我不明白的:
第二行x : 10和直接写x = 10有什么区别吗?
第四行with(this),作用应该是延长作用域链?那在本题中具体是什么情况?
在var x = 20后,再次调用bar()为什么第一个是undefined,第二个是20?

感觉这道题考察的蛮多的,拿出来和大家讨论下。题目测试结果:undefined, undefined, undefined, 20.


这道题目真的好坑,我搞了一天,才彻底的搞懂,感谢楼上的两位前辈的分享!

我的总结放在 github 上 :)

欢迎 fork & pull request

谢谢分享!


var o={   
    x: 10,   
    foo: function () {       
        //A
        //B
        with (this) {        
            //此处的函数声明 bar 因为是函数声明语句的关系,其声明会被提升到函数的顶部,所以与放在A处相同
            function bar() {                 
                console.log(x);                 
                console.log(this.x);            
            }   
              
            var x=20;//也是涉及变量声明提升的问题,B处的代码为var x;此处的等价代码为x=20;因为with语句的关系,变为对this中的属性x赋值          
            (function() {                      
                bar();  //此时bar匿名函数外层函数foo中定义的函数对象,此时this为全局对象               
            })();         
            bar.call(this);  ////此时bar匿名函数外层函数foo中定义的函数对象 ,此时this为传入的对象o    
       }   
       
       console.log(this.x);
       console.log(this.bar);

       
   } 
} 
o.foo();

==在o对象中没有定义bar函数的情况下等价的代码为====

var o={   
    x: 10,   
    foo: function () {       
        //A
        function bar() {                 
                console.log(x);                 
                console.log(this.x);            
            }   
             
        //B
        var x;
        with (this) {         
            x=20;         
   
       }   
        (function() {                      
                bar();              
            })();         
        bar.call(this); 

       
   } 
} 
o.foo();

那么假设o中
没有属性x,会是什么结果呢


如果去的o对象中的x属性,将其修改为全局变量的会是什么结果呢

var x=10;
var o={
    foo: function () {
        //A
        function bar() {
            console.log(x);
            console.log(this.x);
        }
        //B
        var x;
        with (this) {
            x=20;

        }
        (function() {
            bar();
        })();
        bar.call(this);


    }
}
o.foo();

结果输出为 20,10,20,undefined
就是如果with包裹的对象如果没有对应的属性x的,那么x就会变为局部变量-如果函数中声明的话,或成为全局变量-如果函数中没有声明过的话。在当前的函数中x就成为foo函数的局部变量。
bar函数第1次执行,因为bar有闭包,所以console.log(x);输出20;this为全局对象,所以console.log(this.x);
输出10。
bar.call(this);将o作为函数执行上下文,this就为o,o没有属性x,
所以输出为 20,undefined

如果代码这样执行

var p=o.foo;
p();

那么输出输出为undefined 20 undefined 20
因为with(this) this为全局对象,全局对象有属性x,故其值被设置为20,而foo指向的函数中的定义的内部变量x没有被赋值,为undefined


第二行x : 10和直接写x = 10有什么区别吗?

o是一个对象字面了,题目是想把x作为它的属性,所以这么写。而 x = 10这种形式,只能写在函数内:

x: function () { x = 10; return x;}

第四行with(this),作用应该是延长作用域链?那在本题中具体是什么情况?

with是为对象访问提供命名空间式的速写方式。 题目中, 把this传给了with, 那么本来要通过this.x来访问x属性的, 现在只需通过x访问即可,所以,后面的var x = 20相当于o.x = 20

在var x = 20后,再次调用bar()为什么第一个是undefined,第二个是20?

第一次调用bar()是在匿名函数中:

(function() {
   bar();
})();

我们知道,匿名函数中this指向的是全局对象(window), 所以,这里输出两次undefined

接下来通过bar.call(this)的方式调用bar(),此时的作用域链中不存在x变量(提示:var x = 20相当于 o.x = 20),所以alert(x)undefined,而此时的this就是对象o,所以this.x20.

【热门文章】
【热门文章】