当且仅当使用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'