JS类没有经常引用“this”进行成员访问

时间:2014-07-27 15:32:03

标签: javascript class oop this

我典型的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。我猜这是一种语言限制,但我想我还是会再次检查。

5 个答案:

答案 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的好处。仍然 - 它确实导致更清晰的功能逻辑。