eval是一个神奇的方法,可以用它来动态执行代码,以此达到常规办法做不到的事情。本文介绍使用eval来获取和修改上下文变量的办法。
请先看下面的代码:
function A(){
var i=0;
this.set=function(_i){
i=_i;
};
this.get=function(){
return i;
};
}
var a=new A;
a.set(2);
console.log(a.get());
直接用this.*来赋值会导致需要增加一层的缩进。为了减少缩进,通常我会使用prototype来写。但是prototype中的方法获取不到A内部的i,以往我会把var i改成this.i,于是代码就变成了下面这样:
function A(){
this.i=0;
}
A.prototype.set=function(_i){
this.i=_i;
};
A.prototype.get=function(){
return this.i;
};
var a=new A;
a.set(2);
console.log(a.get());
这样出现了一个问题,A的实例会把i作为属性暴露在外。虽然可以使用其他方式来实现外部代码无法读写i,但是我希望在A内部用局部变量的形式来保护i,这是最初需要实现的逻辑。
我想到了eval,它的用途是动态执行代码,而且被执行代码还可以获取到当前环境上下文的所有变量。那么只需要在A内部提供一个执行eval代码的接口给外部,外部代码就能方便的读写内部的东西了。
function A(){
var i=0;
// priv方法用于读写上下文变量
this.priv=function(k,v){
return eval(k+(arguments.length>1?('='+v):''));
};
}
A.prototype.set=function(_i){
var p=this.priv;
p('i',_i);
};
A.prototype.get=function(){
var p=this.priv;
return p('i');
};
var a=new A;
a.set(2);
console.log(a.get(),a.priv); // 输出2,priv方法
但是到这一步没有完整,因为对外暴露了priv接口,外部程序还是可以对A实例的局部变量i进行读写,所以还需要一个代理层来屏蔽这个接口。
function A1(){
var a=new A;
for(var x in a)
// 复制除了priv以外的属性到自身
if(x!=='priv')(function(x,t){
t[x]=function(){
return a[x].apply(a,arguments);
};
})(x,this);
// 返回的是a对象的影分身,具备a的一切属性,但是把priv给屏蔽了
};
m=new A1();
m.set(12);
console.log(m.get(),m.priv); // 输出12, undefined
到此算是大功告成了,以下是完整的例子,可以在浏览器控制台查看结果。
<meta charset='utf-8' />
<script>
function A(){
var i=0;
// priv方法用于读写上下文变量
this.priv=function(k,v){
return eval(k+(arguments.length>1?('='+v):''));
};
}
A.prototype.set=function(_i){
var p=this.priv;
p('i',_i);
};
A.prototype.get=function(){
var p=this.priv;
return p('i');
};
function A1(){
var a=new A;
for(var x in a)
// 复制除了priv以外的属性到自身
if(x!=='priv')(function(x,t){
t[x]=function(){
return a[x].apply(a,arguments);
};
})(x,this);
// 返回的是a对象的影分身,具备a的一切属性,但是把priv给屏蔽了
};
m=new A1();
m.set(12);
console.log(m.get(),m.priv); // 输出12, undefined
</script>
相关文档
暂无
随便看看
畅言模块加载中