Javascript 为未命名的局部变量定义Setter/Getter:不可能?
关于StackOverflow,前面有几个问题询问如何通过作用域链访问局部变量,例如,如果您想使用括号表示法和字符串引用局部变量,则需要类似于Javascript 为未命名的局部变量定义Setter/Getter:不可能?,javascript,scope,closures,local,setter,Javascript,Scope,Closures,Local,Setter,关于StackOverflow,前面有几个问题询问如何通过作用域链访问局部变量,例如,如果您想使用括号表示法和字符串引用局部变量,则需要类似于\uuu local\uuu[“varName”]的内容。到目前为止,我还没有找到实现这一点的最黑客的方法,而且在利用了我所知道的每一个技巧数小时之后,还没有想出一个方法 它的目的是在任意未加密变量上实现getter/setter。Object.defineProperties或\uuuuu defineGet/Setter\uuuu需要调用上下文。对于全
\uuu local\uuu[“varName”]
的内容。到目前为止,我还没有找到实现这一点的最黑客的方法,而且在利用了我所知道的每一个技巧数小时之后,还没有想出一个方法
它的目的是在任意未加密变量上实现getter/setter。Object.defineProperties或\uuuuu defineGet/Setter\uuuu
需要调用上下文。对于全局或窗口上下文中的属性,可以实现使用setter/getter直接引用对象的目标
Object.defineProperty(this, "glob", {get: function(){return "direct access"})
console.log(glob); //"direct access"
即使在使用自定义扩展的测试中,我编译成了一个修改的Chrome,该Chrome在创建任何窗口之前运行,其中上下文是实际的全局上下文,即使试图在全局上下文中直接调用this
,也会使我的程序崩溃,我也可以顺利完成这项工作:
Object.defineProperty(Object.prototype, "define", {
value: function(name, descriptor){
Object.defineProperty(this, name, descriptor);
}
};
define("REALLYglobal", {get: function(){ return "above window context"; }});
然后,它在以后创建的所有帧中都可以通过指定的getter/setter作为全局路由使用。旧的\uuuuu defineGet/Setter\uuuuu
也可以在该上下文中工作,而不指定调用它的内容(但在Firefox中不起作用,上面的方法可以)
因此,基本上可以为对象上的任何变量定义get/set保护,包括直接调用对象的窗口/全局上下文(您不需要window.propname
,只需要propname
)。这就是无法引用未注释的作用域变量的问题,因为它是唯一可以在可访问的作用域中但没有可寻址容器的类型。当然,它们也是最常用的,所以这不是边缘情况。这个问题也超越了当前ES6/Harmony中代理的实现,因为这是一个无法用语言语法处理本地对象容器的问题
我希望能够做到这一点的原因是,它是允许在数组和哈希等复杂对象中使用大多数数学运算符重载并导出复杂结果值的唯一障碍。我需要能够在为重载设置的对象类型上设置值的情况下钩住setter。如果对象可以是全局对象,也可以是包含在父对象中的对象,这可能就是我要讨论的。它在a.myObject
中仍然很有用,但目标是使其尽可能透明可用
不仅如此,能够完成这样的任务真的很有用:
var point3d = function(){
var x, y, z;
return {
get: function(){ return [x, y, z]; },
set: function(vals){ x=vals[0]; y=vals[1]; z=vals[2]; }
};
};
(这类似于ES6的解构,但有更通用的应用程序用于实现附加到获取/设置的功能,而不仅仅是传输复杂的值)。即使是这一基本代码也将完全失败:
var x = {myname: "intercept valueOf and :set: to overload math ops!", index: 5};
x++; //x is now NaN if you don't implement a setter somehow
我不在乎解决方案有多老套,在这一点上,我只是强烈地好奇它是否能够实现,即使它需要打破现有的每一个最佳实践。到目前为止,我已经通过重新定义/拦截/修改
对象.prototype.valueOf/toString
,函数.prototype
函数.prototype.constructor
,函数.prototype.call/apply
,参数.callee.caller
,使Firefox和Chrome崩溃了几百次,在试图追溯上下文的过程中,出现了无限递归错误等等。我能做的唯一一件事就是用eval和动态构建代码块来包装整个过程,这对我来说是一座太远的桥,我永远无法实际使用。另一个远程成功的方法是将与
结合使用,并在容器上预先定义所有局部变量,但这显然是非常具有侵入性的,最重要的是将与
结合使用,答案似乎是否。我一直在寻找这样的行为很长一段时间了。我还没有想出任何可行的解决办法。似乎相似。Python具有nicelocals
关键字。这在具有代理的环境中目前是可能的。这将是node>0.6作为node-harmony\u代理运行,或者是>0.7作为node-harmony运行。铬金丝雀(不确定是否已经脱销)大约:底部的旗帜,实验javascript。Firefox已经有一段时间没有标志了
因此,当ES6变得更加正式时,这可能不起作用,但现在它在一定程度上起作用了
var target = (function(){
var handler = Proxy.create(Proxy.create({
get: function(r, trap){
return function(name,val,c,d){
if (trap === 'get' || trap === 'set') {
name = val;
val = c;
}
console.log('"'+trap + '" invoked on property "'+name+'" ' + (val?' with value "'+val+'"':''));
switch (trap) {
case 'get': return target[name];
case 'set': return target[name] = val;
case 'has': return name in target;
case 'delete': return delete target;
case 'keys': return Object.keys(target);
case 'hasOwn': return Object.hasOwnProperty.call(target, name);
case 'getPropertyDescriptor':
case 'getOwnPropertyDescriptor': return Object.getOwnPropertyDescriptor(target, name);
case 'getPropertyNames':
case 'getOwnPropertyNames': return Object.getOwnPropertyNames(target);
case 'defineProperty': return Object.defineProperty(target, name, val);
}
}
}
}))
var target = {
x: 'stuff',
f: { works: 'sure did' },
z: ['overwritten?']
};
with (handler){
var z = 'yes/no';
if (x) {
//x
} else {
x = true;
}
console.log(f.works);
if (f.works) {
f.works = true;
delete f;
}
}
return target
})()
// "getPropertyDescriptor" invoked on property "z"
// "getPropertyDescriptor" invoked on property "z"
// "getPropertyDescriptor" invoked on property "x"
// "get" invoked on property "x"
// "getPropertyDescriptor" invoked on property "console"
// "getPropertyDescriptor" invoked on property "f"
// "get" invoked on property "f"
// sure did
// "getPropertyDescriptor" invoked on property "f"
// "get" invoked on property "f"
// "getPropertyDescriptor" invoked on property "f"
// "get" invoked on property "f"
// "getPropertyDescriptor" invoked on property "f"
target: { x: 'Stuff', f: { works: true }, z: ['overwritten?'] }
点击或未点击,您需要注意不要通过简单地查看调试器中的代理来破坏浏览器。我必须将它封装在一个闭包中,以防止代理在全局范围内结束,否则它每次都会崩溃帧。关键是它在某种程度上是有效的,而其他任何东西都不起作用。既然您声明希望类似于window/global
,我假设您希望在window/global
之外的给定上下文中使用它。一种简单的方法是将with
语句与local
对象和实现对象的define
函数结合使用。以local
为目标定义属性。您可以将自己的代码放在with
块中
重要提示:with
重载本机局部变量(var、let、const
)。因此,保持清晰的代码并防止作用域和父/子上下文中的名称重复非常重要
让我们从上下文开始,在本例中我使用闭包,但也可以是函数、构造函数或任何其他上下文
// This closure represents any function, class or other scoped block.
(function (){
}());
接下来,我们添加存储容器和define
函数。这基本上是你应该总是从开始,如果你
// This is where we store the local property. (except: var, let, const)
const local = {};
// The define function is used to declare and define the local properties.
function define(name, descriptor){ Object.defineProperty(local, name, descriptor); }
// This with statement extends the current scope with local.
with(local){
// This is where your code goes.
}
local.setDirectly = "directly set value";
console.log(setDirectly); // logs "directly set value"
define("time", {
get: function(){
var date = new Date();
return date.getHours() + ":" + ("0" + date.getMinutes()).substr(-2);
}
})
console.log(time);
(function (){
var counterValue = 0;
define("count", {get: function(){ return counterValue++ }});
}());
console.log(count); // logs 0
console.log(count); // logs 1
// This closure represeents any function, class or other scoped block.
(function(){
// This is where we store the local property. (except: var, let, const)
const local = {};
// The define function is used to declare and define the local properties.
function define(name, descriptor){ Object.defineProperty(local, name, descriptor); }
// This with statement extends the current scope with local.
with(local){
// This is where your code goes.
// Defining a variable directly into local.
local.setDirectly = "directly set value";
console.log(setDirectly); // logs "directly set value"
// Defining local properties with the define function
// For instance a time variable that return the current time (Hours:Minutes)
define("time", {
get: function(){
var date = new Date();
return date.getHours() + ":" + ("0" + date.getMinutes()).substr(-2);
}
})
console.log(time); // logs HH:MM
// Or a counter property that increments each time it's been accessed.
(function (){
var counterValue = 0;
define("count", {get: function(){ return counterValue++ }});
}());
console.log(count); // logs 0
console.log(count); // logs 1
console.log(count); // logs 2
console.log(count); // logs 3
}
}());
Object.defineProperty(window, 'prop', {
get: function () {
alert('you just got me')
},
set: function (val) {
alert('you just set me')
},
configurable: true});