47

JavaScript 允许将函数视为对象——如果您首先将变量定义为函数,则随后可以向该函数添加属性。你如何做相反的事情,并向“对象”添加一个函数?

这有效:

var foo = function() { return 1; };
foo.baz = "qqqq";

此时,foo()调用该函数,并foo.baz具有值“qqqq”。

但是,如果您先进行属性分配部分,那么您如何随后将函数分配给变量?

var bar = { baz: "qqqq" };

我现在可以做些什么来安排bar.baz值“qqqq” bar()调用该函数?

4

8 回答 8

29

在这里很容易混淆,但你不能(容易或清楚地或据我所知)做你想做的事。希望这将有助于解决问题。

首先,Javascript 中的每个对象都继承自 Object 对象。

//these do the same thing
var foo = new Object();
var bar = {};

其次,函数是 Javascript中的对象。具体来说,它们是一个 Function 对象。Function 对象继承自 Object 对象。检查函数构造函数

var foo = new Function();
var bar = function(){};
function baz(){};

一旦将变量声明为“对象”,就不能(容易或清楚地或据我所知)将其转换为函数对象。您需要声明一个 Function 类型的新对象(使用函数构造函数,为变量分配匿名函数等),并从旧对象复制方法的任何属性。

最后,预料到一个可能的问题,即使将某些东西声明为函数,您也不能(据我所知)更改 functionBody/source。

于 2008-09-23T23:27:40.520 回答
25

似乎没有标准的方法来做到这一点,但这是可行的。

但是,为什么,这是个问题。

function functionize( obj , func )
{ 
   out = func; 
   for( i in obj ){ out[i] = obj[i]; } ; 
   return out; 
}

x = { a: 1, b: 2 }; 
x = functionize( x , function(){ return "hello world"; } );
x()   ==> "hello world" 

根本没有其他方法可以实现这一点,做

x={}
x() 

将返回“类型错误”。因为“x”是一个“对象”,你不能改变它。它和尝试做的一样明智

 x = 1
 x[50] = 5
 print x[50] 

它行不通。1 是整数。整数没有数组方法。你做不到。

于 2008-09-23T22:46:58.607 回答
4

对象类型是函数,对象本身是函数实例化。

alert([Array, Boolean, Date, Function, Number, Object, RegExp, String].join('\n\n'))

显示(在 FireFox 中):

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

特别要注意 Function 对象 ,function Function() { [native code] }被定义为递归关系(使用自身的递归定义)。

另外,请注意,关于1[50]=5. 这确实为 Number 对象分配了一个属性,并且是有效的 Javascript。观察,

alert([
  [].prop="a",
  true.sna="fu",
  (new Date()).tar="fu",
  function(){}.fu="bar",
  123[40]=4,
  {}.forty=2,
  /(?:)/.forty2="life",
  "abc".def="ghi"
].join("\t"))

显示

a   fu  fu  bar 4   2   life    ghi

根据 Javascript 的“参与规则”正确解释和执行。

当然,总会有皱纹和表现出来=。分配给变量时,对象通常与其值“短路”,而不是完整的实体。这是布尔对象和布尔值的问题。

显式对象识别解决了这个问题。

x=new Number(1);  x[50]=5;  alert(x[50]);

“重载”是一个相当合法的 Javascript 练习,并且明确地得到了一些机制的认可,prototyping尽管代码混淆可能是一种危险。

最后说明:

alert(  123 . x = "not"  );

alert( (123). x = "Yes!" );  /* ()'s elevate to full object status */
于 2011-05-23T14:24:17.387 回答
1

使用临时变量:

var xxx = function()...

然后复制原始对象的所有属性:

for (var p in bar) { xxx[p] = bar[p]; }

最后将具有旧属性的新函数重新分配给原始变量:

bar = xxx;
于 2008-09-23T22:48:39.960 回答
1
var A = function(foo) {                                                                                                      
  var B = function() {                                                                                                       
    return A.prototype.constructor.apply(B, arguments);
  };
  B.prototype = A.prototype;                                                                                                 
  return B;                                                                                                                  
}; 
于 2012-01-10T04:21:31.960 回答
1

注意:以我如何解决问题的方式写的帖子。我不是 100% 确定它在 OP 的情况下是否可用。

我在寻找一种方法来转换在服务器上创建并通过 JSON / ajax 传递给客户端的对象时发现了这篇文章。

这实际上使我处于与 OP 相同的情况,我想将一个对象转换为一个函数,以便能够在客户端上创建它的实例。

最后我想出了这个,它正在工作(至少到目前为止):

var parentObj = {}

parentObj.createFunc = function (model)
{
    // allow it to be instantiated
    parentObj[model._type] = function()
    {
        return (function (model)
        {
            // jQuery used to clone the model
            var that = $.extend(true, null, model);
            return that;
        })(model);
    }
}

然后可以像这样使用:

var data = { _type: "Example", foo: "bar" };
parentObject.createFunc(data);
var instance = new parentObject.Example();

在我的情况下,我实际上希望拥有与生成的对象实例相关联的函数,并且还能够在实例化它时传入参数。

所以我的代码是:

var parentObj = {};
// base model contains client only stuff
parentObj.baseModel =
{
    parameter1: null,
    parameter2: null,
    parameterN: null, 
    func1: function ()
    {
        return this.parameter2;
    },
    func2: function (inParams) 
    {
        return this._variable2;
    }
}

// create a troop type
parentObj.createModel = function (data)
{
    var model = $.extend({}, parentObj.baseModel, data);
    // allow it to be instantiated
    parentObj[model._type] = function(parameter1, parameter2, parameterN)
    {
        return (function (model)
        {
            var that = $.extend(true, null, model);
            that.parameter1 = parameter1;
            that.parameter2 = parameter2;
            that.parameterN = parameterN;
            return that;
        })(model);
    }
}

并被称为:

// models received from an AJAX call
var models = [
{ _type="Foo", _variable1: "FooVal", _variable2: "FooVal" },
{ _type="Bar", _variable1: "BarVal", _variable2: "BarVal" },
{ _type="FooBar", _variable1: "FooBarVal", _variable2: "FooBarVal" }
];

for(var i = 0; i < models.length; i++)
{
    parentObj.createFunc(models[i]);
}

然后可以使用它们:

var test1 = new parentObj.Foo(1,2,3);
var test2 = new parentObj.Bar("a","b","c");
var test3 = new parentObj.FooBar("x","y","z");

// test1.parameter1 == 1
// test1._variable1 == "FooVal"
// test1.func1() == 2

// test2.parameter2 == "a"
// test2._variable2 == "BarVal"
// test2.func2() == "BarVal"

// etc
于 2016-06-12T17:19:35.997 回答
-1

JavaScript 允许将函数视为对象——您可以向函数添加属性。你如何做相反的事情,并为一个对象添加一个函数?

你似乎有点困惑。JavaScript 中的函数对象。而且变量可变的。你不会期望这会起作用:

var three = 3;
three = 4;
assert(three === 3);

...那么您为什么期望将函数分配给您的变量会以某种方式保留其先前的值?也许一些注释会为您澄清一些事情:

// assigns an anonymous function to the variable "foo"
var foo = function() { return 1; }; 
// assigns a string to the property "baz" on the object 
// referenced by "foo" (which, in this case, happens to be a function)
foo.baz = "qqqq";
于 2008-09-23T22:39:22.697 回答
-1
var bar = { 
    baz: "qqqq",
    runFunc: function() {
        return 1;
    }
};

alert(bar.baz); // should produce qqqq
alert(bar.runFunc()); // should produce 1

我想你正在寻找这个。

也可以这样写:

function Bar() {
    this.baz = "qqqq";
    this.runFunc = function() {
        return 1;
    }
}

nBar = new Bar(); 

alert(nBar.baz); // should produce qqqq
alert(nBar.runFunc()); // should produce 1
于 2010-10-26T21:36:02.813 回答