【问题标题】:Avoiding use of "this" in constructors避免在构造函数中使用“this”
【发布时间】:2016-05-01 01:52:09
【问题描述】:

我正在寻找这种结果:

var Dog = function() {
  this.tail = 1;
  var tail = this.tail;
  this.print = function() {
    console.log(tail);
  };
};

我在哪里使用

tail = this.tail;

避免在打印函数体中使用 this 关键字。然而,这种方法似乎有点老套,我觉得他们必须是一种更好/更标准/不同的方式来做这种事情。

我希望这样做的原因是因为我需要将一些以前是全局变量和函数的代码转换为对象构造器,并且在所有变量前面加上 this 关键字会很多工作量,并且会使代码更难看。

任何见解都是有用的,感谢您查看。

【问题讨论】:

  • 您可以改用闭包。但它会隐藏所有变量,使其不被对象外部访问。
  • "会让代码变得更丑陋。" --- 它不会。
  • 使用var(或类似的)来声明变量!!!
  • 现在我明白你为什么要这么做了!我认为 Oriol 的意思是你应该写 var tail = this.tail 而不是 tail = this.tail。我同意这样更好。
  • 如果对this 的持续引用让您难以接受,您可能想尝试CoffeeScript。除非您使用类似元 JavaScript 的语言,否则这在 JavaScript 中是不可避免的。 @tail is equivalent to this.tail。你使用 JavaScript 的次数越多,this 对你的困扰就越少。这就像在抱怨“the”在英语中的出现频率如此之高。

标签: javascript oop prototype


【解决方案1】:

下面的呢?我测试了它,它有效;)

var Dog = function() {
    this.tail = 1;
    this.print = function() {
        console.log(this.tail);
    };
};

var Dog = function() {
    var tail = 1;
    this.print = function() {
        console.log(tail);
    };
};

只有一个区别:this.tail 可以在全局范围内编辑,var tail 不能。但我认为在这种情况下这不是问题。

编辑:没有this的访问尾部

var Dog = function() {
    var tail = 1;
    this.getTail = function() {
        return tail;
    };
    this.setTail = function(newTail) {
        tail = newTail;
    };

    this.print = function() {
        console.log(tail);
    };
};

【讨论】:

  • 感谢您的回答。不幸的是,你的第一个例子正是我想要避免的。因为我的函数中有很多变量,所以我想避免在实例变量前面加上 this。在您的第二个示例中,尾部不能这样引用:(new Dog).tail; 这是必要的。
  • 只有这两种方式,你自己决定吧。将它们混合在一起总是不令人满意的,因为你有两个用于相同目的的变量可以有不同的值。
  • 在第二个例子中,有一种方法可以通过定义 getter 和 setter 方法(或者只是其中一个,你想要的方式)来访问 tail
【解决方案2】:

是的,您可以这样做。但是,您必须创建一个私有变量,然后使用object.defineProperty 通过公共属性公开它。您必须注意浏览器compatibility issues。例如,直到 IE9 才支持 object.defineProperty。

例子:

var log = function(message) {
  $('#log').append('<div>' + message + '</div>');
}

var Dog = function(aNumber) {
  //Create private variable for tail.  
  var tail = aNumber;

  //Create public property for tail.
  //BTW, it is generally bad practice to name a property the same name as a private variable.
  Object.defineProperty(this, 'tail', {
    get: function() {
      return tail;
    },
    set: function(value) {
      tail = value;
    }
  });

  log('ctor tail:' + tail);
  log('ctor this.tail:' + this.tail);

  this.print = function() {
    log('print tail :' + tail);
    log('print this.tail :' + this.tail)
  };
};

var firstDog = new Dog(1);
var secondDog = new Dog(2);

firstDog.tail = 3;
secondDog.tail = 4;

firstDog.print();
secondDog.print();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='log' />

在您最初的问题中,您在全局范围内引用了 tail 。示例:

tail = this.tail;

在这种情况下,如果您实例化多个 Dog 实例,每个实例将引用与 this.tail 不同的相同版本的 tail。

例子:

var log = function(message) {
  $('#log').append('<div>' + message + '</div>');
}

var Dog = function(aNumber) {
  this.tail = aNumber;
  //Because tail hasn't been declared your referring to tail in global scope.  This is bad! 
  tail = this.tail;
  log('ctor tail:' + tail);
  log('ctor this.tail:' + this.tail);
  this.print = function() {
      log('print tail:' + tail);
      log('print this.tail:' + this.tail);
  };
};

var firstDog = new Dog(1);
var secondDog = new Dog(2);
firstDog.print(); //tail is 2 when you want it to be 1
secondDog.print();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='log' />

在您的更新中,您声明了这样的尾部:

var tail = this.tail;

这确实创建了一个作用域为 Dog 的构造函数的私有变量。但是这样会导致tail的结果不一致,this.tail会保持不同的值。

例子:

var log = function(message) {
  $('#log').append('<div>' + message + '</div>');
}

var Dog = function(aNumber) {
  this.tail = aNumber;
  //Now you have tail scoped to this constructor/closure.  However, this.tail and tail will reference different variables.
  var tail = this.tail;
  log('ctor tail:' + tail);
  log('ctor this.tail:' + this.tail);
  this.print = function() {
    log('print tail :' + tail);
    log('print this.tail :' + this.tail);
  };
};

var firstDog = new Dog(1);
var secondDog = new Dog(2);

firstDog.tail = 3;
secondDog.tail = 4;

firstDog.print();
secondDog.print();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='log' />

如果您出于某种原因无法使用 object.defineProperty,那么您将无法在变量前加上 this。但是,为了确保它 100% 安全,您需要在构造函数中使用别名 this

例子:

var log = function(message) {
  $('#log').append('<div>' + message + '</div>');
}

var Dog = function(aNumber) {
  var self = this
  self.tail = aNumber;
  log('ctor self.tail:' + this.tail);
  this.print = function() {
    log('print self.tail :' + self.tail);
  };
};

var firstDog = new Dog(1);
var secondDog = new Dog(2);

firstDog.tail = 3;
secondDog.tail = 4;

firstDog.print();
secondDog.print();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='log' />

顺便说一句,John Resig 整理了一个很棒的 resource 来更好地理解 JavaScript,包括变量作用域。我强烈建议您这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-22
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-30
    • 2014-11-30
    相关资源
    最近更新 更多