简体   繁体   English

JavaScript函数中引用数组的模式

[英]Pattern for referencing array in JavaScript Function

Consider a simple factory which self-updates - 考虑一个可以自我更新的简单工厂-

function MyFactory(){

  var _data = []; // initial value

  function onLoad(response){

    // assign the incoming value to our '_data' variable
    _data = response;

  }

  // some sort of ajax to get the data
  function getData() {

     // ajax.fecth('/url', onLoad);

     // pseudo-ajax
     onLoad([4,5,6]);

  }

  // public methods / properties
  this.getData = getData;
  this.data = _data;

}

(Can you see the problem here? Worth taking a second.) I'll spell it out - (您能在这里看到问题吗?值得花点时间。)我会说清楚-

// create the object
var factory = new MyFactory();

// get the data
console.log(factory.data);  // [] ok

// get new data [1,2,3], and assign to the data property
factory.getData();

// what have we now got?
console.log(factory.data); // [] argh, expected [1,2,3]

This is not what we want at all. 这根本不是我们想要的。 this.data should return the new array... but doesn't. this.data应该返回新的数组...但是不会。 It continues to reference the original array, even though we've internally updated our object. 即使我们在内部更新了对象,它仍继续引用原始数组。

There is a solution - instead of replacing the value of data, we can do this - 有一个解决方案-我们可以代替替换数据值,而不是-

function onLoad(response){
    // take care to reuse the object
    _data.length = 0;
    Array.prototype.push.apply(_data, response);
}

... which is okay, but feels a bit of a hack. ...没关系,但是有点破绽。

My question is - what would be a better pattern of MyFactory which would ensure that we can update its data property so that it always returns the expected value. 我的问题是-什么是MyFactory的更好模式,它将确保我们可以更新其data属性,使其始终返回期望值。

You probably think that by doing: 您可能会这样认为:

this.data = _data;

You are actually linking both variables and whatever happens to _data will happen to this.data . 您实际上是在链接两个变量,并且_data发生的任何情况都将发生在this.data This is not the case, it just end up copying the object reference. 事实并非如此,它最终只是复制对象引用。 Which means that both variables are pointing to the same object reference (let's say the object is "A") 这意味着两个变量都指向相同的对象引用(假设对象为“ A”)

this.data === A
_data === A

What your onLoad method does is create a new object (lets call it "B") and assign it to data . 您的onLoad方法所做的是创建一个新对象(将其称为“ B”)并将其分配给data

this.data === A
_data === B

_data is not part of the object unlike this.data , so it's not accessible from the object. _datathis.data不同,它不是对象的一部分,因此无法从对象访问它。 This is why it doesn't work. 这就是为什么它不起作用的原因。

There's really no reason to work this way. 确实没有理由以这种方式工作。 You obviously want the data to be public, there's no reason to keep it in the constructor scope. 您显然希望data是公开的,没有理由将其保留在构造函数范围内。

function MyFactory(){

  var that = this; // object reference which private methods can use

  function onLoad(response){

    // assign the incoming value to our '_data' variable
    that.data = response;

  }

  // some sort of ajax to get the data
  function getData() {

     // ajax.fecth('/url', onLoad);

     // pseudo-ajax
     onLoad([4,5,6]);

  }

  // public methods / properties
  this.getData = getData;
  this.data = [];

}

In addition to MinusFour's answer, you have created a bit of confusion with getData . 除了MinusFour的答案之外,您还对getData造成了一些困惑。 Usually, a getter gets a property of an object that is private. 通常,getter获取私有对象的属性。 It's counterpart is setter that sets the value. 相应的是设置值的设置器。

Your getData actually sets the "private" value (which is a closure), then you try to read it as a property. 您的getData实际上设置了“私有”值(这是一个闭包),然后尝试将其作为属性读取。 So if you just create a new getter and change getData to a setter, you're done: 因此,如果仅创建一个新的getter并将getData更改为setter,就可以完成:

 function MyFactory(){ var _data = []; // initial value function onLoad(response){ _data = response; } function getData() { onLoad([4,5,6]); } // setter to get data and set the value of _data this.setData = getData; // getter to return the value of _data this.getData = function() { return _data; }; } // create the object var factory = new MyFactory(); // get the data document.write('data: ' + factory.getData()); // [] ok // get new data [1,2,3], and assign to the data property factory.setData(); // what have we now got? document.write('<br>data: ' + factory.getData()); // expected [4,5,6] 

You could overload the getter so that if you provide an argument, it sets the value immediately, or if no value is provided, do the AJAX thing. 您可以使getter重载,这样,如果提供一个参数,它将立即设置该值,或者如果没有提供任何值,请执行AJAX操作。

Alternatively, you can define data as a getter: 另外,您可以将数据定义为吸气剂:

 function MyFactory(){ var _data = []; function onLoad(response){_data = response;} function getData() {onLoad([4,5,6]);} // public methods - setter and getter this.getData = getData; // Create a data property as a getter Object.defineProperty(this, 'data', {get: function() {return _data;}}); } var factory = new MyFactory(); document.write('Data: ' + factory.data); // [] ok factory.getData(); // what have we now got? document.write('<br>Data: ' + factory.data); // expected [4,5,6] 

Consider method naming conception. 考虑方法命名概念。 Create public getter method to access your private data on demand. 建立公共 getter方法来按需访问您的私人数据。

function MyFactory(){

  var _data = []; // initial value

  function onLoad(response){

    // assign the incoming value to our '_data' variable
    _data = response;

  }

  // some sort of ajax to get the data
  function loadData() {

     // ajax.fecth('/url', onLoad);

     // pseudo-ajax
     onLoad([4,5,6]);

  }

  // public methods / properties
  this.loadData = loadData;
  this.getData = function(){
      return _data;
  }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM