繁体   English   中英

如何在Javascript中使对象属性既是函数又是变量?

[英]How can I make an object property be both a function and a variable in Javascript?

我已经看到*可以将某个键既作为变量又作为函数调用的东西。 变量将返回一个值,函数将执行某些功能。

obj.test
// E.g. 16

obj.test(32)
// do something with 32

我不知道这是什么图书馆。 这不是典型的getter / setter方案,因为第二个方案不是函数而是setter。

请告诉我我不疯。


*)如果我记得在哪里,我可能不需要问这个问题。


我找到了解决方案!

TJCrowder发表关于toString()作为最终可能性的评论后,进行了尝试 ,并得到了我想要的 **(也可以随意投票;)。 但我想要的东西是主观的,我是不是。 TJCrowder在所有(?)场景中均以其能力中的最好的方式回答了其他可能遇到类似问题的其他人,因此,我接受了他的回答。

**)在我正在使用的所有库中grep toString后,我发现Raphael做类似的事情。

介绍

如果o.test()调用一个函数,则o.test返回一个函数引用,这是有保证的。 关于您可能看到的内容的一些可能的想法:

  • 如果在属性赋值obj.test = 42; )时看到不同的行为,则在检索属性( obj.test(); )时,可能是不对称属性 下面更多。

  • 如果在某些表达式中使用了o.test ,例如var x = o.test + 42; element.innerHTML = o.test; ,可能是他们使用了覆盖的toString和/或valueOf 下面更多。

  • 该属性可以在首次使用后重新定义,因此o.test会给您16但随后会更改o.test属性的定义。 以下是有关重新定义自身的属性的更多信息。

不对称性质

在评论中,您说过:

...在注释中说,类似这样的代码使该函数兼作变量。

我能看到的最接近的是您分配给它的位置(不读取它),并且它记住该值。 看起来像这样:

var o = {};
(function(obj) {
    var storedValue;

    function weirdFunction(val) {
        return arguments.length === 0 ? storedValue : val;
    }

    Object.defineProperty(obj, "test", {
        get: function() {
            return weirdFunction;
        },
        set: function(value) {
            storedValue = value;
        },
        enumerable: true
    });
})(o);

o.test = 16;
console.log(o.test());   // 16
console.log(o.test(32)); // 32
console.log(o.test());   // 16

o.test = 24;
console.log(o.test());   // 24
console.log(o.test(32)); // 32
console.log(o.test());   // 24

现场例子

那是一个非对称属性的例子:当您阅读它时,它总是一个函数; 但是当您编写它时,您可以编写任何值,它将记住它。 我已经使它在返回时提供给您的功能使用存储的值,除非您给它提供其他功能。

非对称属性可能有很好的用例,但是如果是这样,我希望它们很少而且相去甚远。 (例如,浏览器中的document.cookie属性是一种非对称属性,它使人们无休止地使用,并且在后部使用时非常痛苦;一类情况是“哇,他们真的,真的不应该这样做像那样”...)

toString / valueOf技巧

这是toString / valueOf技巧的示例(我不推荐使用,但可以在某些警告下使用):

var obj = {test: function(val) { return val; }};
obj.test.valueOf = obj.test.toString = function() {
  return 16;
};
console.log(obj.test);     // 16
console.log(obj.test(32)); // 32

它要求将属性作为非功能使用的任何东西都必须做一些转换,就像console.log一样(在Chrome上对我来说)。 例如,将其转换为字符串或数字: var str = "The result is " + obj.test; (隐式调用toString ),或var = 5 + obj.test; (隐式调用valueOf )。 如果该值未经转换使用,则(当然)它是一个函数引用。

重新定义自己

在符合ES5的系统上,属性可以做的另一件真正可怕的事情是在使用属性时重新定义自身

// Truly Evil And Wrong
var obj = {};
Object.defineProperty(obj, "test", {
    get: function() {
        Object.defineProperty(this, "test", {
            value: function(val) { return val; },
            enumerable: true
        });
        return 16;
    },
    enumerable: true,
    configurable: true
});
console.log(obj.test);     // 16
console.log(obj.test);     // function(val) { return val; }
console.log(obj.test(32)); // 32

但是不要那样做。 只是不要。 :-)

我可能想到的唯一解决方案是,稍后重新定义“ obj”。

我正在玩TJCrowder的评论, 提到规避返回函数引用的唯一方法是使用toString / valueOf 我得到的可能正是我所看到的:

var obj = {
    test: (function() {
        var storedValue = 'Nothing. Pass me a number.';

        var doSomething = function(val) {
            storedValue = val;
            return val + ' black rainbows';
        }

        doSomething.toString = function() {
            return storedValue;
        }

        return doSomething;
    })()
};

有效:

obj.test // Nothing. Pass me a number.
obj.test(45) // "45 black rainbows"
obj.test // 45

它不是一个可设置的变量,但是我认为假设我在看完该部分后就把它编成一部分是合理的。 但是,也许还有一些二传手的诡计可以实现这一目标。

暂无
暂无

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

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