我典型的JS类结构如下所示:
MyClass = function(args)
{
this.myProp1 = undefined;
this.myProp2 = args[0];
//...more member data
this.foo = function()
{
return this.myProp1 + this.myProp2; //<- the problem.
}
//...more member functions
}
//if MyClass extends a superclass, add the following...
MyClass.prototype = Object.create(MySuperClass.prototype);
MyClass.prototype.constructor = MyClass;
...我对JS的持续烦恼是我似乎必须在成员函数中连续使用this
才能访问这些函数所属的同一对象的属性。在其他几种语言中C#&amp;当成员函数处理同一类/实例中的成员数据时,可以安全地省略Java this
。 (我意识到JS的结构根本不同,因为它被设计为原型而不是层次化的继承语言。)
以另一种方式提出问题:有没有办法让未指明的范围不指向window
,而是指向this
的当前本地值?
P.S。我猜这是一种语言限制,但我想我还是会再次检查。
答案 0 :(得分:2)
有一个关键字可以部分地执行您想要的操作:with但强烈建议不要使用它,因为在某些情况下会有歧义。
如果您访问非现有成员,它将回退到window
对象。
所以你可以做的是声明你稍后要使用的所有属性,然后声明一个with
语句。
如果我有你的选择,我可能会改变主意跳过this
,或者如果可以的话,可以使用其他语言。
答案 1 :(得分:2)
我不确定是语言限制还是别的,但是你用于Class和成员函数创建的模式无助于实现你想要的。
为什么不尝试像这样的模块模式?
CalcModule = (function(){
var add = function(a, b) {
return a + b;
};
var sub = function(a, b) {
return a - b;
};
var _privateCalculation = function(){
};
return {
"add" : add,
"sub" : sub
};
});
在这里,您可以获得一个模仿私有成员的控件,而不是将它们放在返回对象中。我希望这会有所帮助。
更新:我不确定模块模式类的扩展。
更新:为函数声明添加了var
答案 2 :(得分:1)
在其他几种语言中,例如C#&amp; Java,当成员函数处理同一个类/实例中的成员数据时,可以安全地省略它。 (我意识到JS的结构根本不同,因为它被设计为原型而不是层次化的继承语言。)
这不是关于继承链,它在js中也是相当静态的。它是关于JS是一种动态语言,全局范围能够随意添加新变量,并且可以使用任意属性修改对象。
因此,实际上不可能使标识符动态地解析为局部变量或对象属性,并且我们希望每次都通过使用属性访问器来明确区分它们。
有没有办法让未指明的范围不指向窗口,而是指向当前的本地值?
“未指定的范围”是本地范围,它是静态确定和优化的。要使它指向一个对象(如果找不到该属性,则返回变量),您可以使用with
statement。然而,由于这种模糊性,它不仅速度慢,而且还被认为是不好的做法 - 查找(变量)可能受到非本地代码(与实例交互)的影响,这破坏了封装并且是可维护性问题。
我典型的JS类结构......
当然你也可以改变它,并使用通过闭包访问的局部变量作为成员(参见Javascript: Do I need to put this.var for every variable in an object?)。这解决了this
的问题,但也是a bit slower(尽管可能仍然比with
更快。)
答案 3 :(得分:1)
最好避免使用with
语句,因为with
语句的存在会禁用优化。此外,with
语句不能在严格模式下使用。请参阅ECMA262§12.10.1:“严格模式代码可能不包含 WithStatement 。在这样的上下文中出现 WithStatement 被视为 SyntaxError < /强>“。
一种选择是使用扩展为属性访问的语法扩展。例如,在CoffeeScript 0.3.2中,@property
被添加为this.property
的简写。
如果您不想使用CoffeeScript,可以使用sweet.js创建自己的宏。以下是添加@property
速记功能的宏的示例:
macro @ {
case { _ $x:ident } => { return #{ this.$x }; }
case { _ $x } => { return #{ this[$x] }; }
}
function Person(name) {
@name = name;
}
var person = new Person("Johnny Appleseed");
alert(person.name);
sweet.js编译器sjs
生成:
function Person$630(name$632) {
this.name = name$632;
}
var person$631 = new Person$630('Johnny Appleseed');
alert(person$631.name);
答案 4 :(得分:-1)
在这里为后代添加我自己的答案,因为在某个阶段,如果我被困在(1)前置this
和(2)使用可怕的with
之间,它可能是有用的是(3)rd解决方案。
假设我们不直接访问任何会员数据;相反,我们为每个数据属性都有getter和setter方法。
在这种情况下,可以使用Doug Crockford所讨论的私人概念:
MyClass = function()
{
var prop = undefined;
this.getProp() {return prop;}
this.setProp(value) {prop = value;}
//now in standard, non-getter and -setter methods, we can do...
this.foo = function()
{
return prop + prop; //<- no problem: no more 'this'
}
}
第(4)个解决方案,不太安全但也不那么冗长:
MyClass = function()
{
var prop = this.prop = undefined; //this.prop for read only! (unsafe)
this.setProp(value) {prop = this.prop = value;}
//now in standard, non-getter and -setter methods, we can do...
this.foo = function()
{
return prop + prop; //<- no problem: no more 'this'
}
}
在(4)中,我们只需要制定者,大大减少了冗长。
由于很少有包含大量逻辑的方法,因此效果很好。使用许多较小的方法,其绝对大小(所有这些访问方法)最终超过了每次访问本地成员时避免this
的好处。仍然 - 它确实导致更清晰的功能逻辑。