2010-04-11 57 views
6

我正在尝试创建一个UserDon对象,并尝试以编程方式生成get和set方法(基于John Resig的专业Javascript书第37页),并且正在Firefox 3.5上测试此方法在javascript中动态创建get/set方法

问题是:在函数UserDon中,“this”是指窗口对象而不是UserDon对象。

所以在调用var userdon = new UserDon(...)后,我在窗口对象(也是setage和getage)上创建了setname和getname方法。

我该如何解决这个问题?

function UserDon(properties) { 
    for(var i in properties) { 
    (function(){ 
     this[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     this[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
     })(); 
    } 
} 

var userdon = new UserDon({ 
    name: "Bob", 
    age: 44 
}); 
+1

好问题。否则,如果你没有在getter/setter中做任何额外的操作,你最好只使用公共属性并放弃方法开销。 :) – deceze 2010-04-11 04:52:31

回答

7

您正在使用的this值属于你必须在循环中自动调用函数表达式,当你以这种方式调用的函数,this总是指的是全局对象。

编辑:我错过了一个事实,即函数表达式是试图使变量捕捉处理循环内的getter/setter创建,但循环变量i,需要在为了一个参数传递要做到这一点,因为函数表达式是存在的,上下文(外this)应该被保留:

function UserDon(properties) { 
    var instance = this; // <-- store reference to instance 

    for(var i in properties) { 
    (function (i) { // <-- capture looping variable 
     instance[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     instance[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
    })(i); // <-- pass the variable 
    } 
} 

var userdon = new UserDon({ 
    name: "Bob", 
    age: 44 
}); 

userdon.getname(); // "Bob" 
userdon.getage(); // 44 

您还可以使用call方法来调用函数表达式,保存上下文(的this值)并介绍CING的循环变量到新的范围在一个单一的步骤:

function UserDon(properties) { 
    for(var i in properties) { 
    (function (i) { // <-- looping variable introduced 
     this[ "get" + i ] = function() { 
     return properties[i]; 
     }; 

     this[ "set" + i ] = function(val) { 
     properties[i] = val; 
     }; 
    }).call(this, i); // <-- preserve context and capture variable 
    } 
} 

我还建议使用一个if (properties.hasOwnProperty(i)) { ... }for...in循环内,以避免在从Object.prototype继承用户扩展属性迭代。

+1

如果没有自动调用函数,getname()和getage()将返回44,因为闭包引用数组的最后一个值,即age,请参阅本书的第29页。 – portoalet 2010-04-11 08:04:40

+0

@portoalet:你是对的我错过了这一点,但这还不够,'i'变量应该作为参数传递给该函数,并且'this'值应该保留,请参阅我的编辑。 – CMS 2010-04-11 08:25:26

+0

谢谢,它现在完美。 – portoalet 2010-04-11 08:41:06

0

使用2个参数获取泛型函数可能是一个更好的主意:属性名称和值(或者只是getter的名称)。 这个函数会检查这个属性是否存在一个特殊函数,如果没有,就会改变这个属性的值(或者返回它的getter值)。

0

这里是我会怎样代码时: -

function UserDon(properties) { 
    var self = this; 
    for(var i in properties) { 
    (function(prop){ 
     self[ "get" + prop ] = function() { 
     return properties[prop]; 
     }; 

     self[ "set" + prop ] = function(val) { 
     properties[prop] = val; 
     }; 
     })(i); 
    } 
} 
1

您还可以使用鲜为人知的
__defineGetter__("varName", function(){});
__defineSetter__("varName", function(val){});

虽然他们是非标准[如X-HTML替换内容类型]他们是由大多数非ie浏览器支持[chrome,firefox]

语法应该是:

benjamin = new object(); 
benjamin.__defineGetter__("age", function(){ 
    return 21; 
}); 

或者,你可以,如果这是一个锻炼与原型接近这个

benjamin = { 
    get age() 
    { 
    return 21; 
    } 
} 
+0

以前从未见过这个。你自己在用这个吗? – portoalet 2010-04-12 11:57:20

+1

我只用它来调试变量被获取/设置的地方。你定义了Setter(“variableName”,outputStackTrace);它也适用于CSS样式。例如,你说'object.style .__ defineGetter __(“left”,outputStackTraceFunction);'出于某种原因,人们不知道这个函数。可能是因为它的非标准? – Warty 2010-04-12 20:26:51