首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >有没有办法在Javascript数组中为惰性变量定义getter?

有没有办法在Javascript数组中为惰性变量定义getter?
EN

Stack Overflow用户
提问于 2010-06-02 03:17:28
回答 5查看 5.9K关注 0票数 14

我正在尝试将延迟计算的元素添加到数组中。这意味着它们的值在它们被访问之前是不会被计算或知道的。这类似于previous question I asked,但用于对象。

我最终为对象所做的是

代码语言:javascript
运行
复制
Object.prototype.lazy = function(var_name, value_function) {
  this.__defineGetter__(var_name, function() {
    var saved_value = value_function();
    this.__defineGetter__(var_name, function() {
      return saved_value;
    });
    return saved_value;
  });
}

lazy('exampleField', function() {
  // the code that returns the value I want
});

但我还没有想出一种方法来实现实数组。数组没有这样的setter。您可以将一个函数推送到一个数组中,但您必须将其作为一个函数来调用,以便它返回您真正想要的对象。我现在要做的是创建一个对象,并将其视为数组。

代码语言:javascript
运行
复制
Object.prototype.lazy_push = function(value_function) {
  if(!this.length)
    this.length = 0;
  this.lazy(this.length++, value_function);
}

所以我想知道的是,有没有办法做到这一点,同时仍然是在一个数组上,而不是在一个伪数组上?

更新:只有当value_function返回原始数据类型时,以下函数才有效。

代码语言:javascript
运行
复制
Array.prototype.lazy_push = function(value_function) {
  var a = this,
  i = this.length;
  this.push({
    toString: function() {
      return a[i] = value_function();
    }
  });
}

如果您尝试推送一个对象,例如其中包含属性的对象,则在直接访问该对象之前,您将无法访问这些属性。这不会发生在setter中,这就是为什么我想要一些Javascript的设置语法。现在,我将使用伪数组,这对于我正在做的事情来说已经足够了。

EN

回答 5

Stack Overflow用户

发布于 2010-06-10 23:53:20

没有。不幸的是,这是一件大事。

票数 2
EN

Stack Overflow用户

发布于 2010-06-13 00:15:40

好吧,除非我误解了你的问题,否则我相信我已经找到了一个简单的解决方案,它不需要所谓的"lazy_push“函数。

按照我上一个答案中的方法,创建一个MyArray类:

代码语言:javascript
运行
复制
function MyArray(){
     this.object = [];
 }

MyArray.prototype.push = function(what){
     this.object.push(what);
}

现在最重要的部分是getter函数,我们将创建一个getIdx()函数来获取数组中的值。然后,该函数使用'typeof‘运算符来确定返回值是否为函数。如果是,则返回函数返回的值,如果不是,则返回原始值。

代码更有意义:

代码语言:javascript
运行
复制
MyArray.prototype.getIdx = function(which){
     if(typeof this.object[which] == 'function'){
         alert("a function");
         //NOTICE THE '()' AT THE END OF THE NEXT LINE!!!
         return this.object[which]();
     }
     return this.object[which];
 }

希望如果我没有完全回答你的问题,你可以从这里弄清楚。

<-我的原创帖子->

这不是一个真正的答案,但有几个要点。

  1. 在Javascript中没有真正的数组,数组只是一个扩展对象(就像JS中的所有东西一样)
  2. 你最好不要向JS中的本机对象添加原型函数,你可能会意外地覆盖现有的属性,或者最终产生令人困惑的错误。例如,添加到Object的原型将添加到JS中的每个单独的对象(这就是一切),您需要绝对确保您希望JS中的每个类型都具有该属性。这是很危险的,因为如果你不小心覆盖了实际的数组()或对象()函数,你会破坏浏览器中的javascript,期间,刷新页面不会修复它。
  3. 不是添加到你正在修改的对象的原型中,而是创建一个扩展它的新对象。例如,如果您想要扩展Array类:

//使用对象变量创建构造函数,//该对象变量包含您希望扩展函数MyArray(){ this.object = [];}//创建引用对象的本机函数的函数MyArray.prototype.push = function(what){ this.object.push(what);} //Etc...等等……等等……

为本机对象函数编写所有的访问器方法不一定很有趣,但它保证了Javascript引擎的安全。

票数 2
EN

Stack Overflow用户

发布于 2010-06-11 20:55:01

不是吧。在JavaScript中不能重载索引器操作符是一个很大的缺点。哦,好吧。我们只需要有创意,想出一个不同的解决方案。这是一件好事(也很有趣)。:-)

LLer,你解决的方案是非常好的。太棒了。遇到真正了解JavaScript的人是令人耳目一新的。

读完这个问题后,我有了一个史诗般的想法,并写了一些代码来娱乐它。我对这个问题的解决方案与您的解决方案以及其他许多以前做过的解决方案非常相似。但是,我觉得我想出了一些独特的,非常整洁的东西,所以我想分享它。

因此,我在CodePlex上托管了一个我的项目,其中我使用了一种非常类似jQuery的技术来定义属性(自包含的getter/setter函数),与您正在使用的非常相似。对于我想出的解决方案,我只是简单地从我的这段预先存在的代码中推断出来。下面是我对延迟加载数组索引的方法。从头开始...

让我们考虑一个名为"PageSize“的属性。下面是如何在我的技术中使用该属性:

代码语言:javascript
运行
复制
var MyClass = function() { }; // MyClass constructor.

var instance = new MyClass();
instance.PageSize(5);

alert(instance.PageSize());

请注意,该属性是一个单独的函数,其中提供一个值作为第一个参数将调用setter,省略该参数将调用getter。"PageSize“属性将被定义为MyClass类的一部分,如下所示:

代码语言:javascript
运行
复制
MyClass.prototype.PageSize = function(v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading); };

属性函数只是对utitily方法调用的包装,该方法执行实际的获取和设置。下面是GetSetProperty函数的一个片段:

代码语言:javascript
运行
复制
Object.prototype.GetSetProperty = function(name, value, loadFunction) {
    if (!this.Properties)
    {
        this.Properties = {};
    }

if (value)
{
    this.Properties[name] = value;
}
else
{       
    if (!this.Properties[name] && loadFunction)
    {
        this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
}
};

这样就可以处理属性了。但是,为了提供访问Array类型的可能属性的索引值的方法,我进一步修改了这段代码,如下所示:

代码语言:javascript
运行
复制
Object.prototype.GetSetProperty = function(name, value, loadFunction, index) {
  if (!this.Properties)
  {
    this.Properties = {};
  }

  if (typeof index === "number" && this.Properties[name] && this.Properties[name].constructor == Array)
  {
    return this.GetSetArrayProperty(name, index, value, loadFunction);
  }
  else 
  {
    value = index;
  }

  if (value)
  {
    this.Properties[name] = value;
  }
  else
  {    
    if (!this.Properties[name] && loadFunction)
    {
      this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
  }
};


Object.prototype.GetSetArrayProperty = function(name, index, value, loadFunction) {
  if (value)
  {
    this.Properties[name][index] = value;
  }
  else
  {
    if (!this.Properties[name][index] && loadFunction)
    {
      this.Properties[name][index] = loadFunction();
    }

    return this.Properties[name][index];
  }
};

需要像这样修改原型声明:

代码语言:javascript
运行
复制
MyClass.prototype.PageSize = function(i, v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading, i); };

阅读本文的每个人都可以在这里访问代码的工作集:http://jsbin.com/ajawe/edit

下面是带有测试的代码的完整清单:

代码语言:javascript
运行
复制
Object.prototype.GetSetProperty = function(name, value, loadFunction, index) {
  if (!this.Properties)
  {
    this.Properties = {};
  }

  if (typeof index === "number" && this.Properties[name] && this.Properties[name].constructor == Array)
  {
    return this.GetSetArrayProperty(name, index, value, loadFunction);
  }
  else 
  {
    value = index;
  }

  if (value)
  {
    this.Properties[name] = value;
  }
  else
  {    
    if (!this.Properties[name] && loadFunction)
    {
      this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
  }
};


Object.prototype.GetSetArrayProperty = function(name, index, value, loadFunction) {
  if (value)
  {
    this.Properties[name][index] = value;
  }
  else
  {
    if (!this.Properties[name][index] && loadFunction)
    {
      this.Properties[name][index] = loadFunction();
    }

    return this.Properties[name][index];
  }
};


// Here's a nifty function that declares the properties for you.
Function.prototype.CreateProperty = function(propertyName, loadFunction) {
  eval("this.prototype['" + propertyName.toString() + "'] = function(i, v) { return this.GetSetProperty('" + propertyName.toString() + "', v, " + eval(loadFunction) + ", i); };");
};




var myFunctionThatDoesLazyLoading = function() {
  return "Ahoy!";
};


var MyClass = function() { }; // MyClass constructor.
MyClass.prototype.PageSize = function(i, v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading, i); };

var instance = new MyClass();
alert(instance.PageSize()); // PageSize is lazy loaded.

instance.PageSize(5); // PageSize is re-assigned.
alert(instance.PageSize()); // Returns the new value.

instance.PageSize([1, 2, 3]); // PageSize is re-assigned to have an Array value.
alert(instance.PageSize(2)); // Returns the value at index 2 of the Array value.

instance.PageSize(2, "foo"); // Re-assigns the value at index 2.
alert(instance.PageSize(2)); // Returns the new value at index 2.

MyClass.CreateProperty("NewProp", function() { return ["a", "b", "c"]; }); // Demo of the CreateProperty function.
alert(instance.NewProp());
alert(instance.NewProp(1));
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2952573

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档