在JavaScript中是否可以“返回一个getter”?

5
我希望做类似于这样的事情:

我想实现这样的功能:

function x(){
    var o = {};
    o.__defineGetter__('y', function(){
        return new Date();
    });

    return o.y;
}

var z = x();
console.log(z);
//Wait 1 second
console.log(z); //Date should be one second past the last printing

当然,这并不起作用,因为当o.y被返回时,它已经被求值。我正在寻找一种返回作为getter的变量的方法。以下示例让我对此有了希望:
function x(context){
    //Bind the getter to the passed in scope
    context.__defineGetter__('y', function(){
        return new Date();
    });
}

x(this);
console.log(y);
//Wait 1 second
console.log(y); //Date is one second past last printing

有人尝试过这样做吗?

是的,我熟悉使用不同语法建模类似行为的其他方法。我只是希望这个特定的语法能够适用于一个特殊的场景。

谢谢,

克里斯

3个回答

2
function x(){
    var o = function() {};
    o.__proto__ = {
           valueOf:  function() { 
               return new Date().toString(); 
           }
     };

    return o;
}

var z = x(); 
console.log(z);  // Tue Mar 13 2012 14:10:10 GMT+0200 (GTB Standard Time)
setTimeout(function() { 
   console.log(z); // Tue Mar 13 2012 14:10:12 GMT+0200 (GTB Standard Time)
}, 2000);

1
这应该是被接受的答案。然而,更简单的方法是从函数x()返回一个带有"valueOf"属性的对象,例如:"function x() { return { valueOf: function () { ... } }; }" - Dan Phillimore
是的,这段代码可以用更多的方式和更简单的方式来编写。但我想x()函数和内部对象定义的原因是o对象可以有更多的方法和属性,并且它们都在x的私有上下文中定义。x()函数只是返回o对象,然后展示时间(在该示例中),但你也可以像o.speak()之类的操作。因此,为了回答问题,即使不完整、似乎无用或错误,答案也应该尊重上下文。 - TheBrain
同意。但我的意思是,没有理由使用函数作为要返回的对象并依赖于具有不稳定浏览器支持的 __proto__。原始问题并没有返回一个函数对象,所以我认为这只会增加不必要的干扰。 - Dan Phillimore
这是一个非常聪明的解决方案,可以解决我提出的例子。我忘记了我当时想做什么,但它涉及到了https://github.com/scriby/asyncblock。所以在那个模块的上下文中,它确实是一个非常小众/奇怪的尝试,但它有一个特定的目的。由于使用了valueOf,这个解决方案无法解决我的整体需求,但是我会给你答复我实际提出的问题的分数 :) - user1144642

2
答案是否定的,你不能给一个变量赋值,使得该变量在像变量一样访问时表现得像是一个函数。就像你在问题中指出的那样,最接近的方法是定义一个具有getter函数的属性。你不能创建一个函数的局部变量,以按照你所描述的方式工作。
但是,你可以定义一个函数,该函数定义一个具有getter函数的全局属性(或者更准确地说,是全局对象上的属性),并使其看起来像是你想要的效果。例如,在ES5中,以下代码将创建一个名为y的全局变量,它的行为与你所描述的相同。
function x(n) { 
    Object.defineProperty(this, n, { 
        get: function() { 
            return new Date(); 
        }
    }); 
}

x('y')

请注意,这仅适用于非严格模式。在严格模式下,this 的值将为 undefined

我无法想象为什么您希望变量表现出这种方式。


@nikc.org 谢谢!但是现在它已经格式化得很好了,有人可能会尝试使用它。天哪! - chuckj
1
尝试执行以下代码:var x = {valueOf:function() {console.log("我应该是一个变量"); return Math.random() }}; console.log(10 * x); - TheBrain
1
这非常聪明而且非常接近。然而,它对于给定的情况不起作用,也就是说,“console.log(x);”会打印“[object Object]”,因为将x作为参数传递并不能强制调用valueOf()方法。但还是很酷的! - chuckj

1

这里的问题是,在第一个函数中返回o.y时,你没有返回getter方法,而是返回调用getter方法后返回的日期对象。然后你将那个日期对象分配给了z,所以每次你使用console.log(z)时,都会记录该日期对象,而不是再次调用函数。

在第二个例子中,当你使用console.log(y)时,实际上是每次调用该函数。

可能的解决方案,虽然可能不是你想要做的,是让第一个示例中的getter返回一个函数。然后它就可以工作了。

function x(){
    var o = {};
    o.__defineGetter__('y', function(){
        return function() {
            return new Date();
        }
    });

    return o.y;
}

var z = x();

console.log(z());
//Wait 1 second

setTimeout( function() {
    console.log(z()); //Date is one second past last printing
}, 1000)

在Javascript中,Getter方法是一种特殊情况,因为它们在结尾没有通常的()调用函数,这可能会让人感到困惑,因为通常你期望o.y返回一个函数而不是调用一个函数。


1
给那位点了踩的人:如果你要这样做,请提供一个解释。如果你注意到了什么问题,留下一条评论会更有帮助。 - Philip Walton
我实际上删除了一个变量,因为xz都可以被替换为引用函数的一个变量。 - bennedich
你没有删除任何变量;你添加了一个。OP有xz,而你有xzf。此外,你提供的链接并没有解答OP的问题,也不比我的回答在风格上更好,我写这篇回答是为了帮助OP理解发生了什么,而不是成为优秀Javascript编码风格的典范。如果我离开了回答的重点,评论他代码的质量既不恰当也不会有帮助。通过使我的返回语句返回一个函数,我认为我正在帮助阐明实际发生的事情。 - Philip Walton
谢谢。我知道这里发生了什么,我也知道可以返回一个函数来获得类似的行为。但我真的想要我描述的确切行为。基本上,就假设我有一个想要以那种方式实现的充分理由。 - user1144642
哇,我的演示目的真的超出了你的理解范围。它指出最终z === f,因此您可以用一个立即函数替换全部内容。这是一个新演示给你去理解:http://jsfiddle.net/vrtja/1/。保持优雅。 - bennedich
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接