【问题标题】:How to update original this when cloning with extend使用扩展克隆时如何更新原始内容
【发布时间】:2015-01-08 01:48:42
【问题描述】:

我正在尝试使用 jquery 扩展方法克隆一些对象。但是,在克隆我的对象后,我意识到克隆对象的某些方法正在修改原始对象的值,所以我认为两个对象的属性可能指向同一个变量。

在运行了一些测试之后,我发现我的克隆对象的属性被正确复制了……包括本地的self 变量(用于保存对类实例的原始this 的引用)。由于克隆的self 仍然指向原始实例,因此引用该变量的方法将针对原始实例的属性而不是它自己的实例:

var Animal = function() {

  var self = this;

  this.sound = "";

  this.talk = function(){
    alert(self.sound);
  };

};

var dog = new Animal();
dog.sound = "Woof";
dog.talk(); //Woof as expected

var cat = $.extend(true, {}, dog); 
cat.sound = "Meow";
cat.talk(); //Woof... but Meow was expected

extend 方法的行为确实有意义...但是是否有一种通用 方法来确保self 变量引用新的克隆对象?泛型是指self 变量可能有不同的名称(即_this 等),并且我想避免为每个类添加自定义方法只是为了更新self 变量。

您还应该记住,self 变量是私有的(有很多很好的理由保留它)所以这意味着您不能在实例之外设置它。

【问题讨论】:

  • extend 扩展对象,它不会创建新实例。我认为唯一(也是正确的)方法是创建一个新动物,而不是复制旧动物。
  • 或者,创建一个使用正确上下文更改属性的方法 -> jsfiddle.net/1572gy9o
  • 确实...以动物为原型并从那里创建新实例更有意义。您可以根据需要制作子级别。通过扩展将狗变成猫似乎有点奇怪。
  • @adeneo extend 仍然是我们谈论克隆对象时的参考方法,即使它不是主要目的。创建一个新实例将是一个易于实现的解决方案(在我的情况下),但我脑海中总是有一个声音在说“你这个懒惰的程序员,找到一个通用的解决方案!”。
  • 但创建新动物的通用且正确的解决方案是创建Animal 类的新实例,而不是克隆狗,可以这么说。 $.extend 不是类实例的引用,它通常不用于。

标签: javascript jquery clone


【解决方案1】:

事实上,这个用例不需要var self = this 构造。

刚刚在这里做了一个小测试:http://jsfiddle.net/quwdeafd/
看看this的范围。 这不是你要找的吗?

var Animal = function() {

  this.sound = "";
  this.talk = function(){
      console.log(this); //Logs Animal the first time, object the second 
      console.log(this.sound); //Logs Woof and meow 
  };

};

var dog = new Animal();
dog.sound = "Woof";
dog.talk(); 

var cat = $.extend(true, {}, dog); 
cat.sound = "Meow";
cat.talk(); 

小备注:通常习惯将此方法放在对象的原型上:

Animal.prototype.talk = function(){
      console.log(this); 
      console.log(this.sound);
  };

因为它使方法立即可用,而无需在每次实例化时都进行初始化。

【讨论】:

  • var self = this 实际上是一个相当好的做法,因为this 会根据范围而变化,因此如果您需要在更深的范围内访问this,其中this 会发生变化,请将其分配给@ 987654331@,或任何变量都允许在更深的范围内访问它。 Check out this StackOverflow Question
  • 没有self 变量也能正常工作,但我认为关键是要真正保留它,因为 OP 似乎需要它来做某事?
  • @BrandonAnzaldi 我同意,我使用 _.bind 代替,相对频繁。但是对于这个例子,它似乎没有任何作用。
  • @adeneo 可能,我不知道。但如果没有,那么解决方案非常简单:-)
  • 我猜你已经知道我的 Animal 只是一个例子。正如 Brandon Anzaldi 指出的那样,我的真实课程有很多范围级别,当您输入这些范围时,self 非常方便(请参阅强制)。
【解决方案2】:

正如 adeneo 所指出的,问题在另一个层面。即使extend 通常被称为克隆方法,它也不是为此目的而设计的。这个问题中提到的问题是其局限性的一个很好的例子。

为了记录,我停止使用extend 方法进行克隆,我通过用this SO answer 中的克隆方法替换它解决了我的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    相关资源
    最近更新 更多