题目: 以下代码执行后输出的值分别是?
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.x
是20
.