87,997
社区成员




var test="wrong"
Object.prototype.test="right";
var score=0;
void function f0(){
if(test=="right")score++;
}()
void function(){
if(test=="wrong")score++;
}()
var e="right";
try{
throw new Error;
} catch(e) {
e="wrong";
if(test=="right")score++;
}
if(e=="right")score++;
var f;
void function f(){
}
if(typeof f=="undefined")score++;
var err;
function a(){
var m="right";
var n;
return function(){
var err;
return arguments[0].call(this,arguments[1]);
}
}
try{
var b=a();
if(b(eval,"m")=="right")score++;
} catch(err) {
}
alert(score+"/6")
function MyConsole(obj){
var top={};
for(var i in Object.prototype){
top[i]=Object.prototype[i];
}
var low = {};
for(var i in obj){
low[i]=obj[i];
}
function merge(o,d){
for(var i in d){
o[i]=d[i];
}
}
merge(low,top);
this.global = low;
}
MyConsole.prototype.log = function(key){
alert(this.global[key]);
}
function myWindow(){
this.test = 'wrong';
this.console = new MyConsole(this);
}
win = new myWindow();
win.console.log('test');
Object.prototype.test = "right";
var console = new MyConsole(win);
console.log('test');
test = 'gss';
///放断点. 在console中看.
Object.prototype.test = "right";
///放断点. 在console中看.
function MyConsole(obj){
this.global = obj;
}
MyConsole.prototype.log = function(key){
alert(this.global[key]);
}
function myWindow(){
this.console = new MyConsole(this);
}
win = new myWindow();
win.test = 'wrong';
win.console.log('test');
Object.prototype.test = "right";
var console = new MyConsole(new myWindow());
console.log('test');
function MyConsole(obj){
this.global = obj;
}
MyConsole.prototype.log = function(key){
alert(this.global[key]);
}
function myWindow(){
this.test = 'wrong';
this.console = new MyConsole(this);
}
myWindow = new myWindow();
myWindow.console.log('test');
Object.prototype.test = "right";
var console = new MyConsole({});
console.log('test');
test = 'gss';
Object.prototype.test = "right";
var $c = window.console.log(test);
var $A1 = new Object();
var $t1 = $A1.test; //在设置原型的test值之前就取值,那自然
Object.prototype.test = "right";
var $B1 = new Object();
var $t2 = $B1.test;
var $t11 = $A1.test; //敢问这里不是能取到right么?
window.test = 'wrong';
Object.prototype.test = "right";
function wrapConsole(){
var global={};
for(var i in Object.prototype){
global[i] = Object.prototype[i];
}
return function (key){
// test 在 说不好是Object函数 的一个closure层里面的值;
// 先找Object 中的 test,找不到window中的test.
alert(global[key] || window[key]);
}
}
myConsole = wrapConsole();
myConsole('test');
Object.prototype.test = "right";
console.log(test); //right
test = "wrong";
console.log(test); //怎么还是right?
Object.prototype.test = "right";
console.log(test); //right
test = "wrong";
console.log(test); //怎么还是right?
var $A1 = new Object();
var $t1 = $A1.test;
Object.prototype.test = "right";
var $B1 = new Object();
var $t2 = $B1.test;
Object.prototype.test = "right";
console.log(test); //right
test = "wrong";
console.log(test); //怎么还是right?
//先粘贴这一段
var test = "wrong";
Object.prototype.test = "right"
console.log(test);
//wrong对不对?
//接着第二次再粘贴这段代码
console.log(test);
//right了?灵异了?
void function f0(){
if(test=="right")score++;
}()
void function(){
if(test=="wrong")score++;
}()
函数表达式分两种,常用的匿名函数表达式(Anonymous Function Expression AFE)和命名函数表达式(Named Function Expression NFE)。他们的共同点是,都是函数表达式,和函数声明有本质区别。唯一不同的是,命名函数表达式内部可以通过函数名来访问函数自身(arguments.callee被废除),而这个函数名却不对外渗透。参见js版置顶帖【你自认为理解javascript?】第二题。ES对这个特性的规定是使用类似"new Object()"的形式创建一个特殊对象,这个对象只有一个属性,命名函数表达式的名字,指向这个函数的引用,并将这个特殊对象压入匿名函数表达式的作用域链顶端。这就解释了本例中,命名函数表达式查找test得到继承自Object的("right"),而匿名函数表达式查找test得到的是window下的("wrong")。然而新版本已经更正了此问题,特殊对象已经不再继承自Object,因此,本例中匿名函数和命名函数内部的test都应该是window.test。
测试chrome版本 33.0.1750.149 ,发现情况根本不是这样。分析得,从开发者工具F12粘贴入代码,代码是通过eval运行的,并且,使用了with(commandLineAPI){ // your code} 进行包裹。这个commandLineAPI对象提供了命令行可以直接访问的诸多API,而它是继承自Object的,因此代码从作用域链顶端的withBlock Scope找到test值。新建html粘贴入代码则此二例子test值皆为"wrong",表现正常。
======================================================
var e="right";
try{
throw new Error;
} catch(e) {
e="wrong";
if(test=="right")score++;
}
if(e=="right")score++;
catch块中的代码执行的时候,作用域链顶端会插入catchBlock Scope,这个异常e就是在这里声明的。按出题者所述,这个catchBlock Scope也是控制作用域的特殊对象,因此test值在这个特殊对象中找到,值为“right”。然而现在的浏览器对控制作用域的这种内部特殊对象都做了修正,他们不再继承自Object(同命名函数表达式)。
至于变量e,catch内部的e来自catchBlock scope,因此catch内部修改e对外部没有影响。这个解释通了。
相同的还有finally块。
======================================================
var f;
void function f(){
}
if(typeof f=="undefined")score++;
这个很好解释,命名函数表达式,f值只对函数表达式内部有效,不会渗透到外部作用域。因此f还是undefined。chrome解析正确。
======================================================
var err;
function a(){
var m="right";
var n;
return function(){
var err;
return arguments[0].call(this,arguments[1]);
}
}
try{
var b=a();
if(b(eval,"m")=="right")score++;
} catch(err) {
}
这个涉及到js引擎对eval的处理。按题意,m值应该可以正确获取,但是现代浏览器对eval的处理更多的想一个保留字,eval使用不当会影响js的优化。因此现在的处理方式是,如果直接使用eval,则eval会引用当前EC的scope chain,如果间接使用eval,则scope chain中只有global。因此这个m应该是获取不到的。换成这样便可:
var err;
function a(){
var m="right";
var n;
return function(){
var err;
return eval(arguments[0]);
}
}
try{
var b=a();
if(b("m")=="right")score++;
} catch(err) {
}