Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/441.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当且仅当使用JavaScript时,如何计算JavaScript中的变量?_Javascript_Variables - Fatal编程技术网

当且仅当使用JavaScript时,如何计算JavaScript中的变量?

当且仅当使用JavaScript时,如何计算JavaScript中的变量?,javascript,variables,Javascript,Variables,这就是我现在正在做的 var foo = function() { var x = someComplicatedComputationThatMayTakeMoreTime(); this.foo = function() { return x; }; return x; } 它可以工作,但只有当foo作为这样的函数调用时才可以 foo(); 但是如果我想把它叫做一个有值的正态变量呢?我可以将代码修改为 var foo = function() { var x = some

这就是我现在正在做的

var foo = function() {
  var x = someComplicatedComputationThatMayTakeMoreTime();
  this.foo = function() { return x; };
  return x;
}
它可以工作,但只有当foo作为这样的函数调用时才可以

foo();
但是如果我想把它叫做一个有值的正态变量呢?我可以将代码修改为

var foo = function() {
  var x = someComplicatedComputationThatMayTakeMoreTime();
  this.foo = x;
  return x;
}
这将允许我只作为函数调用它一次,然后作为正则变量调用一次。但这仍然不是我想要的。此外,如果它意外地再次被作为函数调用,并返回错误,则会变得复杂

这在JavaScript中可能吗

顺便说一句,这是针对Chrome/Firefox的扩展,所以IE兼容性并不重要


最后使用了toString,因为getter不允许我重新定义整个属性,函数必须与之关联。toString有更清晰的语法。

我认为您需要的是一个延迟实例化的变量,它可以这样实现

var myProperty = null;
function getMyProperty() {
    return (myProperty = myProperty ||  builder());
}

如果Internet Explorer不存在,您可以使用John Resig在本文中描述的getter和setter:

。。。它们允许您将特殊函数绑定到看起来像普通对象属性的对象,但实际上执行隐藏函数


这在网络上是不实用的,因为IE不支持它,但是你可以看看 例如,如何做到这一点

有几种方法可以做到这一点,下面是一个例子:

var data = {};
data.__defineGetter__("prop",
                      (function () {
                           var value = null;
                           return function () {
                             if (null == value) {
                               value = getYourValueHere();
                             }
                             return value;
                           };
                        })());
现在你可以像这样使用它:

var a = data.prop;
var b = data.prop;

使用函数是您目前的最佳选择,但是所有主要浏览器供应商正在使用的新JavaScript标准(ECMAScript第五版)为您提供了一种创建访问器属性的方法,您可以使用内部调用的
get
set
函数定义属性,不必担心将此属性视为函数,例如:

var obj = {};
Object.defineProperty(obj, 'foo', {
  get: function () { // getter logic
    return 'foo!';
  },
  set: function (value) {
    // setter logic
  }
});

obj.foo; // "foo!", no function call

这个新标准需要一些时间才能在所有浏览器上实现(IE9预览版让我非常失望),我不建议您在生产中使用它,除非您完全控制应用程序的使用环境。

您可以定义一个JavaScript getter。从:


有关更多信息,请参阅John Resig的帖子和上的页面。

我建议在上添加一个变体,但要使用闭包

var myProperty = (function () {
  var innerProperty = null;
  return function() {
    return (innerProperty = innerProperty ||  someComplicatedComputationThatMayTakeMoreTime());
  };
})();

然后每次需要访问变量时都使用
myProperty()

使用toString如何

var foo = function() {
  function someComplicatedComputationThatMayTakeMoreTime() {
        //your calculations
  }
  return {
      toString: function() { 
           return someComplicatedComputationThatMayTakeMoreTime(); 
      }
  }
}
更多关于

根据评论进行编辑。使用singleton(我认为它被称为):


我将使用显式惰性求值。以下是我根据方案的执行情况:

var delay, lazy, force, promise, promiseForced, promiseRunning;

(function () {

  var getValue = function () {
    return this.value;
  };

  var RUNNING = {};

  var DelayThunk = function (nullaryFunc) {
    this.value = nullaryFunc;
  };
  DelayThunk.prototype.toString = function () {
    return "[object Promise]";
  };
  DelayThunk.prototype.force = function () {
    if (promiseRunning (this)) {
      throw new Error ("Circular forcing of a promise.");
    }
    var nullaryFunc = this.value;
    this.value = RUNNING;
    this.value = nullaryFunc ();
    this.force = getValue;
    return this.value;
  };

  var LazyThunk = function (nullaryFunc) {
    DelayThunk.call (this, nullaryFunc);
  };
  LazyThunk.prototype = new DelayThunk (null);
  LazyThunk.prototype.constructor = LazyThunk;
  LazyThunk.prototype.force = function () {
    var result = DelayThunk.prototype.force.call (this);
    while (result instanceof LazyThunk) {
      result = DelayThunk.prototype.force.call (result);
    }
    return force (result);
  };

  delay = function (nullaryFunc) {
    return new DelayThunk (nullaryFunc);
  };

  lazy = function (nullaryFunc) {
    return new LazyThunk (nullaryFunc);
  };

  force = function (expr) {
    if (promise (expr)) {
      return expr.force ();
    }
    return expr;
  };

  promise = function (expr) {
    return expr instanceof DelayThunk;
  };

  promiseForced = function (expr) {
    return expr.force === getValue || !promise (expr);
  };

  promiseRunning = function (expr) {
    return expr.value === RUNNING || !promise (expr);
  };

}) ();
示例语法:

var x = lazy (function () { return expression; });
var y = force (x);

var z = delay (function () { return expression; });
var w = force (z);
注:值在计算后存储,因此重复强制不会进行额外计算

用法示例:

function makeThunk (x, y, z) {
  return lazy (function () {
    // lots of work done here
  });
}

var thunk = makeThunk (arg1, arg2, arg3);

if (condition) {
  output (force (thunk));
  output (force (thunk)); // no extra work done; no extra side effects either
}
您可以使用创建此类功能

var object = {};
var handler = {

    resolvers: {},

    get ( target, property, proxy ) {

        if ( ! target.hasOwnProperty( property ) && this.resolvers.hasOwnProperty( property ) ) {
            // execute the getter for the property;
            target[ property ] = this.resolvers[ property ]();
        }
        return target[ property ];

    },

    set ( target, property, value, receiver ) {

        // if the value is function set as a resolver
        if ( typeof value === 'function' ) {
            this.resolvers[property] = value;
        // otherwise set value to target
        } else {
            target.property = value;
        }
    },

    has ( target, property, receiver ) {
        //true when proxy handler has either a resolver or target has a value;
        return this.resolvers.hasOwnProperty( property ) || target.hasOwnProperty( property );
    }

};

var lazyObject = new Proxy( object, handler );
现在您可以这样使用它:

'exampleField' in lazyObject; //returns false
lazyObject.exampleField = function(){ return 'my value' }; // add a resolver function
'exampleField' in lazyObject; //returns true
lazyObject.exampleField; //executes your resolver function and returns 'my value'
本示例旨在演示工作原理。你可以根据需要改变



这里是

我希望能够使用myProperty变量,而不必担心调用getMyProperty()。这就是他现在所拥有的(尽管我更喜欢你的)。@LLer-不幸的是,JavaScript不支持这一点。你为什么不试试哈斯克尔?:)在尝试编辑之后,我发现了一些我认为有效的东西。幸运的是,这是一个Chrome/Firefox扩展,所以IE并不重要。:)在这种情况下,它将完美地工作,我也在Firefox扩展中使用了它。查看文档,有一个比我展示的更友好的语法。显然,我发现IE8部分支持它们,但使用不同的语法:。IE8使用的是
Object.defineProperty
方法,它应该成为ECMAScript标准。是的,这是ES5标准语法,从我所知,我只是觉得语法非常糟糕。是的,它有点难看,但这种语法选择非常仔细,因为你可以看到没有定义新语法,该方法接收一个普通的旧对象,引入新语法会使采用新标准的速度变慢,从而产生更多的兼容性问题……使用
this.foo
:1.
this
时存在两个问题。
this
如果被称为
foo()
,则引用顶级对象(
窗口
),如果将
foo
赋值给一个变量并多次调用该变量,
foo
将在每次调用时更新,因为该变量没有被更改。这只是一个示例,其中大多数都是在对象内部定义的,因此它引用对象。我用一个简单的alert()函数检查它是被多次调用还是只被调用一次,它的值只被计算一次?哇,这很有效,因为只有在使用变量时才会调用toString。谢谢。如果
foo
被访问两次,那么复杂的计算不会被执行两次吗?会的。如果您不想这样做,那么应该在返回的对象中添加一个额外的属性(比如:result)。现在向toString添加一个检查:如果result属性没有值,则执行计算(在toString中),将其结果分配给属性并返回它。如果它有一个值,则返回该值。这就是我最后所做的,并且它是有效的:D var foo={toString:function(){return foo=somecomposedcomputization that may takemoretime();;}}}目前唯一的问题是,如果我想用对象的属性执行此操作,我无法在不知道对象名称的情况下访问其他属性,我以前使用的是“this.otherproperty”。没什么大不了的,但我总是想让事情变得更灵活,所以我用了_defineGetter__;()来解决这些问题。@LLer:看到编辑过的答案了,但也许你指的是别的什么?用法看起来很有希望。谢谢这很有趣,我将试着理解一下。
var object = {};
var handler = {

    resolvers: {},

    get ( target, property, proxy ) {

        if ( ! target.hasOwnProperty( property ) && this.resolvers.hasOwnProperty( property ) ) {
            // execute the getter for the property;
            target[ property ] = this.resolvers[ property ]();
        }
        return target[ property ];

    },

    set ( target, property, value, receiver ) {

        // if the value is function set as a resolver
        if ( typeof value === 'function' ) {
            this.resolvers[property] = value;
        // otherwise set value to target
        } else {
            target.property = value;
        }
    },

    has ( target, property, receiver ) {
        //true when proxy handler has either a resolver or target has a value;
        return this.resolvers.hasOwnProperty( property ) || target.hasOwnProperty( property );
    }

};

var lazyObject = new Proxy( object, handler );
'exampleField' in lazyObject; //returns false
lazyObject.exampleField = function(){ return 'my value' }; // add a resolver function
'exampleField' in lazyObject; //returns true
lazyObject.exampleField; //executes your resolver function and returns 'my value'